Page 1 of 1

At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Mon Feb 25, 2019 9:47 pm
by Badger
I'm putting this in demos since its not a complete game or anything, but feel free to move, delete etc etc.

After several months of slaving over a hot 7905 regulator and multiple diversions whilst trying to teach myself 6502 assembly, I've finally created something I'm happy with.

The result is a more pleasant text mode horizontal scrolling across the full screen. I say its pseudo hires since it basically plots the characters on screen and then redefines them to acheive the scrolling. After 7 scrolls the characters reset to their original redefinition and the whole screen scrolls left 1 character.

The TAP file is attached and if anyone wants the source (its 100% asm) then I can post it as code or you can dissasemble it from starting memory $600

The code is probably horrible and very noobish but it works which is better than 100% efficient non-working code :D
asmscrol.tap
(1.74 KiB) Downloaded 416 times

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Mon Feb 25, 2019 11:29 pm
by Chema
I must confess I am quite impressed. Congratulations!

You beat me definitely with this one. I had been toying with the same idea for a scrolling game after I failed to perform a smooth scroll in Oricium. I think Dbug suggested the idea of redefining the charset for this (what I did for the stars).

Really, really nice and the only way to achieve a full frame lateral scroll at a good frame rate. If you have the sources, I would love to see them (better than with the debugger, with no labels or nice symbols).

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Tue Feb 26, 2019 7:17 am
by Badger
I'm not sure that this version is working correctly.

It did work well when I was scrolling 2 "pixels" at a time but I think I tried to be clever and scroll it 1 pixel at a time. I only spotted it when I ran Oricutron in full screen mode.

I'll have a good look through the code , fix it and then re-release along with the source,

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Tue Feb 26, 2019 8:46 am
by Dbug
That could be a good base for a better Skramble or Choplifter game :)

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Tue Feb 26, 2019 9:58 pm
by Badger
Corrected version attached. It was something silly on my part (isnt it always)

Still a little jumpy in parts, but hopefully can smooth it out a little more.

Will comment the source and then share it
asmscrol.tap
(1.31 KiB) Downloaded 455 times

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Wed Feb 27, 2019 10:06 am
by ibisum
Its very interesting .. is it glitching for known reasons, though? Because I see a lot of flicker - perhaps this is just a timing issue - i.e. you're updating as fast as possible?

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Wed Feb 27, 2019 10:21 am
by Chema
Probably needs to sync with vertical retrace... not sure the frame rate that he is achieving, though.

The reason why I did not manage to use this idea is due to the limitations it imposes to put different elements together to create a scenario (graphic blocks bleed into other characters when scrolling, so you basically need to keep blank spaces and they consume more characters, or find some other smart tricks). Moreover if you want to scroll back and forth.

But I had in mind the idea of trying again, because I feel quite frustrated with the bumpy scrolling in Oricium... Now badger showed that it can be done (although I am quite sure Dbug sent me something along that line with trees scrolling with pixel precision... am I right?).

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Wed Feb 27, 2019 10:30 am
by Badger
I think its glitching after seven cycles, I think this is due to the fact that the character redefine is a lot faster than the scroll , addnext mountain and copy buffer to screen routines.

Interestingly,, if I add a delay in each cycle it actually looks smoother.

I'm playing around with a few things to see if I can make it better without breaking it :D As you probably know that is harder than it sounds.
I've pasted the full asm code below which includes an experimental 1 pixel row coloring routine and also a currently unused player character keyboard and plotting rouitine.

Please excude the beginner mistakes and bad coding.

Code: Select all

#define CHAR_BUF $B018	
#define BUFFER_ADRESS ($afc8+40+26*40+38)	;last char pos of buffer
#define DISPLAY_ADRESS $BB80				; start address of text screen
#define TERRAIN_CHARS $B400+97*8-1			; memory location of 1st char to redefine
#define SRC_ADD $AFC8						;first mem loc of buffer screen area
#define DEST_ADD ($Bb80+40)					;destination address to copy buffer to
#define SRC_ADD2 $AFC9						; mem location of 2nd column of buffer to scroll into first
#define DEST_ADD2 $afc8						;mem location of 1st column of buffer - gets 2nd column copied into here to achieve scroll
#define COL1_START $afc8					; mem location of first column of buffer to set paper attributes
#define COL2_START $afc9					; mem location of 2nd column of buffer to set ink attributes
#define CURRENT_TERRAIN $09					; zero page to track current definition of terrain
#define CUR_X $08			
#define CUR_Y $07
#define blankchar #32						;ASCII code of characters to use.
#define charblankb4up #97					; first non-blank char , used with TERRAIN_CHARS to set what characters to redefine
#define charup #98			
#define charsolid #99	
#define charb4down #100
#define chardown #101	
#define spcafter #32
#define hirescol1 $a000						;mem location of 1st column of hires screen area - experimental coloring

.text
mainprog
.(
	jsr clrscreen
	;lda #<CHAR_BUF
	;sta putscrn+1
	;lda #>CHAR_BUF
	;sta putscrn+2
	;ldx #84
	;stx $04
	;jsr add
	;lda #02
	;sta $02
	;lda #04
	;sta $03
	lda #01
	sta $024e
	lda #01
	sta $024f
	lda  #10
	sta $26a
starter
	ldx #00
	stx $01
	;lda #$58
	;sta $05
	lda #00
	sta CURRENT_TERRAIN
	jsr defchars
bigloop
	lda CURRENT_TERRAIN
	cmp #00
	bne sc3					; if current terrain is not 0 then dont scroll just redefine characters
	jsr _scroll				; scroll buffer
	jsr _buff2scrn			; copy buffer to screen
	jsr defchars			; redefine characters
	
	jsr _nextmount			; add next moutain column to buffer
	jmp endscroll
sc3
	jsr defchars			; redefine characters
	
endscroll	
	;jsr chkkey  ;future keyboard and player movement controls
	inc CURRENT_TERRAIN		
	cmp #07
	bne noreset
	lda #00					;reset terrain flag if 7 
	sta CURRENT_TERRAIN
noreset
	inc $01
	ldx $01
	cpx #255
	bne bigloop
	jmp starter
	rts
chkkey
	lda $2df
	beq nokey
	lda #00
	sta $2df
	lda $208
	and #$7f
	cmp #56
	beq nokey
	cmp #03
	beq left
	cmp #46
	beq up
	cmp #15
	beq right
	cmp #42
	beq down
	rts
nokey
	rts
left
	ldy $02
	cpy #02
	beq nokey
	lda #32
	sta $05
	jsr display
	dec $02
	ldx #01
	stx $04
	jsr sub
	lda #$58
	sta $05
	jsr display
	rts
right
	ldy $02
	cpy #39
	beq nokey
	lda #32
	sta $05
	jsr display
	inc $02
	ldx #01
	stx $04
	jsr add
	lda #$58
	sta $05
	jsr display
	rts
up
	ldx $03
	cpx #02
	beq nokey
	lda #32
	sta $05
	jsr display
	dec $03
	ldx #40
	stx $04
	jsr sub
	lda #$58
	sta $05
	jsr display
	rts
down
	ldx $03
	cpx #27
	beq nokey
	lda #32
	sta $05
	jsr display
	inc $03
	ldx #40
	stx $04
	jsr add
	lda #$58
	sta $05
	jsr display
	rts
display
	lda #04
	jsr putscrn
	ldx #01
	stx $04
	jsr add
	lda $05
	jsr putscrn
	jsr add
	ldx $03
	lda inks,x
	jsr putscrn
	ldx #03
	stx $04
	jsr sub
	rts
putscrn
	sta $0123
	rts

add
	clc
	lda putscrn+1
	adc $04
	sta putscrn+1
	lda putscrn+2
	adc #00
	sta putscrn+2
	rts
sub
	sec
	lda putscrn+1
	sbc $04
	sta putscrn+1
	lda putscrn+2
	sbc #00	
	sta putscrn+2
	rts

.)


