Difference between revisions of "Z80 Routines:Graphic:put8x8sprite"

From WikiTI
Jump to: navigation, search
m
(input of routine added)
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Category:Z80 Routines:Graphic|put8x8sprite]][[Category:Z80 Routines|put8x8sprite]]
+
[[Category:Z80 Routines:Graphic|Put8xBsprite]][[Category:Z80 Routines|Put8xBsprite]]
The '''put8x8sprite''' routine is used to plot a 8x8 sized sprite.
+
 
{{stub}}
+
The '''put8xBsprite''' routine is used to plot a 8xB sized sprite.
  
 
== Code ==
 
== Code ==
  
=== Version without clipping ===
+
=== Basic Version ===
 
  <nowiki>
 
  <nowiki>
 +
;-----> Draw a sprite
 +
; input: a=x e=y
 +
; b=height of sprite
 +
; ix holds pointer
 +
; output:
 +
; destroys de,hl
 +
putSprite8xb:
 +
ld h,$00
 +
ld d,h
 +
#ifdef faster
 +
sla e ;*2
 +
sla e ;*4
 +
#endif
 +
ld l,e
 +
add hl,de ;*2 faster:*8
 +
add hl,de ;*3 faster:*12
 +
#ifndef faster
 +
add hl,hl ;*6
 +
add hl,hl ;*12
 +
#endif
 +
ld e,a
 +
srl e
 +
srl e
 +
srl e
 +
add hl,de
 +
ld de,gbuf
 +
add hl,de
 +
and 7
 +
ld c,a
 +
putSpriteLoop1:
 +
ld d,(ix)
 +
ld e,$00
 +
ld a,c
 +
or a
 +
jr z,putSpriteSkip1
 +
putSpriteLoop2:
 +
srl d
 +
rr e
 +
dec a
 +
jr nz,putSpriteLoop2
 +
putSpriteSkip1:
 +
ld a,(hl)
 +
xor d
 +
ld (hl),a
 +
inc hl
 +
ld a,(hl)
 +
xor e
 +
ld (hl),a
 +
ld de,$0B
 +
add hl,de
 +
inc ix
 +
djnz putSpriteLoop1
 +
ret
 +
</nowiki>
 +
 +
=== Masked Version ===
 +
<nowiki>
 +
PutSpriteMask:
 +
; Displays an 8x8 masked sprite
 +
; A = x coordinate
 +
; E = y coordinate
 +
; IX = address of sprite
 +
; IX + 8 = address of mask
 +
    LD    H, 0
 +
    LD    D, H
 +
    LD    E, L
 +
    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
 +
 +
    AND    7
 +
    JR    Z, _Aligned
 +
    LD    C, A
 +
    LD    B,8
 +
 +
_RowLoop:
 +
    PUSH  BC
 +
    LD    B, C
 +
    LD    D, (IX)
 +
    LD    A, (IX + 8)
 +
    LD    C, 0
 +
    LD    E, C
 +
 +
_ShiftLoop:
 +
    SRL    A
 +
    RR    C
 +
    SRL    D
 +
    RR    E
 +
    DJNZ  _ShiftLoop
 +
 +
    CPL
 +
    AND    (HL)
 +
    XOR    D
 +
    LD    (HL), A
 +
 +
    INC    HL
 +
    LD    A, C
 +
 +
    CPL
 +
    AND    (HL)
 +
    XOR    E
 +
    LD    (HL), A
 +
 +
    LD    DE, 12
 +
    ADD    HL, DE
 +
    INC    IX
 +
    POP    BC
 +
    DJNZ  _RowLoop
 +
    RET
 +
 +
_Aligned:
 +
    LD    DE, 12
 +
 +
_PutLoop
 +
    LD    A, (IX + 8)
 +
    AND    (HL)
 +
    XOR    (IX)
 +
    LD    (HL), A
 +
    INC    IX
 +
    ADD    HL, DE
 +
    DJNZ  _PutLoop
 +
    RET
  
 
  </nowiki>
 
  </nowiki>
  
=== Version with Clipping ===
+
=== Full Clipping (vertical and horizontal) Version ===
 
  <nowiki>
 
  <nowiki>
 +
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
  
 
  </nowiki>
 
  </nowiki>
 +
 +
== Customization ==
 +
 +
You can suit these routines to your needs by following the following suggestions:
 +
- change the input in e to l
 +
- replace the logic ("xor" intructions to "or" or "cpl \ and ")
 +
- instead of 8xB, you can put a ld b,8
 +
