Difference between revisions of "Z80 Routines:Graphic:largesprite"
From WikiTI
m |
Guillaumeh (Talk | contribs) (+ version that doesn't use shadow registers) |
||
Line 131: | Line 131: | ||
#define gbuf $8E29 | #define gbuf $8E29 | ||
#endif</nowiki> | #endif</nowiki> | ||
+ | |||
+ | |||
+ | == Version without shadow registers == | ||
+ | |||
+ | by Tijl Coosemans, made for Venus. Compatible with ION's routine. | ||
+ | |||
+ | <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> |
Revision as of 03:07, 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.
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
Contents
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