Scrolling Tiles - slenkar - 05-21-2013
I managed to get it done using ZXBASIC
Code: DIM mapdata(31) AS UBYTE => {1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2}
DIM brick(7) AS UBYTE =>{249,249,0,159,159,0,249,249}
DIM crystal(7) AS UBYTE =>{16,40,84,40,84,40,16,0}
Dim CurrentGraphic as ubyte=1
Dim NextGraphic as Ubyte
Dim PreviousGraphic as ubyte
Dim address as UInteger
Dim LineStartAddress as UInteger
addr=16384
LineStartAddress=addr
Dim PreviousAddress as UInteger
Dim LandscapeEightIter as Ubyte
Dim LandscapeIter as ubyte
Dim LineNumber as UByte
for x=0 to 31
Print AT 0,x;"["
next
for iterations=0 to 258 'scroll left 258 times
address=16384
for y=0 to 7
LineStartAddress=address
for x=0 to 31
CurrentGraphic = PEEK(address)
'pause 5
if x>0 'the leftmost byte has no graphics to its left
if CurrentGraphic Band 128=128 'if this graphic has a dot on the left
PreviousGraphic=PreviousGraphic Bor 1 'Add a dot to the right of the previous graphic byte
POKE PreviousAddress,PreviousGraphic
end if
end if
PreviousAddress=address 'save the address of the byte on the left
CurrentGraphic=CurrentGraphic SHL 1 'shift dors to left
PreviousGraphic=CurrentGraphic 'save graphic
if x<31
POKE address,CurrentGraphic
end if
if x=31
if mapdata(LandscapeIter)=1
NextGraphic=brick(LineNumber)
end if
if mapdata(LandscapeIter)=2
NextGraphic=crystal(LineNumber)
end if
if mapdata(LandscapeIter)=0
NextGraphic=0
end if
if LandscapeEightIter=0
if NextGraphic Band 1=1
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=1
if NextGraphic Band 2=2
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=2
if NextGraphic Band 4=4
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=3
if NextGraphic Band 8=8
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=4
if NextGraphic Band 16=16
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=5
if NextGraphic Band 32=32
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=6
if NextGraphic Band 64=64
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
if LandscapeEightIter=7
if NextGraphic Band 128=128
CurrentGraphic=CurrentGraphic BOR 1
end if
end if
POKE address,CurrentGraphic
end if
address=address+1 'move one square right
next
address=LineStartAddress
address=address+256 'move one line down
LineNumber=LineNumber+1
next
LineNumber=0
LandscapeEightIter=LandscapeEightIter+1
if LandscapeEightIter=8
LandscapeEightIter=0
LandscapeIter=LandscapeIter+1
end if
next
Print "done"
Print STR(178 Band 128)
STOP
but I could never get it done using assembly:
Code: function FASTCALL drawthis() as ubyte
asm
;LD HL,2000
;LD (delayiter),HL
LD HL,16384
;drawvert:
;LD A,31
;LD L,A
;LD (screenwidthiter),A
;drawblokes:
;LD A,(graphic)
;DEC A
;LD (graphic),A
;LD (HL),A
;LD A,(screenwidthiter)
;LD L,A
;DEC A
;LD (screenwidthiter),A
;LD B,A
;INC B
;INC B
;INC B
;djnz drawblokes
;LD A,(screenheightiter)
;LD L,A
;INC H
;DEC A
;LD (screenheightiter),A
;LD B,A
;INC B
;djnz drawvert
LD A,31
LD (screenwidthiter),A
LD A,7
LD (screenheightiter),A
LD HL,60000
LD (delayiter),HL
loop:
LD BC,20000
LD A,7
LD (screenheightiter),A
LD HL,16384
LD (screenaddress),HL
screenvert:
;LD BC,6000
;wait:
;DEC BC
;LD A,B
;Or C
;jp nz,wait
LD (screenaddress),HL
;load landscape number into a
LD HL,data
LD BC,(landscapeiter)
ADD HL,BC
LD A,(HL)
LD (__LABEL__printablevar),A
;load graphic into B
CP 0
jp z,thisisempty
CP 1
jp z,thisisbrick
CP 2
jp z,thisiscrystal
jp thisisbrick
thisisempty:
LD B,0
jp donegraphic
thisisbrick:
LD HL,brick
LD DE,(screenheightiter)
ADD HL,DE
LD B,(HL)
jp donegraphic
thisiscrystal:
LD HL,crystal
LD DE,(screenheightiter)
ADD HL,DE
LD B,(HL)
jp donegraphic
donegraphic:
LD A,0
LD (rightbit),A
LD A,(landscapeiter)
CP 0
jp z,bit0
CP 1
jp z,bit1
CP 2
jp z,bit2
CP 3
jp z,bit3
CP 4
jp z,bit4
CP 5
jp z,bit5
CP 6
jp z,bit6
CP 7
jp z,bit7
bit0:
BIT 0,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit1:
BIT 1,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit2:
BIT 2,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit3:
BIT 3,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit4:
BIT 4,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit5:
BIT 5,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit6:
BIT 6,B
jp nz,setbitfirst
jp z,dontsetbitfirst
bit7:
BIT 7,B
jp z,dontsetbitfirst
jp nz,setbitfirst
setbitfirst:
LD A,1
LD (rightbit),A
dontsetbitfirst:
LD HL,(screenaddress)
LD A,31
LD L,A
LD (screenwidthiter),A
LD (screenaddress),HL
LD A,0
LD (leftbit),A
BIT 7,(HL)
jp nz,dontsetbit
LD A,1
LD (leftbit),A
dontsetbit:
LD A,(HL)
SLA A
LD (HL),A
LD A,(rightbit)
CP 0
jp z, dontsetrightbit
LD A,(HL)
OR 1
LD (HL),A
dontsetrightbit:
LD A,(leftbit)
LD (rightbit),A
LD A,30
LD (screenwidthiter),A
LD L,A
LD (screenaddress),HL
screenhori:
LD A,0
LD (leftbit),A
BIT 7,(HL)
jp nz,dontsetbit3
LD A,1
LD (leftbit),A
dontsetbit3:
LD B,(HL)
SLA B
LD A,(rightbit)
CP 0
jp nz,dontsetblockbit2
LD A,B
OR 1
LD B,A
dontsetblockbit2:
LD (HL),B
LD A,(screenwidthiter)
LD L,A
DEC A
LD (screenwidthiter),A
LD A,(leftbit)
LD (rightbit),A
LD A,(screenwidthiter)
CP 0
jp nz,screenhori
LD A,(screenheightiter)
INC H
DEC A
LD (screenaddress),HL
LD (screenheightiter),A
CP 0
jp nz,screenvert
LD A,(__LABEL__landscapeeightiter)
INC A
LD (__LABEL__landscapeeightiter),A
LD A,(__LABEL__landscapeeightiter)
CP 8
jp nz,dontresetblock
LD A,0
LD (__LABEL__landscapeeightiter),A
LD A,(landscapeiter)
INC A
LD (landscapeiter),A
dontresetblock:
;jp loop
end asm
end function
Dim x as Integer
for x=0 to 31
Print AT 0,x;STR(x)
next
for x=0 to 30
drawthis()
Print AT x,0;STR(PEEK(@printablevar))+"-"
next
Print "done"
STOP:
printablevar:
ASM
defb 255
END ASM
landscapeeightiter:
ASM
defb 0
blockiter:
defw 8
delayiter:
defw 60000
screenwidthiter:
defb 31
screenheightiter:
defb 8
scrolliter:
defw 10000
graphic:
defb 255
screenaddress:
defw 0
landscapeiter:
defb 0
data:
defb 1,1,0,1,1,1,0,1,1,2,2,2,2,0,1,0,1,0,2,2,2,2
brick:
defb 249,249,0,159,159,0,249,249
crystal:
defb 16,40,84,40,84,40,16,0
rightbit:
defb 0
leftbit:
defb 0
DISPNUM:
call 11563 ; We'll push the BC register onto the calculator stack
call 11747 ; and then output that number to the screen by calling this routine
ret
end asm
Re: Scrolling Tiles - LCD - 05-22-2013
Looks good, and very smooth...
By the way:
Code: if NextGraphic Band 64=64
can be shortened:
Re: Scrolling Tiles - boriel - 05-22-2013
LCD Wrote:Looks good, and very smooth... It does indeed! :!:
The idea behind ZX Basic is you don't have to go down to ASM if possible :roll:
Quote:By the way:
Code: if NextGraphic Band 64=64
can be shortened:
That's right. In fact this rule can be applied to the other lines also
(band 32 = 32, band 16 = 16 etc).
Slenkar, the rule is
Code: IF x band 2^n = 2^n THEN
can be replaced by
Not sure if the compiler already optimizes that with -O3. Will check it... :|
Re: Scrolling Tiles - slenkar - 05-22-2013
oh ok thanks
I havent checked this out with 03 yet, i wonder if its faster
I put the bricks on the bottom of the screen and colored them,
and put a few GOTO's in there to make it more efficient.
If there are any other optimizations feel free to share
Code: '#include<mj/fourspriter.bas>
DIM mapdata(63) AS UBYTE => {1,0,1,1,1,1,1,1,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2}
DIM brick(7) AS UBYTE =>{249,249,0,159,159,0,249,249}
DIM crystal(7) AS UBYTE =>{16,40,84,40,84,40,16,0}
INK 2
PAPER 0
'MJfspActivateSprite(1)
'MJfspSetGfxAddress (@brick)
'MJfspSetGfxSprite (1,1,2,3,4)
'MJfspInitSprites ()
'MJfspMoveSprite (1,1,1)
Dim CurrentGraphic as ubyte=1
Dim NextGraphic as Ubyte
Dim PreviousGraphic as ubyte
Dim address as UInteger
Dim LineStartAddress as UInteger
addr=16384
LineStartAddress=addr
Dim PreviousAddress as UInteger
Dim LandscapeEightIter as Ubyte
Dim LandscapeIter as ubyte
Dim LineNumber as UByte
for x=0 to 31
for y=0 to 23
Print AT y,x;" "
next
next
Dim startaddress as UInteger
ASM
LD HL,(__LABEL__adr)
LD A,2
SLA A
SLA A
SLA A
OR H
LD H,A
LD A,7
SLA A
SLA A
SLA A
SLA A
SLA A
OR L
LD L,A
LD (__LABEL__adr),HL
END ASM
Print AT 1,0;STR(PEEK(UINTEGER,@adr))
for iterations=0 to 480 'scroll left 480 times
address=PEEK(UInteger,@adr)
for y=0 to 7
LineStartAddress=address
for x=0 to 31
CurrentGraphic = PEEK(address)
'pause 5
if x>0 'the leftmost byte has no graphics to its left
if CurrentGraphic Band 128=128 'if this graphic has a dot on the left
PreviousGraphic=PreviousGraphic Bor 1 'Add a dot to the right of the previous graphic byte
POKE PreviousAddress,PreviousGraphic
end if
end if
PreviousAddress=address 'save the address of the byte on the left
CurrentGraphic=CurrentGraphic SHL 1 'shift dors to left
PreviousGraphic=CurrentGraphic 'save graphic
POKE address,CurrentGraphic
if x=31
if mapdata(LandscapeIter)=1
NextGraphic=brick(LineNumber)
GOTO 50
end if
if mapdata(LandscapeIter)=2
NextGraphic=crystal(LineNumber)
GOTO 50
end if
if mapdata(LandscapeIter)=0
NextGraphic=0
end if
50
if LandscapeEightIter=0
if NextGraphic Band 1
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=1
if NextGraphic Band 2
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=2
if NextGraphic Band 4
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=3
if NextGraphic Band 8=8
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=4
if NextGraphic Band 16
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=5
if NextGraphic Band 32
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=6
if NextGraphic Band 64
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
if LandscapeEightIter=7
if NextGraphic Band 128
CurrentGraphic=CurrentGraphic BOR 1
GOTO 100
end if
end if
100 POKE address,CurrentGraphic
end if
address=address+1 'move one square right
next
address=LineStartAddress
address=address+256 'move one line down
LineNumber=LineNumber+1
next
LineNumber=0
LandscapeEightIter=LandscapeEightIter+1
if LandscapeEightIter=8
LandscapeEightIter=0
LandscapeIter=LandscapeIter+1
end if
'MJfspUpdateSprites()
next
'Print "done"
'Print STR(178 Band 128)
STOP
adr:
ASM
defw 16384
END ASM
poker:
ASM
defb 0
END ASM
Re: Scrolling Tiles - britlion - 05-23-2013
I think your gotos could be more descriptive, if you have to use them. Structured programming, of course, never uses them - though I am guilty of doing so How about instead of goto 100 you used goto endofblock ?
What you're trying to do, though is escape multiple if's right?
So you began with
if test=1 then
do thing 1
end if
if test=2 then
do thing 2
end if
if test=3 then
do thing 3
end if
And elected to speed that up with:
if test=1 then
do thing 1
goto endofblock
end if
I believe? So that it doesn't do all the other tests?
In that case, you need to look at If / then / Else concepts, I think:
IF test=1 then
do thing 1
ELSEIF test=2 then
do thing 2
ELSEIF test=3 then
do thing 3
ELSE
do thing "not found"
END IF
It's one if, and it only tests until it finds a match, because ELSE doesn't run if the IF is true. If test=1 then it does thing 1, and gets out right there. if test=2 - it checks to see if test=1, finds it isn't so checks to see if test=2, finds it is, does thing 2 and goes to the END IF.
Does that help?
Re: Scrolling Tiles - slenkar - 05-23-2013
yes that seems more sensible
Re: Scrolling Tiles - slenkar - 05-23-2013
faster version, uses 9 bit rotation
this one takes 7 seconds to scroll 800 pixels
the previous one takes 23 seconds
Code: DIM mapdata(63) AS UBYTE => {1,0,1,1,1,1,1,1,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2,1,0,2,0,2,1,1,2}
DIM brick(7) AS UBYTE =>{249,249,0,159,159,0,249,249}
DIM crystal(7) AS UBYTE =>{16,40,84,40,84,40,16,0}
Dim LandscapeBANDS(7) AS UBYTE=>{1,2,4,8,16,32,64,128}
INK 2
PAPER 0
Dim LandscapeEightIter as Ubyte
Dim LandscapeIter as ubyte
Dim LineNumber as UByte
DIm NextGraphic as UByte
Dim address as UBYTE
Dim x as UINTEGER
for x=0 to 31
for y=0 to 23
Print AT y,x;"A"
next
next
Dim startaddress as UInteger
Function FASTCALL drawthis() as UBYTE
ASM
;LD A,255
;LD (__LABEL__iters),A
;iterloop:
LD A,7
LD (__LABEL__heightiter),A
LD HL,(__LABEL__startadr)
heightloop:
LD B,L
Ld A,(HL)
RLA
LD (HL),A
widthloop:
DEC L
Ld A,(HL)
RLA
LD (HL),A
djnz widthloop
LD A,31
LD L,A
INC H
LD A,(__LABEL__heightiter)
DEC A
LD (__LABEL__heightiter),A
CP 0
JP NZ,heightloop
;LD A,(__LABEL__iters)
;DEC A
;LD (__LABEL__iters),A
;CP 0
;jp nz,iterloop
END ASM
End Function
for x=0 to 800
drawthis()
'address=PEEK (UINTEGER,@adr)
'address=address+31
'CurrentGraphic=PEEK(UINTEGER,address)
'CurrentGraphic Or 1
'P''OKE UINTEGER address,CurrentGraphic
for LineNumber=0 to 7
CurrentGraphic=PEEK(UINTEGER,address)
if mapdata(LandscapeIter)=1
NextGraphic=brick(LineNumber)
GOTO 50
end if
if mapdata(LandscapeIter)=2
NextGraphic=crystal(LineNumber)
GOTO 50
end if
if mapdata(LandscapeIter)=0
NextGraphic=0
end if
50
'if LineNumber=0
if NextGraphic Band LandscapeBANDS(LandscapeEightIter)
POKE @bit0+LineNumber,1
else
POKE @bit0+LineNumber,0
end if
'GOTO 100
'end if
100
next
LandscapeEightIter=LandscapeEightIter+1
if LandscapeEightIter=8
LandscapeEightIter=0
LandscapeIter=LandscapeIter+1
end if
ASM
LD HL,(__LABEL__startadr)
LD A,31
LD L,A
LD A,(__LABEL__bit0)
CP 0
JP Z,dontset0
LD A,(HL)
OR 1
LD (HL),A
dontset0:
INC H
LD A,(__LABEL__bit1)
CP 0
JP Z,dontset1
LD A,(HL)
OR 1
LD (HL),A
dontset1:
INC H
LD A,(__LABEL__bit2)
CP 0
JP Z,dontset2
LD A,(HL)
OR 1
LD (HL),A
dontset2:
INC H
LD A,(__LABEL__bit3)
CP 0
JP Z,dontset3
LD A,(HL)
OR 1
LD (HL),A
dontset3:
INC H
LD A,(__LABEL__bit4)
CP 0
JP Z,dontset4
LD A,(HL)
OR 1
LD (HL),A
dontset4:
INC H
LD A,(__LABEL__bit5)
CP 0
JP Z,dontset5
LD A,(HL)
OR 1
LD (HL),A
dontset5:
INC H
LD A,(__LABEL__bit6)
CP 0
JP Z,dontset6
LD A,(HL)
OR 1
LD (HL),A
dontset6:
INC H
LD A,(__LABEL__bit7)
CP 0
JP Z,dontset7
LD A,(HL)
OR 1
LD (HL),A
dontset7:
END ASM
next
'Print "done"
'Print STR(178 Band 128)
STOP
adr:
ASM
defw 16384
END ASM
startadr:
ASM
defw 16384
END ASM
currentgraphic:
ASM
defb 0
END ASM
linestartadr:
ASM
defb 0
END ASM
bit0:
ASM
defb 0
END ASM
bit1:
ASM
defb 0
END ASM
bit2:
ASM
defb 0
END ASM
bit3:
ASM
defb 0
END ASM
bit4:
ASM
defb 0
END ASM
bit5:
ASM
defb 0
END ASM
bit6:
ASM
defb 0
END ASM
bit7:
ASM
defb 0
END ASM
heightiter:
ASM
defb 7
END ASM
iters:
ASM
defb 255
END ASM
Re: Scrolling Tiles - boriel - 05-23-2013
slenkar Wrote:faster version, uses 9 bit rotation
this one takes 7 seconds to scroll 800 pixels
the previous one takes 23 seconds awesome! hock:
But you finally used ASM
(just kidding) :mrgreen: .
I see how you overcome the limitation using external labels from within ASM.
I'm working on a system to access BASIC variables from ASM in an easy way. The compiler is currently *broken*. I finally started the hard refactoring (almost from scratch) I mentioned some month ago. Please, be patient.
Re: Scrolling Tiles - slenkar - 05-23-2013
There is still quite a bit of basic in there,
Im gonna combine it with a sprite library and see if it looks ok
Re: Scrolling Tiles - britlion - 05-28-2013
Some ideas
Is
At 15 T states
A better choice than:
Code: LD A,(HL)
RLA
LD (HL),A
At 7+4+7=18 T states perhaps? (Also 1 byte shorter, and doesn't mess up your A register, for what it's worth - which is usually the biggest reason it's useful).
Similarly:
Code: LD A,31
LD L,A
LD A,(__LABEL__bit0)
You are faffing with A, where:
Code: LD L,31
LD A,(__LABEL__bit0)
is more direct, surely?
I suspect that:
Code: LD A,(HL)
OR 1
LD (HL),A
Again faffs with the A register (for 7+4+7 T states), where
Is 15 T states and doesn't faff with the A register.
Code: LD A,(__LABEL__bit0)
CP 0
JP Z,dontset0
CP 0 works, but is two bytes. You can trigger the flags with something like AND A - which is a single byte opcode, and faster.
Code: LD A,(__LABEL__bit0)
AND A
JP Z,dontset0
Finally, I get the feeling that using a bunch of bytes in memory for the bit counter could be optimized by using bits of a byte for the bit information. But I'm way too distracted to try to refactor that right now So I'll stick to simple tweak suggestions.
Al that said. Wow. You're using assembler, and it's working like a charm! Well done! This isn't easy stuff
Re: Scrolling Tiles - slenkar - 05-28-2013
thanks I put all those suggestions in the code and they worked
testing bits of a byte in a register would be faster than loading 8 bytes and testing each :oops:
|