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