Omnimaga
Calculator Community => TI Calculators => ASM => Topic started by: matthias1992 on July 03, 2010, 10:43:56 am
-
hey there!
I slightly modified the spirte routine from Ti asm in 28 days to support hardware keycode control. The point is if i wanted to display a 16x16 sprite (x,y) then what should I change? I do understand how to make a (8x#) sprite, you just need to modify B for that but how can I make the sprite wider?
Thanks in advance!
.nolist
#include "ti83plus.inc"
#define ProgStart $9D95
.list
.org ProgStart - 2
.db t2ByteTok, tAsmCmp
B_CALL(_RunIndicOff)
B_CALL(_GrBufClr)
Show:
CALL PutSpr
B_CALL(_GrBufCpy)
KeyLoop:
LD A, $FD
OUT (1), A
IN A, (1)
CP %10111111
RET Z
LD A, $FE
OUT (1), A
IN A, (1)
CP %11111110
JP Z, MoveDown
CP %11111101
JP Z, MoveLeft
CP %11110111
JP Z, MoveUp
JR NZ, KeyLoop
; Move sprite right
CALL PutSpr ; Erase sprite
LD HL, xpos
INC (HL)
JR Show ; Draw sprite at new location
MoveLeft:
; Move sprite left
CALL PutSpr
LD HL, xpos
DEC (HL)
JR Show
MoveUp:
; Move sprite up
CALL PutSpr
LD HL, ypos
DEC (HL)
JR Show
MoveDown:
CALL PutSpr
LD HL, ypos
INC (HL)
JR Show
ypos: .DB 0
xpos: .DB 0
sprite:
.DB %10000001
.DB %11000011
.DB %01100110
.DB %00111100
.DB %00111100
.DB %01100110
.DB %11000011
.DB %10000001
PutSpr:
LD DE, (ypos)
LD IX, sprite
LD B, 8
ClipSprXOR:
; D = xpos
; E = ypos
; B = height
; IX = image address
; Start by doing vertical clipping
LD A, %11111111 ; Reset clipping mask
LD (clip_mask), A
LD A, E ; If ypos is negative
OR A ; try clipping the top
JP M, ClipTop ;
SUB 64 ; If ypos is >= 64
RET NC ; sprite is off-screen
NEG ; If (64 - ypos) > height
CP B ; don't need to clip
JR NC, VertClipDone ;
LD B, A ; Do bottom clipping by
JR VertClipDone ; setting height to (64 - ypos)
ClipTop:
LD A, B ; If ypos <= -height
NEG ; sprite is off-screen
SUB E ;
RET NC ;
PUSH AF
ADD A, B ; Get the number of clipped rows
LD E, 0 ; Set ypos to 0 (top of screen)
LD B, E ; Advance image data pointer
LD C, A ;
ADD IX, BC ;
POP AF
NEG ; Get the number of visible rows
LD B, A ; and set as height
VertClipDone:
; Now we're doing horizontal clipping
LD C, 0 ; Reset correction factor
LD A, D
CP -7 ; If 0 > xpos >= -7
JR NC, ClipLeft ; clip the left side
CP 96 ; If xpos >= 96
RET NC ; sprite is off-screen
CP 89 ; If 0 <= xpos < 89
JR C, HorizClipDone ; don't need to clip
ClipRight:
AND 7 ; Determine the clipping mask
LD C, A
LD A, %11111111
FindRightMask:
ADD A, A
DEC C
JR NZ, FindRightMask
LD (clip_mask), A
LD A, D
JR HorizClipDone
ClipLeft:
AND 7 ; Determine the clipping mask
LD C, A
LD A, %11111111
FindLeftMask:
ADD A, A
DEC C
JR NZ, FindLeftMask
CPL
LD (clip_mask), A
LD A, D
ADD A, 96 ; Set xpos so sprite will "spill over"
LD C, 12 ; Set correction
HorizClipDone:
; A = xpos
; E = ypos
; B = height
; IX = image address
; Now we can finally display the sprite.
LD H, 0
LD D, H
LD L, E
ADD HL, HL
ADD HL, DE
ADD HL, HL
ADD HL, HL
LD E, A
SRL E
SRL E
SRL E
ADD HL, DE
LD DE, PlotSScreen
ADD HL, DE
LD D, 0 ; Correct graph buffer address
LD E, C ; if clipping the left side
SBC HL, DE ;
AND 7
JR Z, _Aligned
LD C, A
LD DE, 11
_RowLoop:
PUSH BC
LD B, C
LD A, (clip_mask) ; Mask out the part of the sprite
AND (IX) ; to be horizontally clipped
LD C, 0
_ShiftLoop:
SRL A
RR C
DJNZ _ShiftLoop
XOR (HL)
LD (HL), A
INC HL
LD A, C
XOR (HL)
LD (HL), A
ADD HL, DE
INC IX
POP BC
DJNZ _RowLoop
RET
_Aligned:
LD DE, 12
_PutLoop:
LD A, (IX)
XOR (HL)
LD (HL), A
INC IX
ADD HL, DE
DJNZ _PutLoop
RET
clip_mask: .DB 0
.end
.end
-
And here is yet another problem, I am trying to make this in a manner that every time + is pressed the next sprite is drawn and every time I press - the previous one is drawn. C is the counter of the sprites and checked if it is z, if it is the program is aborted (becuase you can't do -1 sprite) and if it is >255 9the maximum of 8 bits) it should also be aborted. P.s. I know C is already used elsewere, that is likely to screw it up but i tried to insert a cntr byte by doing:
cntr: .db 0
but then every time I did this:
LD cntr, C
or this
LD (cntr), C
it threw a error saying: "unrecognized argument"
This is my source:
.nolist
#include "ti83plus.inc"
#define ProgStart $9D95
.list
.org ProgStart - 2
.db t2ByteTok, tAsmCmp
ypos: .DB 0
xpos: .DB 0
clip_mask: .DB 0
B_CALL(_RunIndicOff)
B_CALL(_GrBufClr)
LD C, $0001
PUSH BC
Show:
CALL PutSpr
B_CALL(_GrBufCpy)
KeyLoop:
LD A, $FD
OUT (1), A
IN A, (1)
CP %10111111
RET Z
CP %11111101
JP Z, NextSpr
CP %11111011
JP Z, PrevSpr
LD A, $FE
OUT (1), A
IN A, (1)
CP %11111110
JP Z, MoveDown
CP %11111101
JP Z, MoveLeft
CP %11110111
JP Z, MoveUp
JR NZ, KeyLoop
; Move sprite right
CALL PutSpr ; Erase sprite
LD HL, xpos
INC (HL)
JR Show ; Draw sprite at new location
MoveLeft:
; Move sprite left
CALL PutSpr
LD HL, xpos
DEC (HL)
JR Show
MoveUp:
; Move sprite up
CALL PutSpr
LD HL, ypos
DEC (HL)
JR Show
MoveDown:
CALL PutSpr
LD HL, ypos
INC (HL)
JR Show
NextSpr:
POP BC
LD A, C
OR A
RET Z
CP 255
RET Z
INC C
CALL PutSpr
PrevSpr:
POP BC
LD A, C
OR A
RET Z
CP 255
RET Z
DEC C
CALL PutSpr
PutSpr:
PUSH BC
LD DE, (ypos)
LD A, C
CP 1
LD IX, Spr1
CP 2
LD IX, Spr2
LD B, 8
ClipSprXOR:
; D = xpos
; E = ypos
; B = height
; IX = image address
; Start by doing vertical clipping
LD A, %11111111 ; Reset clipping mask
LD (clip_mask), A
LD A, E ; If ypos is negative
OR A ; try clipping the top
JP M, ClipTop ;
SUB 64 ; If ypos is >= 64
RET NC ; sprite is off-screen
NEG ; If (64 - ypos) > height
CP B ; don't need to clip
JR NC, VertClipDone ;
LD B, A ; Do bottom clipping by
JR VertClipDone ; setting height to (64 - ypos)
ClipTop:
LD A, B ; If ypos <= -height
NEG ; sprite is off-screen
SUB E ;
RET NC ;
PUSH AF
ADD A, B ; Get the number of clipped rows
LD E, 0 ; Set ypos to 0 (top of screen)
LD B, E ; Advance image data pointer
LD C, A ;
ADD IX, BC ;
POP AF
NEG ; Get the number of visible rows
LD B, A ; and set as height
VertClipDone:
; Now we're doing horizontal clipping
LD C, 0 ; Reset correction factor
LD A, D
CP -7 ; If 0 > xpos >= -7
JR NC, ClipLeft ; clip the left side
CP 96 ; If xpos >= 96
RET NC ; sprite is off-screen
CP 89 ; If 0 <= xpos < 89
JR C, HorizClipDone ; don't need to clip
ClipRight:
AND 7 ; Determine the clipping mask
LD C, A
LD A, %11111111
FindRightMask:
ADD A, A
DEC C
JR NZ, FindRightMask
LD (clip_mask), A
LD A, D
JR HorizClipDone
ClipLeft:
AND 7 ; Determine the clipping mask
LD C, A
LD A, %11111111
FindLeftMask:
ADD A, A
DEC C
JR NZ, FindLeftMask
CPL
LD (clip_mask), A
LD A, D
ADD A, 96 ; Set xpos so sprite will "spill over"
LD C, 12 ; Set correction
HorizClipDone:
; A = xpos
; E = ypos
; B = height
; IX = image address
; Now we can finally display the sprite.
LD H, 0
LD D, H
LD L, E
ADD HL, HL
ADD HL, DE
ADD HL, HL
ADD HL, HL
LD E, A
SRL E
SRL E
SRL E
ADD HL, DE
LD DE, PlotSScreen
ADD HL, DE
LD D, 0 ; Correct graph buffer address
LD E, C ; if clipping the left side
SBC HL, DE ;
AND 7
JR Z, _Aligned
LD C, A
LD DE, 11
_RowLoop:
PUSH BC
LD B, C
LD A, (clip_mask) ; Mask out the part of the sprite
AND (IX) ; to be horizontally clipped
LD C, 0
_ShiftLoop:
SRL A
RR C
DJNZ _ShiftLoop
XOR (HL)
LD (HL), A
INC HL
LD A, C
XOR (HL)
LD (HL), A
ADD HL, DE
INC IX
POP BC
DJNZ _RowLoop
RET
_Aligned:
LD DE, 12
_PutLoop:
LD A, (IX)
XOR (HL)
LD (HL), A
INC IX
ADD HL, DE
DJNZ _PutLoop
RET
Spr1:
.DB %10000001
.DB %11000011
.DB %01100110
.DB %00111100
.DB %00111100
.DB %01100110
.DB %11000011
.DB %10000001
Spr2:
.DB %11111111
.DB %10000001
.DB %10000001
.DB %10000001
.DB %10000001
.DB %10000001
.DB %10000001
.DB %11111111
.end
.end
-
P.s. I know C is already used elsewere, that is likely to screw it up but i tried to insert a cntr byte by doing:
cntr: .db 0
but then every time I did this:
LD cntr, C
or this
LD (cntr), C
it threw a error saying: "unrecognized argument"
The reason that's not working is that the only 8-bit register you can store into/from an immediate address is A. One way you can get around this is by making "cntr" two bytes instead of one, and then using "ld (cntr), BC".
I also see a few issues with your code, so let's try and tackle them one at a time :) (The cool thing is that one of them sort of fixes itself and doesn't actually cause a visible problem XD)
- The first is where you put xpos, ypo, and clip_mask. Although in this case it isn't a problem, under most circumstances it could lead to quite annoying behavior :D
It's best to put variables like this either at the end of your code or at least somewhere it won't be executed (in the Asm28days example, notice that ypos/xpos/sprite are skipped because of the jr's). The reason for this is that a db/dw directive will actually insert the numbers into the code. Even though the programmer knows they just want to use those locations as storage, the processor will still try and execute it as code. In your case the three consecutive $00's are executed, but since this is the opcode for 'nop' nothing happens.
- The next issue are those "push BC"'s you have. When you use "call", the address of where to return to is pushed onto the same stack as when you push/pop the 16-bit registers. This means that when you use "ret", whatever is at the top of the stack is popped and used as the address to return to. There are a couple places where this will cause a problem:
1) When running through "KeyLoop", you have BC at the top of the stack so when it gets to the "ret z" it starts executing code starting at the value of BC, which is probably not even part of the program. You need to be careful when using the stack and make sure there aren't any conflicts with call/ret.
2) In PutSpr, the first line is a "push BC" and I don't see any "pop BC"'s before the first ret, so weird things are going to happen there as well.
I think the best way to fix these problems for your program is to just use some memory location for "cntr" instead of the stack.
I hope this helps ;D I'm not sure if I got all the bugs, but my computer is being mean to me today so I can't test this on an emulator.