|
|
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>
| |