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

From WikiTI
Jump to: navigation, search
m
m (delete)
Line 1: Line 1:
[[Category:Z80 Routines:Graphic|LargeSprite]][[Category:Z80 Routines|LargeSprite]]
 
The '''Largesprite''' routine is used to copy the contents of a variable sized sprite to the Graph Buffer.
 
  
== Code ==
 
Here is Joe Wingbermuehle's version, which is the one used in ION. Gbuf must be defined before its use.
 
 
<nowiki>
 
;=======================
 
;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</nowiki>
 
 
== Example ==
 
<nowiki>
 
  ;...
 
  ld  l,8  ;y
 
  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</nowiki>
 
 
 
== Version without shadow registers ==
 
 
by Tijl Coosemans, made for Venus. Compatible with ION's routine. screenBuf must be defined.
 
 
<nowiki>
 
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
 
</nowiki>
 
 
 
 
== Version with Clipping ==
 
This is a version that supports clipping the large sprite.  It's considerable larger and requires Self modifying code.  The SMC can be removed without to much difficulty. It has different inputs than ION's.
 
 
<nowiki>;--------------------------------
 
;Clip Big Sprite
 
;by James Montelongo
 
;MAX SIZE: 64x64
 
;ix - Sprite
 
;b  - height
 
;c  - width in bytes
 
;d  - x
 
;e  - y
 
 
ClipBigSprite:
 
; Early out, Check if its even remotely on screen
 
ld a,e
 
cp 64
 
ret p
 
add a,b
 
ret m
 
ret z
 
ld a,d
 
cp 96
 
ret p
 
ld a,c
 
add a,a
 
add a,a
 
add a,a
 
add a,d
 
ret m
 
ret z
 
 
ld a,e
 
or a
 
jp p,Check_clip_bottom
 
neg
 
push de
 
ld hl,0
 
ld d,l
 
ld e,a
 
bit 2,c
 
jr z,$+2+1
 
add hl,de
 
add hl,hl
 
bit 1,c
 
jr z,$+2+1
 
add hl,de
 
add hl,hl
 
bit 0,c
 
jr z,$+2+1
 
add hl,de
 
pop de
 
ex de,hl
 
add ix,de ;Here you can save the top offset
 
ex de,hl
 
ld e,0
 
neg
 
add a,b
 
ld b,a
 
Check_clip_bottom:
 
 
ld a,e
 
add a,b
 
sub 64
 
jp m,Check_clip_Left
 
neg
 
add a,b
 
ld b,a
 
Check_clip_Left:
 
; at this point you may want to save b
 
xor a
 
ld (bigskip),a
 
ld a,Clipleftsize
 
ld (Do_Clipleft),a
 
ld a,d
 
or a
 
jp p,Check_clip_right
 
cpl
 
and $F8
 
rra
 
rra
 
rra
 
ex de,hl ;save the clipped left offset
 
ld e,a
 
ld d,0
 
add ix,de
 
ld (bigskip),a
 
ex de,hl
 
inc a
 
neg
 
add a,c
 
ld c,a
 
xor a
 
ld (Do_Clipleft),a
 
ld a,d
 
and $07
 
ld d,a
 
Check_clip_right:
 
 
ld a,Cliprightsize
 
ld (Do_Clipright),a
 
ld a,c
 
add a,a
 
add a,a
 
add a,a
 
add a,d
 
sub 96
 
jp m,Check_clip_middle
 
and $F8
 
rra
 
rra
 
rra
 
ld l,a
 
ld a,(bigskip)
 
add a,l
 
inc a
 
ld (bigskip),a
 
neg
 
add a,c
 
ld c,a
 
xor a
 
ld (Do_Clipright),a
 
Check_clip_middle:
 
; This is where C should be saved.
 
xor a
 
ld (Do_ClipMiddle),a
 
ld a,c
 
or a
 
jp nz,dontskipmiddle
 
ld a,ClipMiddlesize
 
ld (Do_ClipMiddle),a
 
dontskipmiddle:
 
ld l,e
 
ld a,d
 
ld h,0
 
ld d,h
 
add hl,hl
 
add hl,de
 
add hl,hl
 
add hl,hl
 
ld e,a
 
and $07
 
xor 7
 
ld (BigRot1),a
 
ld (BigRot2),a
 
ld (BigRot3),a
 
add a,a
 
ld (clipbigrot1),a
 
ld a,$ff
 
clipbigrot1 = $+1
 
jr $
 
srl a
 
srl a
 
srl a
 
srl a
 
srl a
 
srl a
 
srl a
 
srl e
 
srl e
 
srl e
 
add hl,de
 
ld de,gbuf
 
add hl,de
 
; This is where gbuf offset should be saved.
 
ld d,a
 
cpl
 
ld e,a
 
;masks should be saved to
 
BigSpriteRow:
 
push bc
 
push hl
 
ld b,c
 
Do_Clipleft = $+1
 
jr Clipleft
 
ld a,(ix)
 
inc ix
 
BigRot1 = $+1
 
jr $
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
BigMask0:
 
and e
 
or (hl)
 
ld (hl),a
 
Clipleft:
 
Clipleftsize = Clipleft-(Do_Clipleft+1)
 
 
Do_ClipMiddle = $+1
 
jr $+2
 
BigSpriteloop:
 
ld a,(ix)
 
inc ix
 
BigRot2 = $+1
 
jr $
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
ld c,a
 
BigMask1:
 
and d
 
or (hl)
 
ld (hl),a
 
inc hl
 
ld a,c
 
BigMask2:
 
and e
 
or (hl)
 
ld (hl),a
 
djnz BigSpriteloop
 
ClipMiddle:
 
ClipMiddlesize = ClipMiddle-(Do_ClipMiddle+1)
 
 
Do_ClipRight = $+1
 
jr ClipRight
 
ld a,(ix)
 
BigRot3 = $+1
 
jr $
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
rrca
 
BigMask3:
 
and d
 
or (hl)
 
ld (hl),a
 
ClipRight:
 
Cliprightsize = ClipRight-(Do_ClipRight+1)
 
pop hl
 
 
ld bc,12 ;width of the screen
 
add hl,bc
 
 
bigskip = $+1
 
ld bc,0
 
add ix,bc
 
pop bc
 
djnz BigSpriteRow
 
ret
 
</nowiki>
 

Revision as of 01:12, 25 June 2010