Created: 13th November 1999
Last Modified: 27th November 1999
This page will explain the basics behind findpixel and non-aligned sprite routines.
The idea behind a findpixel routine is that you give it a pair of coordinates and it returns a pointer to the relevant section in the video memory. The fastest (but not smallest) routine is the following:
FindPixel: ld a,c ;a contains y coordinate add a,a ;a contains y * 2 add a,a ;a contains y * 4 ld l,a ;l contains y * 4 ld h,$3f ;h contains ($fc >> 2) ld a,b ;a contains x coordinate rra ;a contains x / 2 add hl,hl ;hl = hl * 2 rra ;a contains x / 4; carry flag -> msb add hl,hl ;hl = hl * 4 rra ;a contains x / 8; carry flag -> msb add a,l ;a contains x offset ld l,a ;l = l + a ld a,b ;a contains x coordinate and %00000111 ;a contains (x and %00000111) ret ;we're finished
It takes the following inputs:
And gives the following outputs:
Now for a program that uses FindPixel. It's so simple I won't even put the source in a file - copy and paste it if you want to see it work.
.org $d748 ld bc,$1234 ;x = $12, y = $34 call FindPixel ;get real memory ld b,(hl) ;get current value or a ;or it with new value ld (hl),a ;and put it back onto the screen ret ;we're finished FindPixel: --FindPixel Routine goes here - left out to save space.-- .end
Now that we've got a findpixel routine we can write a non-aligned sprite routine. The following routine was written by me - it's a downgrade from the one I use in xenophon (coming soon, plug plug). The original uses undocumented opcodes (it won't run on certain emulators as officially some of the instructions I use don't exist). The following uses self-writing code, but only a bit...
PutSprite: ld a,c ;a contains y coordinate add a,a ;a contains y * 2 add a,a ;a contains y * 4 ld l,a ;l contains y * 4 ld h,$3f ;h contains $fc / 4 ld a,b ;a contains x coordinate rra ;a contains x / 2 add hl,hl ;hl = hl * 2 rra ;a contains x / 4; carry flag -> msb add hl,hl ;hl = hl * 4 rra ;a contains x / 8; carry flag -> msb add a,l ;a contains x offset ld l,a ;l = l + a ld a,b ;a contains x coordinate and %00000111 ;a contains (x and %00000111) ld c,a ;c contains bit number ld (swmemplus-1),a ;ld a,(ix + 0) becomes ld a,(ix + a) ld ix,MaskTable ;ix points to MaskTable ld a,(ix + 0) ;ld a,(ix + a) swmemplus: ld ix,TempMem ;ix points to TempMem ld (ix + 0),a ;(ix + 0) contains bitmask ld (ix + 1),c ;(ix + 1) contains bit number SpriteStart: ld b,8 ;Sprite is 8 rows high SpriteLoop: push bc ;Save loop counter ld a,(de) ;a contains current row of sprite ld b,(ix + 1) ;b contains bit number jr z,NoRotate ;if b = 0 then don't rotate sprite RotateLoop: rrca ;rotate sprite right djnz RotateLoop ;until b = 0 NoRotate: ld c,a ;c contains rotated sprite or (hl) ;a contains sprite + current value and (ix + 0) ;a contains new value ld (hl),a ;place new value to screen inc hl ;move to next byte ld a,(ix + 0) ;a contains bitmask cpl ;invert value of a and c ;a = a and rotated sprite or (hl) ;a contains new value ld (hl),a ;put new value into memory ld bc,15 ;bc = Screen Width - 1 add hl,bc ;hl points to next row inc de ;de points to next row of sprite pop bc ;restore loop counter djnz SpriteLoop ;loop if not done ret ;return MaskTable: ;table for converting bit to bitmask .db %11111111,%01111111,%00111111,%00011111 .db %00001111,%00000111,%00000011,%00000001 TempMem: ;two bytes for temp storage .db 0, 0
This takes the following inputs:
It modifies af, bc, de, hl and ix. Note that this routine does not clip sprites, so using it too close to the edge will produce strange results. Also, this routine has been modified from the one used in xenophon, so it will OR the sprite to the screen rather than just draw it on.