_nextmount
.(
	lda #<BUFFER_ADRESS	; End column to add mountain to
	sta write+1
	lda #>BUFFER_ADRESS
	sta write+2

ldy #26	;load y with number of rows to loop
loop
addblock		;calc inverts the height so can use logical numbers in heights table
	sty CUR_Y	;current height to check
	ldx CUR_X	;current heights table position
	clc
	lda heights,x
	eor #255
	sec
	adc #26
	cmp CUR_Y
	beq testnext		
	bcs	lookforup		; y is less than height look if next block is an up
	bcc lookfordown     ; y is greater than height  ie plot something

lookforup
	ldx CUR_X
	inx
	clc
	lda heights,x
	eor #255
	sec
	adc #26
	cmp CUR_Y
	beq b4up
	jmp noc

lookfordown
	ldx CUR_X
	inx
	clc
	lda heights,x
	eor #255
	sec
	adc #26
	cmp CUR_Y
	beq sb4d
	jmp sol

smallloop
	jmp loop

testprev
	ldx CUR_X
	dex
	clc
	lda heights,x
	eor #255
	sec
	adc #26
	cmp CUR_Y
	bcs sb4d
	jmp noc
	
testnext
	ldx CUR_X
	inx
	clc
	lda heights,x
	eor #255
	sec
	adc #26
	cmp CUR_Y
	beq sol
	bcs dnc
	bcc upc
	jmp write
	

b4up
	lda charblankb4up
	jmp write
sol
	lda charsolid
	jmp write
sb4d
	lda charb4down
	jmp write
upc
	lda charup
	jmp write
dnc
	lda chardown
	jmp write
noc
	lda blankchar
	jmp write

write
	sta $0123 	
decrem
	sec			; Calc new buffer adress
	lda write+1
	sbc #40
	sta write+1
	lda write+2
	sbc #0
	sta write+2
	dey
	bne smallloop

	inc CUR_X
	lda CUR_X
	cmp #62
	bne skip2
	ldx #00
	stx CUR_X
skip2
	rts
.)

_buff2scrn						;routine to copy buffer to screen
.(

	lda #<SRC_ADD ;set our source memory address to copy from
	sta $FB
	lda #>SRC_ADD
	sta $FC
	lda #<DEST_ADD ;set our destination memory to copy to
	sta $FD
	lda #>DEST_ADD
	sta $FE
	ldy #$00 ;reset x and y for our loop
	ldx #$05

Loop
	lda ($FB),Y ;indirect index source memory address, starting at $00
	sta ($FD),Y ;indirect index dest memory address, starting at $00
	iny 
	bne Loop ;loop until our dest goes over 255

	inc $FC ;increment high order source memory address, starting at $80
	inc $FE ;increment high order dest memory address, starting at $60
	dex
	bne Loop ;

rts
.)

_copyback		;routine to copy screen to buffer after a clearscreen
.(
	lda #<DEST_ADD ;set our source memory address to copy from, bb80
	sta $FB
	lda #>DEST_ADD
	sta $FC
	lda #<SRC_ADD;set our destination memory to copy to, $00, WRAM afc8
	sta $FD
	lda #>SRC_ADD
	sta $FE
	ldy #$00 ;reset x and y for our loop
	ldx #$04

Loop
	lda ($FB),Y 
	sta ($FD),Y 
	iny 
	bne Loop ;loop until our dest goes over 255

	inc $FC 
	inc $FE 
	dex
	bne Loop 

rts
.)


_scroll			; scroll routine, copies all rows starting at column 2 left by 1 char position
.(

lda #<SRC_ADD2 
sta $FB
lda #>SRC_ADD2
sta $FC
lda #<DEST_ADD2 
sta $FD
lda #>DEST_ADD2
sta $FE
ldy #$00 ;reset x and y for our loop
ldx #$05

Loop:
lda ($FB),Y 
sta ($FD),Y 
iny 
bne Loop ;loop until our dest goes over 255

inc $FC 
inc $FE 
dex
bne Loop ;
jsr _resetatt			;reset paper attributes after scroll
jsr _resetatt2			;reset ink attributes after scroll
;jsr _resetatt3			;experimental hires ink colourings, comment out above line and uncomment this to use
rts
.)

_resetatt			; put paper attribute based on papers table into 1st column of buffer after a scroll
.(
lda #<COL1_START
sta paperadd+1
lda #>COL1_START
sta paperadd+2
ldy #27		;load y with number of rows to loop
loop
	lda papers,y
paperadd
	sta $0123 	
increm
	clc			; Calc new buffer adress
	lda paperadd+1
	adc #40
	sta paperadd+1
	lda paperadd+2
	adc #0
	sta paperadd+2

	dey
	bne loop
	rts
.)

_resetatt2		; put ink attribute based on inks table into 2nd column of buffer after a scroll
.(
lda #<COL2_START
sta inkadd+1
lda #>COL2_START
sta inkadd+2
ldy #27			;load y with number of rows to loop
loop
	lda inks,y
inkadd
	sta $0123 	
increm
	clc			; Calc new buffer adress
	lda inkadd+1
	adc #40
	sta inkadd+1
	lda inkadd+2
	adc #0
	sta inkadd+2

	dey
	bne loop
	rts
.)

_resetatt3			;experimental mixing of text and hires attributes for single pixel row coloring
.(
lda #<COL2_START
sta inkadd2+1
lda #>COL2_START
sta inkadd2+2
lda #<hirescol1+1		;3rd column of hires memory area
sta inkadd3+1
lda #>hirescol1+1
sta inkadd3+2
ldy #27			;load y with number of rows to loop
loop
	lda #30		;hires attribute in 2nd column (paper attribute in 1st column)
	jsr inkadd2
	clc			; Calc new buffer adress
	lda inkadd2+1
	adc #40
	sta inkadd2+1
	lda inkadd2+2
	adc #0
	sta inkadd2+2
	dey
	bne loop

ldy #0
loop2
	clc			; Calc new buffer adress
	lda inkadd3+1
	adc #01
	sta inkadd3+1
	lda inkadd3+2
	adc #0
	sta inkadd3+2
	lda inks2,y			
	jsr inkadd3		;put attribute in current row 
	clc				; add 1 to column to set back to text
	lda inkadd3+1
	adc #01
	sta inkadd3+1
	lda inkadd3+2
	adc #0
	sta inkadd3+2
	lda #26			;text mode attribute
	jsr inkadd3
	clc			
	lda inkadd3+1	;add 38 to goto next row
	adc #38
	sta inkadd3+1
	lda inkadd3+2
	adc #0
	sta inkadd3+2
	iny
	cpy #175
	bne loop2
	rts

inkadd2
	sta $0123
	rts
inkadd3
	sta $0234
	rts
.)



defchars
.(
	ldy #40
	lda CURRENT_TERRAIN
	cmp #00					; check current terain flag and jump to relevant redefine routine
	beq tloop1
	cmp #01
	beq tloop2
	cmp #02
	beq tloop3
	cmp #03
	beq tloop4
	cmp #04
	beq tloop5
	cmp #05
	beq tloop6
	cmp #06
	beq tloop7

	rts
tloop1
	lda terraindata1,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	beq enddef
	jmp tloop1

tloop2
	lda terraindata2,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	beq enddef
	jmp tloop2

tloop3
	lda terraindata3,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	beq enddef
	jmp tloop3

tloop4
	lda terraindata4,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	beq enddef
	jmp tloop4

tloop5
	lda terraindata5,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	beq enddef
	jmp tloop5


tloop6
	lda terraindata6,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	beq enddef
	jmp tloop6

tloop7
	lda terraindata7,Y
	sta TERRAIN_CHARS,Y
	dey
	tya
	bne tloop7

enddef
	rts
.)


clrscreen			; clears text screen
.(
	lda #<DISPLAY_ADRESS
	sta write2+1
	lda #>DISPLAY_ADRESS
	sta write2+2
	
	ldy #26			;row to loop
clearloop2
	ldx #38			;cols to loop
clearloop1
	lda #32			;ASCII of char to write to screen
	jsr write2
	clc			
	lda write2+1
	adc #1
	sta write2+1
	lda write2+2
	adc #0
	sta write2+2
	dex
	bne clearloop1
	clc			
	lda write2+1
	adc #2
	sta write2+1
	lda write2+2
	adc #0
	sta write2+2
	dey
	bne clearloop2
	jsr _copyback
	rts
write2
	sta $0123
	rts
.)


; various tables for mountain heights, paper colors, ink colors, and terrain character definitions

heights
	.byt 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,7,8,9,10,11,12,13,12,11,10,9,8,7,8,9,10,11,11,12,13,14,13,12,11,10,9,8,7,6,5,6,5
papers
	.byt 0,0,0,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22	;first entry is bottom row
inks
	.byt 0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7

; below is a table for the experimental hires row coloring
inks2
	.byt 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,4,5,6,7,7,6,5,6,7,5,4,3,2,3,4,6,2,4,5,5,5,6,7,5,3,2,4,5,7

terraindata1
	.byt	0,0,0,0,0,0,0,0,0			;33
	.byt	1,3,7,15,31,31,63,63		;34
	.byt	63,63,63,63,63,63,63,63		;35	
	.byt	63,63,63,63,63,63,63,63		;36
	.byt	32,48,56,60,62,62,63,63		;37

terraindata2
	.byt	0,0,0,0,0,0,0,1,1
	.byt	3,7,15,31,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	0,32,48,56,60,60,62,62

terraindata3
	.byt	0,0,0,0,0,1,1,3,3
	.byt	7,15,31,63,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	62,63,63,63,63,63,63,63
	.byt	0,0,32,48,56,56,60,60

terraindata4
	.byt	0,0,0,0,1,3,3,7,7
	.byt	15,31,63,63,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	60,62,63,63,63,63,63,63
	.byt	0,0,0,32,48,48,56,56

terraindata5
	.byt	0,0,0,1,3,7,7,15,15
	.byt	31,63,63,63,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	56,60,62,63,63,63,63,63
	.byt	0,0,0,0,32,32,48,48

terraindata6
	.byt	0,0,1,3,7,15,15,31,31
	.byt	63,63,63,63,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	48,56,60,62,63,63,63,63
	.byt	0,0,0,0,0,0,32,32

terraindata7
	.byt	0,1,3,7,15,31,31,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	63,63,63,63,63,63,63,63
	.byt	32,48,56,60,62,62,63,63
	.byt	0,0,0,0,0,0,0,0
	

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Wed Feb 27, 2019 12:28 pm
by ibisum
>Interestingly,, if I add a delay in each cycle it actually looks smoother.


This is kinda to be expected, seems the engine might need to sync the char-redef on scroll-lag intervals .. and anyway, adjusting this lock-step works in your favour, since not every use of such an engine would require bat-out-of-hell full-screen scrolling, as nice as that is to see on the Oric .. most important is a smoother scroll, even at lesser tempo's, and sometimes perhaps in smaller regions of the screen according to how its used in a game/app ..

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Tue Mar 19, 2019 1:15 pm
by Antiriad2097
This seems like a similar technique to that used by Joffa for Cobra on the Spectrum to get a smooth full screen scroll.

Perhaps a similar game style could be adopted?

Re: At last a smooth(ish) - pseudo hires horizontal scroll

Posted: Sun Mar 31, 2019 4:09 am
by NekoNoNiaow
Nice scrolling indeed, great effort @Badger!

Looking at MSX 1 games such as Gradius (see below), it is possible to have slow and block by block scrolling with smooth moving sprites and obtain a result which is reasonably playable.
I guess something of that ilk could also be attempted on the Oric.