article about sprite output (from unpublished :)
ZXNet echo conference «code.zx»
From Alexander Kucher → To All 18 September 2000
Hello All!
=== I quote the file SPRITE.TX ===
(c) Stels
Hello to everyone who decided to look into this
section of our magazine!
This article is intended for more or less
prepared reader, although it is possible
Of course, don’t go into all the details
this matter.
It's rare that a programmer can't handle
there was no problem with outputting the sprite from the exact
down to the pixel. Moreover, if before
moving the sprite vertically is quite
easily, then with horizontal movement already
quite significant work arises -
ness. This problem can be solved without
in how many ways that depend on
specific situation.
For example, you can build in memory
eight shifted relative to each other
sprites, this method allows you to get
high sprite output speed, but
has its drawbacks. The most important thing is
that each sprite takes 8 times
more memory, and therefore it can be
use only for small quantities
sprites.
The second way is to move each
output sprite byte to the right by 0..7
positions, which takes up quite a lot
time, but it frees up more
memory.
The third way is a little way
reminiscent of the second one, but working
much faster. The disadvantage of this
way is that the withdrawal procedure itself
takes up much more space than in
the first two cases, and therefore not
It is recommended to use it if you
do not lack memory or
you don't need great speed.I will also say that this withdrawal method
sprites with minor changes
I borrowed it from the game
Vyacheslav Mednonogov "Black Raven".
Now about some restrictions:
-you cannot display sprites that go beyond
screen borders.
- because the procedure uses the stack, then
need to be specially modified
interrupt handler, or even them in general
prohibit. Otherwise the sprite
will be covered with debris.
In fact, we have to write 8
almost identical withdrawal procedures, each
of which will be displayed on the screen
sprite with relative shift
familiar places by 0..7 pixels.
First we write a procedure that prints
one vertical column of sprite with
shift 0, i.e. without shift.
Input data for all eight procedures
will be like this:
HL - Address on screen.
B - Sprite height in pixels.
SP - Address of the sprite column to be displayed,
increased by 2.
DE - The first two bytes of the sprite.
(D - sprite, E - mask).
Put0 ld a,(hl)
or e
xor d
ld(hl),a
pop de ;take the next bytes
;sprite and mask.
djnz Put0_
jp Exit ;Exit if drawn
;entire column.
Put0_ inc h ;Calculate the address
ld a,h ;next line
and 7 ;in the screen.
jp nz,Put0
ld a,l
add a,#20
ld l,a
jr c,Put0
ld a,h
sub 8
ld h,a
jr Put0The remaining seven procedures differ
from a friend only the first part, although
Of course, some will notice that the calculation
the next line address could be
formulate it as a procedure and call
via CALL, but this is essential
would reduce the speed of operation.
Now let's write the second part of the procedure,
which displays the same sprite column,
but with a shift to the right by 1 bit.
The input parameters are the same.
Put1 ld a,e
rrca ;move the mask to the right
ld c,a ;save
and #7F ;discard the bit,
;cat crawled out from the left
or(hl)
ld(hl),a
ld a,c
and #80 ;move the bit to
inc l ; familiar place to the right
or(hl)
ld(hl),a
; repeat the same operations
ld a,d ;for image
rrca
ldc,a
and #80
xor (hl)
ld(hl),a
ld a,c
and #7F
dec l
xor (hl)
ld(hl),a
pop de
djnz Put1_
jp Exit
Put1_ inc h ;Calculate the address
ld a,h ;next line
and 7 ;in the screen.
jp nz,Put1
ld a,l
add a,#20
ld l,a
jr c,Put1
ld a,h
sub 8
ld h,a
jr Put1
In the Put2 procedure we perform the same operations -
tions, but only shift it by two bits, and
we transfer these same two bits to the familiar place
more to the right.
However, it should be noted that in the procedurePut5 we shift the byte not by 5 bits,
but only 3, but to the left what will it give
same result, but it will work
faster.
In the Put6 procedure, two bits to the right,
and in the Put7 procedure by 1.
Now all that remains is to write the control
This part of the procedure.
;At the input of the procedure:
;HL-Sprite address
;DE-Coordinates on screen (Y,X)
;B-Sprite height in pixels
;C-Sprite length in familiar places
PutSpr push bc
push hl
call ScrPut
ex de,hl
pop hl
pop bc
PutSpr0 push bc
push de
call Line0
pop de
inc e
pop bc
dec c
jr nz,PutSpr0
ret
;Input: DE-Y(0..191),X(0..255)
;Output:HL-Address on screen
; Switches to the desired procedure
ScrPut call Scr
ex de,hl
ld bc,PutTable
ld h,0
ld l,a
add hl,hl
add hl,bc
ld a,(hl) ;Take the address of the procedure.
inc hl
ld h,(hl)
ld l,a
ld (Jump0+1),hl ;switch
;to the output of this procedure
ex de,hl
ret
;Table of procedures
PutTable dw Put0,Put1,Put2,Put3
dw Put4,Put5,Put6,Put7
;In.:DE-Y(0..191),X(0..255)
;Output:HL-Address on screen
; A-(0..7) how much to shift
; sprite to the right.
Scr ld a,e
and 7
push af
srl e
srl e
srl e
ld a,d
rrca
rrca
rrca
and #18ld h,a
ld a,d
and 7
add a,h
ld b,a
ld a,#40
add a,b
ld h,a
ld a,d
rla
rla
and #E0
or e
ld l,a
pop af
ret
;Draws one vertical column
;HL-address of the sprite
;DE is the output address on the screen
;B-sprite height
Line0 push bc
ld c,(hl)
inc hl
ld b,(hl)
inc hl
ld (Line1+1),hl
ld h,b
ld l,c
ex de,hl
pop bc
ld (Exit0+1),sp
Line1 ld sp,0
Jump0 jp 0 ;Jump to procedure
Exit ld hl,0
add hl,sp
dec hl
dec hl ;address of next
;sprite column
Exit0 ld sp,0 ;restore stack
ret
About the format of the sprites themselves you can
find out by carefully studying the structure
procedures.
The sprite data is located as follows:
the following sequence:
Top to bottom, left to right alternate
bytes of mask and sprite, with the first one
byte - mask.
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Organization of interrupts
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Having carefully studied the procedures, some
some of you will probably notice that the procedure
Line0 is written in a very intricate way, because
it can be simplified several times:
Line0
Line1 ld sp,0
dec sp
dec sp
pop de
Jump0 jp 0
In fact, such sophistication is neededfor the correct operation of interrupts, because
when calling an interrupt, part of the sprite
is overwritten by the return address and so that
restore the sprite, you need to have it in DE
corrupted two bytes of the sprite, which
upon completion of processing we return to
place. However, since we first established
we flush the stack, and only then read DE,
then when the interrupt arrives at this moment
there will be no corrupted data in DE.
Now I give the processing procedure
interrupts:
Inter ld (SP__+1),sp
ld sp,Stack ;Temporary stack
push af,bc,de,hl,ix,iy
exx
ex af,af'
push af,bc,de,hl
;Your handler
pop hl,de,bc,af
ex af,af'
exx
pop iy,ix
;Here we find out whether
;now the stack is on the sprite
SP__ ld hl,0
ld de,#6000 ;Lower limit
;sprites
sbc hl,de
jr c,Normal
ld hl,(SP__+1)
ld e,(hl)
inc hl
ld d,(hl)
ld (Jump+1),de
pop hl,de,bc,af
ld sp,(SP__+1)
inc sp
inc sp
push de
ei
Jump jp 0
;If the stack is below the sprites
Normal pop hl,de,bc,af
ld sp,(SP__+1)
ei
ret
It should also be noted that sprites
must be located above the border
sprites, and the stack is below this boundary.
Of course you can install your own
border value.
In the appendix you will find all the sources.
===End quote ===Best regards, Alexander September 18, 2000