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

From WikiTI
Jump to: navigation, search
(+ version that doesn't use shadow registers)
m (The contents table should be at the top!)
Line 3: Line 3:
 
The sprite can be of any size (max. 96x64), so the input of the largesprite routine is quite big.
 
The sprite can be of any size (max. 96x64), so the input of the largesprite routine is quite big.
  
 +
== Code ==
 
Here is Joe Wingbermuehle's version, which is the one used in ION.
 
Here is Joe Wingbermuehle's version, which is the one used in ION.
  

Revision as of 05:36, 18 May 2007

The Largesprite routine is used to copy the content of a sprite to the Graph Buffer. The sprite can be of any size (max. 96x64), so the input of the largesprite routine is quite big.

Code

Here is Joe Wingbermuehle's version, which is the one used in ION.

;=======================
;LargeSprite
;by Joe Wingbermuehle
;=======================
;Does:   Copy a sprite to the gbuf
;Input:  ix=sprite address, a='x', l='y', b='height' (in pixels), c='width' (in bytes, e.g. 2 would be 16)
;Output: The sprite is copied to the gbuf
;-----------------------
largeSprite:
   di                                 ;turn interrupts off (we want to use shadow registers)
   ex   af,af'
                                      ;exchange af with af'     \
   ld   a,c                           ;ld c in a (a = 'width')  | for not destroying a ('x')
   push   af                          ;push a                   |
      ex   af,af'
                                      ;exchange back            | and 'width' is now in a' (saved)
      ld   e,l                        ;e = 'y'
      ld   h,$00                      ;h =  0
      ld   d,h                        ;d =  0
      add   hl,de                     ;'y' *2  \
      add   hl,de                     ;    *3  | calculate 'y' *12 because 'y' is 'in rows'
      add   hl,hl                     ;    *6  |   (screen is 12 bytes in length)
      add   hl,hl                     ;    *12 /
      ld   e,a                        ;e = 'x'
      and   $07                       ;and %00000111
      ld   c,a                        ;last 3 bits in c (amount of bits to shift all bytes)
      srl   e                         ;e/2   | shifting e ('x') 3 bits to the right
      srl   e                         ; /4   |   %11111111 becomes %00011111 for example
      srl   e                         ; /8   /
      add   hl,de                     ;hl = 'y'; de = 'x' (rounded) | add them
      ld   de, gbuf                   ;de = the adress of graph buffer
      add   hl,de                     ;add hl to the adress of the gbuf
largeSpriteLoop1:
      push   hl                       ;save adress
largeSpriteLoop2:
         ld   d,(ix)                  ;first sprite data in d
         ld   e,$00                   ;e = 0
         ld   a,c                     ;a = c (to not destroy c)
         or   a                       ;is a = 0? (same as cp 0)
         jr   z,largeSpriteSkip1      ;if theres nothing to shift (a = 0) loop it
largeSpriteLoop3:
         srl   d                      ;shift one bit to the right; put the destroyed bit in the carry flag
         rr   e                       ;put the carry flag in e (%00000000 becomes %10000000 if carry flag = 1)
         dec   a                      ;decrease counter (with was 'the amount of bits to shift')
         jr   nz,largeSpriteLoop3     ;if the counter is not 0 loop back
largeSpriteSkip1:
         ld   a,(hl)                  ;graphbyte in a
         xor   d                      ;xor first byte of sprite (that can be changed to 'or d' if you want a OR-routine)
         ld   (hl),a                  ;back to buffer
         inc   hl                     ;increase pointer
         ld   a,(hl)                  ;graphbyte in a
         xor   e                      ;xor with shifted sprite byte (change to 'or e' for OR-routine)
         ld   (hl),a                  ;back to buffer
         inc   ix                     ;increase sprite adress
         ex   af,af'
                                      ;exchange af with af' ( a is now the 'width' from the first line)
         dec   a                      ;decrease 'width'
         push   af                    ;push the 'width'
            ex   af,af'
                                      ;exchange back
         pop   af                     ;pop the 'width'
         jr   nz,largeSpriteLoop2     ;if a is not 0 (if a = 0 then we would be done) loop it
      pop   hl                        ;pop gbuf adress (search the last push hl!)
   pop   af                           ;pop  | to restore the real 'width'
   push   af                          ;push /
      ex   af,af'
                                      ;af' must be the original 'width' when loop 'largeSpriteLoop1'
      ld   de,$0C                     ;ld de,12
      add   hl,de                     ;next line
      djnz   largeSpriteLoop1         ;if not b = 0 loop (b = height of sprite)
   pop   af                           ;pop because we dont want a stack problem :)
   ret                                ;return

Example

   ;...
   ld   a,8   ;y
   ld   l,a
   ld   a,16  ;x
   ld   b,8   ;height
   ld   c,2   ;width in bytes
   ld   ix,sprite
   call largesprite
   call fastcopy
   ;...
sprite:
   .db %11111111,%11111111
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %11111111,%11111111

Macro

This macro can be used with Tasm or Spasm.

#define lsprite(lsprite_down,lsprite_right,lsprite_size_down,lsprite_size_right,lsprite_address) ld a,lsprite_down \ ld l,a \ ld a,lsprite_right \ ld b,lsprite_size_down \ ld c,lsprite_size_right \ ld ix,lsprite_address \ call largesprite

[→How do you do a line break in this Wiki?]

The above example would be:

   ;...
   lsprite(16, 8, 8, 2,sprite)
   call fastcopy
   ;...
sprite:
   .db %11111111,%11111111
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %10000000,%00000001
   .db %11111111,%11111111

Differences between the 83+ and the 83 in Largesprite

You need to define 'gbuf' which is $9340 on the Ti83+ and $8E29 on the Ti83 before you include the largesprite routine.

#ifdef TI83P
#define gbuf $9340
#else
#define gbuf $8E29
#endif


Version without shadow registers

by Tijl Coosemans, made for Venus. Compatible with ION's routine.

iLargeSprite
	ld	h,0
	ld	d,h
	ld	e,l
	add	hl,de
	add	hl,de
	add	hl,hl
	add	hl,hl
	ld	e,a
	srl	e
	srl	e
	srl	e
	add	hl,de
	ld	de,screenBuf
	add	hl,de
	and	7
	ld	e,a
iLargeSpriteLoop1
	push	bc
	push	hl
	ld	b,c
iLargeSpriteLoop2
	ld	c,(ix)
	ld	d,0
	inc	ix
	ld	a,e
	or	a
	jr	z,iLargeSprite1
iLargeSpriteLoop3
	srl	c
	rr	d
	dec	a
	jr	nz,iLargeSpriteLoop3
iLargeSprite1
	ld	a,c
	xor	(hl)
	ld	(hl),a
	inc	hl
	ld	a,d
	xor	(hl)
	ld	(hl),a
	djnz	iLargeSpriteLoop2
	pop	hl
	ld	c,12
	add	hl,bc
	pop	bc
	djnz	iLargeSpriteLoop1
	ret