- adapt for each sprite its height/width
 +
.db 3 ; height
 +
.db %11111111
 +
.db %11111111
 +
.db %11111111
 +
- take out horizontal/vertical clipping if you don't need it
 +
 +
You will need to change the code yourself. If you understand well assembly it will be a quick task.
 +
 +
Define faster to get more speed with size costs.
 +
To use these routines in the TI-85 or TI-86, you need to change not only the address of the graphics buffer but also the multiplication of the x coordinates. (TI-83+ screen is 96x64 instead of 128x64) Later we can provide a TI-85/86 version.
 +
  
 
== Example ==
 
== Example ==
 +
 +
A example using the basic version of PutSprite8xB.
 
  <nowiki>
 
  <nowiki>
 
   ;...
 
   ;...

Latest revision as of 05:01, 16 May 2010


The put8xBsprite routine is used to plot a 8xB sized sprite.

Code

Basic Version

;-----> Draw a sprite
; input:	a=x	e=y
;		b=height of sprite
;		ix holds pointer
; output:	
; destroys de,hl
putSprite8xb:
	ld	h,$00
	ld	d,h
#ifdef	faster
	sla e			;*2
	sla e			;*4
#endif
	ld	l,e
	add	hl,de		;*2	faster:*8
	add	hl,de		;*3	faster:*12
#ifndef	faster
	add	hl,hl		;*6
	add	hl,hl		;*12
#endif
	ld e,a
	srl	e
	srl	e
	srl	e
	add	hl,de
	ld	de,gbuf
	add	hl,de
	and 7
	ld c,a
putSpriteLoop1:
	ld	d,(ix)
	ld	e,$00
	ld a,c
	or a
	jr	z,putSpriteSkip1
putSpriteLoop2:
	srl	d
	rr	e
	dec	a
	jr	nz,putSpriteLoop2
putSpriteSkip1:
	ld	a,(hl)
	xor	d
	ld	(hl),a
	inc	hl
	ld	a,(hl)
	xor	e
	ld	(hl),a
	ld	de,$0B
	add	hl,de
	inc	ix
	djnz	putSpriteLoop1
	ret
 

Masked Version

PutSpriteMask:
; Displays an 8x8 masked sprite
; A = x coordinate
; E = y coordinate
; IX = address of sprite
; IX + 8 = address of mask
    LD     H, 0
    LD     D, H
    LD     E, L
    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

    AND    7
    JR     Z, _Aligned
    LD     C, A
    LD     B,8

_RowLoop:
    PUSH   BC
    LD     B, C
    LD     D, (IX)
    LD     A, (IX + 8)
    LD     C, 0
    LD     E, C

_ShiftLoop:
    SRL    A
    RR     C
    SRL    D
    RR     E
    DJNZ   _ShiftLoop

    CPL
    AND    (HL)
    XOR    D
    LD     (HL), A

    INC    HL
    LD     A, C

    CPL
    AND    (HL)
    XOR    E
    LD     (HL), A

    LD     DE, 12
    ADD    HL, DE
    INC    IX
    POP    BC
    DJNZ   _RowLoop
    RET

_Aligned:
    LD     DE, 12

_PutLoop
    LD     A, (IX + 8)
    AND    (HL)
    XOR    (IX)
    LD     (HL), A
    INC    IX
    ADD    HL, DE
    DJNZ   _PutLoop
    RET

 

Full Clipping (vertical and horizontal) Version

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

 

Customization

You can suit these routines to your needs by following the following suggestions: - change the input in e to l - replace the logic ("xor" intructions to "or" or "cpl \ and ") - instead of 8xB, you can put a ld b,8 - adapt for each sprite its height/width

.db 3				; height
.db %11111111
.db %11111111
.db %11111111

- take out horizontal/vertical clipping if you don't need it

You will need to change the code yourself. If you understand well assembly it will be a quick task.

Define faster to get more speed with size costs. To use these routines in the TI-85 or TI-86, you need to change not only the address of the graphics buffer but also the multiplication of the x coordinates. (TI-83+ screen is 96x64 instead of 128x64) Later we can provide a TI-85/86 version.


Example

A example using the basic version of PutSprite8xB.

   ;...
   ld   e,8   ;y
   ld   a,16  ;x
   ld   b,8   ;height
   ld   ix,sprite
   call putsprite
   call fastcopy
   ;...
sprite:
   .db %11111111
   .db %10000001
   .db %10000001
   .db %10000001
   .db %10000001
   .db %10000001
   .db %10000001
   .db %11111111