A86: Re: 3 *5 PutSprite routine
[Prev][Next][Index][Thread]
A86: Re: 3 *5 PutSprite routine
I suggest a FindAddress (not FindPixel) routine like the one below. A
findpixel routine isn't exactly what you need for a putsprite, since you
need to find the number of times to shift the sprite, not the pixel offset
in the byte (unless it's a Mardell style putsprite). The routine below is
fairly fast, returns the offset in the buffer and the buffer doesn't have to
be aligned.
As for a putsprite, if you are doing sprites with width's that are not
multiples of eight, the easiest way is to treat them as if they are a
multiple of eight. This will waste more space, but will usually result in a
more efficient sprite routine. If you don't like my method, I encourage you
to read scabby's sources, as he's the only programmer I know who's made big
games with odd sprite sizes. Reading any of his code (even and especially
Repton) will give great insight on optimization and coding practices.
A non-masked, non-grayscale putsprite should be pretty easy to write,
especially after you have a FindAddress routine. We can walk through the
steps of writing the routine. First thing to note is that I haven't tested
it, and thus it might not work. Second, is that in real code, I would
prefix all labels with PutSprite. For example, Loop would be PutSpriteLoop.
This will allow you to have many routines in a large project and will allow
you to easily share code files between projects without having name
conflicts. I used short names to save space and make the code more
readable.
This routine is a good example of using self-modifying code to use only
normal registers without pushing/popping anything:
; in: hl = sprite, bc = x,y location
PutSprite:
ex de,hl ; save the sprite pointer in DE
call FindAddress ; calculate the offset in the buffer and
; the byte offset in the video buffer
ld bc,$fc00 ; normal video memory starts at the address $fc00
add hl,bc ; add the start and the offset to get the
; starting byte of the sprite in the video buffer
ld (_@ShiftC),a ; use self-modifying code to load the number
; of times to shift into the OR operation below
; instead of <OR 0>, it will <OR A>, but with the
; value that A is currently
; using self-modifying code like this can save you
; from pushing/popping registers in a critical loop,
; and effectively create registers from nowhere
ld a,ROWS ; load the height of the sprite, which is how many times
; that the routine needs to loop
Loop:
ld (_@LoopC),a ; update the counter below, with self-modifying code
sub a ; clear the accumlator and flags, since A - A = 0
ld b,(de) ; load the byte from the sprite
inc de ; move the pointer to the next byte of the sprite
ld c,a ; clear the low byte of BC
; BC will be used as a 16-bit register as the sprite is
; shifted to fit into two bytes in video memory
_@ShiftC =$+1 ; a label will point to the start of an instruction
; the $ symbol is a constant used by the assembler to
; represent the current value of the program counter, PC
; by setting ShiftC to PC plus one, ShiftC will point to
; second byte of the OR instruction, the data byte
; the data byte, which is the zero below, will be loaded
; above by the number of times to shift
; by specifying a label's address instead of adding to
; a label's value, you will prevent mistakes will coding
; prefixing labels that are selfmodified with _@ will
; identify them from normal labels
or 0 ; the zero will be the number of times to shift
; since A is zero, it is the same as a load, but
; it will also update the flags with the value of A
jr z,DoneShift ; if the shift counter is zero at the beginning, then
; the loop can be skipped entirely
Shift:
srl b ; shift the high byte to the right into the carry flag,
; and set the high bit to zero
rr c ; shift from the carry flag into the low byte
dec a ; decrease the shift counter and update flags
jr nz,Shift ; if there are more bits to shift, continue loop
Done:
ld (hl),b ; load the high byte into video memory
inc hl ; move to the next byte in video memory
ld (hl),c ; load the low byte into video memory
ld bc,15 ; the row is 15 bytes ahead in the video buffer
add hl,bc ; advance the video memory pointer to the next row
LoopC =$+1 ; point to the data byte of the load
ld a,0 ; load the row counter value, set at the top of the loop
dec a ; decrease the row/byte counter
jr nz,Loop ; if there are more rows to draw, then loop
ret ; all done!
; in: bc = x,y location
; out: hl = offset of byte, a = offset in video byte
FindAddress:
ld a,c ; get the y coord
add a,a ; multiply by 2
add a,a ; again by 4
ld l,a ; save as low byte
ld h,0 ; clear high byte
add hl,hl ; multiply by 8
add hl,hl ; and again by 16
ld a,b ; now get the x coord
and %11111000 ; clear lower 3 bits
rra ; divide by 2
rra ; this time by 4
rra ; and finally by 8
or l ; combine with low byte
ld l,a ; save it
ld a,b ; get x coord again
and %00000111 ; clear all but last 3 bits
ret ; return to caller
> Hi, I need a putsprite routine that puts 3wide by 5high aligned sprites.
I
> am using Find_Pixel by Clem.
>
> I don't think that this would be too hard, but I don't know how to do it.
References: