Prev: 45716 Up: Map Next: 46163
45756: Draw Sprite
Used by the routine at DrawList.
Draws one sprite into the off-screen play window buffer. The sprite is found using the type in the draw list entry, as an index into the table of sprite pointers at SpritePointers. A sprite has a two byte header (the width in bytes plus flags, then the height in pixel rows) followed by its pixel rows, each made of pairs of bytes, one pair for each byte of width. The first byte of each pair is ORed onto the buffer and the second is then XORed onto the result. The rows are stored from the bottom of the sprite to the top. A sprite whose width and height are both zero is blank and is not drawn. Bit 7 of the type in the draw list entry means the sprite is drawn facing the other way. The flag in bit 7 of the sprite's own header records which way its data is currently stored, and if the two differ then the sprite's data is flipped in place first, using FlipSprite. The x position is a pixel position in the buffer, where 16 is the left edge of the play window. The y position is the height of the bottom of the sprite above the bottom of the buffer, so it increases up the screen: 48 is the bottom of the play window and 160 is the top. Sprites that overlap the top or bottom are clipped, and 16 pixels either side are available for sprites that overhang the left or right edge. If the sprite is not on a byte boundary then each pair of bytes is shifted right by the number of pixels using the tables built by BuildShiftTables, and an extra byte is written for each row. The drawing is done by unrolled loops at DrawSprite_Shifted (shifted) and DrawSprite_Unrolled (byte aligned), which are entered part way along according to the width of the sprite so that exactly the right number of bytes are drawn on each row. The sprite data is read by pointing the stack pointer at it and using POP.
Before After
draw-sprite-before draw-sprite-after
Input
IX Draw list entry: type, x position, y position
Find the sprite for this entry.
DrawSprite 45756 LD A,(IX+0) Fetch the type.
45759 ADD A,A Double it, discarding the "face the other way" bit, to give the offset into the table of pointers.
45760 LD L,A Add the offset to the address of the table of sprite pointers at SpritePointers.
45761 LD H,0
45763 LD BC,24739
45766 ADD HL,BC
45767 LD E,(HL) Fetch the address of the sprite into DE.
45768 INC HL
45769 LD D,(HL)
45770 LD A,(DE) Fetch the width byte of the header into C.
45771 LD C,A
45772 INC DE Fetch the height from the header.
45773 LD A,(DE)
45774 OR C Combine them and keep bits 0-5.
45775 AND 63
45777 RET Z Return if both the width and the height are zero, as the sprite is blank.
45778 DEC DE Point DE at the start of the header again.
45779 CALL FlipSprite Flip the sprite data if it is stored facing the wrong way, using FlipSprite.
Find which page of the shift tables to use, which depends on the x position within a byte.
45782 LD A,(IX+1) Fetch the x position.
45785 DEC A Take one off, shift the result left by one (multiplying by two) and keep only the three bits of the shift, so that this is the shift amount multiplied by two.
45786 RLCA
45787 AND 14
45789 OR 224 Add the base of the shift tables to give the page number, in H.
45791 LD H,A
45792 LD A,(IX+1) Fetch the x position again.
45795 AND 7 Test whether it is a multiple of 8.
45797 LD A,(DE) Fetch the width byte of the header.
45798 JP Z,DrawSprite_Aligned Jump to DrawSprite_Aligned to draw the sprite without shifting if the x position is exactly on a byte boundary.
The sprite needs shifting, so it will cover one more byte on each row than its width.
45801 INC A Add one to the width in bytes.
45802 AND 15
45804 LD (38433),A Store it as the number of bytes written to the buffer for each row.
45807 LD C,A Take a copy of it.
45808 ADD A,23 Add 23 to give the amount to subtract to get from the end of one row of the buffer to the start of the row above, since each row is 24 bytes long.
45810 LD (45989),A Write that as the number to subtract in the SUB instruction at 45988.
45813 LD A,C Fetch the width back, plus one.
45814 DEC A Take one off to get the width.
45815 INC DE Point DE at the height.
45816 NEG Negate the width and keep the bottom two bits, so that this is the number of unused copies of the unrolled loop out of the four available.
45818 AND 3
45820 ADD A,A Multiply by 14, the length of one copy of the unrolled loop.
45821 LD B,A
45822 ADD A,A
45823 ADD A,B
45824 ADD A,A
45825 ADD A,B
45826 LD B,H Hold the shift table page in B.
45827 LD HL,45931 Point HL at DrawSprite_Shifted.
45830 CALL AddAToHL Add the offset using AddAToHL, to skip the copies that are not needed.
45833 LD (45929),HL Write the address into the jump at DrawSprite_Shifted_Jump, so that it enters the loop at the right place.
45836 LD A,(DE) Fetch the height of the sprite.
45837 LD (38434),A Store it as the number of rows still to draw.
45840 LD H,B Put the page number back into H.
45841 LD C,(IX+1) Fetch the x position into C.
45844 LD B,(IX+2) Fetch the y position into B.
Clip the bottom of the sprite, if it is below the bottom of the play window.
45847 LD A,B Is the bottom of the sprite on or above the bottom of the play window (48)?
45848 CP 48
45850 JR NC,DrawSprite_Shifted_Address Jump to DrawSprite_Shifted_Address if so.
45852 LD L,A Keep the y position.
45853 LD A,(DE) Fetch the height of the sprite.
45854 ADD A,L Add the y position to get the top of the sprite.
45855 CP 48 Is the top of the sprite below the bottom of the play window?
45857 RET C Return if it is, as the sprite is not visible at all.
45858 LD A,48 Work out how many rows of the sprite are below the play window.
45860 SUB L Subtract the y position from the bottom of the play window.
45861 LD L,A Keep that number of rows.
45862 LD A,(DE) Fetch the height of the sprite.
45863 SUB L Take away the number of rows that are cut off.
45864 RET Z Return if nothing is left.
45865 LD (38434),A Store the number of rows that are left to be drawn.
45868 PUSH HL Save the number of rows that are cut off.
45869 LD A,(38433) Fetch the number of bytes written for each row.
45872 DEC A Take one off to get the width in bytes.
45873 LD B,A Use it as a counter.
45874 XOR A Start the total at zero, and clear the high byte of HL.
45875 LD H,A
DrawSprite_Shifted_Multiply 45876 ADD A,L Add the number of rows that were cut off to the total, once for each byte of the width, to multiply them.
45877 DJNZ DrawSprite_Shifted_Multiply
45879 LD L,A Keep the size of the hidden rows.
45880 ADD HL,HL Double it, as each byte of the width has a pair of bytes of data.
45881 ADD HL,DE Add the address of the sprite to give the address of the first visible row of data.
45882 EX DE,HL Keep the address of the first visible row.
45883 POP HL Restore HL.
45884 LD B,48 Start drawing from the bottom of the play window.
Find the address in the buffer and point the stack pointer at the sprite data.
DrawSprite_Shifted_Address 45886 CALL GetBufferAddress Find the address in the buffer of the first byte to draw, using GetBufferAddress.
45889 LD (38435),SP Save the stack pointer.
45893 EX DE,HL Point the stack pointer at the sprite, so that POP fetches the data.
45894 LD SP,HL
45895 EX DE,HL
45896 INC SP Take it past the height byte, to the first pair of data bytes.
Clip the top of the sprite, if it is above the top of the play window.
45897 LD A,(IX+2) Fetch the y position.
45900 CP 160 Jump to DrawSprite_Done to finish if it is, as the sprite is not visible.
45902 JP NC,DrawSprite_Done
45905 LD L,A Keep the y position.
45906 LD A,(38434) Fetch the number of rows to draw.
45909 ADD A,L Add the y position to get the top of the sprite.
45910 SUB 160 Subtract the top of the play window.
45912 JR C,DrawSprite_Shifted_Rows Jump if the sprite does not reach above the top of the play window.
45914 LD L,A Keep the number of rows that are cut off.
45915 LD A,(DE) Take the cut off rows away from the number of rows to draw.
45916 SUB L
45917 LD (38434),A
DrawSprite_Shifted_Rows 45920 LD A,(38434) Fetch the number of rows to be drawn.
45923 EXX Switch to the shadow registers, and keep the number of rows to draw in B'.
45924 LD B,A
DrawSprite_Shifted_Row 45925 EXX Switch back to the main registers.
45926 POP DE Fetch the first pair of data bytes into DE.
45927 LD A,(BC) Fetch the first byte of the buffer to be changed.
DrawSprite_Shifted_Jump 45928 JP DrawSprite_Shifted_Jump Jump into the unrolled loop.
The unrolled loop that draws one row of a sprite that is not on a byte boundary. BC points at the buffer, DE holds the current pair of data bytes (OR byte in E and XOR byte in D) and H holds the shift table page. Each pair of bytes is split by the shift table into a left part that is merged into the buffer byte already in A and a right part that is merged into the next buffer byte.
DrawSprite_Shifted 45931 LD L,E Merge the left part of the shifted pair into the buffer byte already in A: OR on the shifted OR byte and XOR on the shifted XOR byte. Store the result and move on to the next buffer byte, and the right half of the shift table.
45932 OR (HL)
45933 LD L,D
45934 XOR (HL)
45935 LD (BC),A
45936 INC BC
45937 INC H
45938 LD L,E Merge the right part of the shifted pair into the next buffer byte and leave it in A, as the next pair also overlaps it. Go back to the left half of the table and fetch the next pair of data bytes.
45939 LD A,(BC)
45940 OR (HL)
45941 LD L,D
45942 XOR (HL)
45943 DEC H
45944 POP DE
45945 LD L,E Merge the left part of the second pair and store it.
45946 OR (HL)
45947 LD L,D
45948 XOR (HL)
45949 LD (BC),A
45950 INC BC
45951 INC H
45952 LD L,E Merge the right part of the second pair and fetch the third.
45953 LD A,(BC)
45954 OR (HL)
45955 LD L,D
45956 XOR (HL)
45957 DEC H
45958 POP DE
45959 LD L,E Merge the left part of the third pair and store it.
45960 OR (HL)
45961 LD L,D
45962 XOR (HL)
45963 LD (BC),A
45964 INC BC
45965 INC H
45966 LD L,E Merge the right part of the third pair and fetch the fourth.
45967 LD A,(BC)
45968 OR (HL)
45969 LD L,D
45970 XOR (HL)
45971 DEC H
45972 POP DE
45973 LD L,E Merge the left part of the fourth pair and store it.
45974 OR (HL)
45975 LD L,D
45976 XOR (HL)
45977 LD (BC),A
45978 INC BC
45979 INC H
45980 LD L,E Merge the right part of the fourth pair.
45981 LD A,(BC)
45982 OR (HL)
45983 LD L,D
45984 XOR (HL)
45985 DEC H
45986 LD (BC),A Store the last buffer byte of the row.
Move up to the start of the previous row of the buffer. The number to subtract is written by 45810 for each sprite.
45987 LD A,C Subtract the number of bytes to step back (the operand of this instruction is modified) from the low byte of the buffer address.
45988 SUB 0
45990 LD C,A
45991 JP NC,DrawSprite_Shifted_Next Take a carry from the high byte if there was a borrow.
45994 DEC B
DrawSprite_Shifted_Next 45995 EXX Switch to the shadow registers, where B' holds the number of rows left to draw.
45996 DJNZ DrawSprite_Shifted_Row Loop back until every row of the sprite has been drawn.
DrawSprite_Done 45998 LD SP,(38435) Restore the stack pointer.
46002 RET Return.
The sprite is on a byte boundary, so no shifting is needed and each pair of bytes is combined with just one byte of the buffer.
DrawSprite_Aligned 46003 AND 15 Keep the width of the sprite in bytes.
46005 LD (38433),A Store it as the number of bytes written to the buffer for each row.
46008 LD C,A Take a copy of it.
46009 ADD A,23 Add 23 to give the amount to subtract to get back to the start of the row above, once the last byte of a row has been written.
46011 LD (46151),A Write that as the number to subtract in the SUB instruction at 46150.
46014 LD A,C Fetch the width back.
46015 INC DE Point DE at the height.
46016 NEG Negate the width and keep the bottom two bits, so that this is the number of unused copies of the unrolled loop out of the four available.
46018 AND 3
46020 LD C,A Keep the number of unused copies of the loop.
46021 ADD A,A Multiply by 6, the length of one copy of the unrolled loop.
46022 ADD A,C
46023 ADD A,A
46024 LD HL,46126 Point HL at DrawSprite_Unrolled.
46027 CALL AddAToHL Add the offset using AddAToHL, to skip the copies that are not needed.
46030 LD (46124),HL Write the address into the jump at DrawSprite_Aligned_Jump, so that it enters the loop at the right place.
46033 LD A,(DE) Fetch the height of the sprite.
46034 LD (38434),A Store it as the number of rows still to draw.
46037 LD C,(IX+1) Fetch the x position into C.
46040 LD B,(IX+2) Fetch the y position into B.
Clip the bottom of the sprite, as in 45847.
46043 LD A,B Is the bottom of the sprite on or above the bottom of the play window (48)?
46044 CP 48
46046 JR NC,DrawSprite_Aligned_Clip Jump to DrawSprite_Aligned_Clip if so.
46048 LD L,A Keep the y position.
46049 LD A,(DE) Fetch the height of the sprite.
46050 ADD A,L Add the y position to get the top of the sprite.
46051 CP 48 Is the top of the sprite below the bottom of the play window?
46053 RET C Return if it is, as the sprite is not visible at all.
46054 LD A,48 Work out how many rows of the sprite are below the play window.
46056 SUB L Subtract the y position from the bottom of the play window.
46057 LD L,A Keep that number of rows.
46058 LD A,(DE) Fetch the height of the sprite.
46059 SUB L Take away the number of rows that are cut off.
46060 RET Z Return if nothing is left.
46061 LD (38434),A Store the number of rows that are left to be drawn.
46064 PUSH HL Save the number of rows that are cut off.
46065 LD A,(38433) Fetch the width of the sprite in bytes.
46068 LD B,A Use it as a counter.
46069 XOR A Start the total at zero, and clear the high byte of HL.
46070 LD H,A
DrawSprite_Aligned_Multiply 46071 ADD A,L Add the number of rows that were cut off to the total, once for each byte of the width, to multiply them.
46072 DJNZ DrawSprite_Aligned_Multiply
46074 LD L,A Keep the size of the hidden rows.
46075 ADD HL,HL Double it, as each byte of the width has a pair of bytes of data.
46076 ADD HL,DE Add the address of the sprite to give the address of the first visible row of data.
46077 EX DE,HL Keep the address of the first visible row.
46078 POP HL Restore HL.
46079 LD B,48 Start drawing from the bottom of the play window.
DrawSprite_Aligned_Clip 46081 CALL GetBufferAddress Find the address in the buffer of the first byte to draw, using GetBufferAddress.
46084 LD (38435),SP Save the stack pointer.
46088 EX DE,HL Point the stack pointer at the sprite, so that POP fetches the data.
46089 LD SP,HL
46090 EX DE,HL
46091 INC SP Take it past the height byte, to the first pair of data bytes.
Clip the top of the sprite, as in 45897.
46092 LD A,(IX+2) Fetch the y position.
46095 CP 160 Jump to DrawSprite_Done to finish if it is, as the sprite is not visible.
46097 JP NC,DrawSprite_Done
46100 LD L,A Keep the y position.
46101 LD A,(38434) Fetch the number of rows to draw.
46104 ADD A,L Add the y position to get the top of the sprite.
46105 SUB 160 Subtract the top of the play window.
46107 JR C,DrawSprite_Aligned_Rows Jump if the sprite does not reach above the top of the play window.
46109 LD L,A Keep the number of rows that are cut off.
46110 LD A,(DE) Fetch the height of the sprite.
46111 SUB L Take the cut off rows away from the number of rows to draw.
46112 LD (38434),A Store the number of rows to be drawn.
DrawSprite_Aligned_Rows 46115 LD A,(38434) Fetch the number of rows to be drawn.
46118 LD H,B Move the buffer address into HL.
46119 LD L,C
46120 EXX Switch to the shadow registers, and keep the number of rows to draw in B'.
46121 LD B,A
DrawSprite_Aligned_Row 46122 EXX Switch back to the main registers.
DrawSprite_Aligned_Jump 46123 JP DrawSprite_Aligned_Jump Jump into the unrolled loop.
The unrolled loop that draws one row of a sprite on a byte boundary. HL points at the buffer and each pair of data bytes is fetched into DE: the OR byte (E) is ORed onto the buffer byte and the XOR byte (D) is XORed onto the result.
DrawSprite_Unrolled 46126 POP DE Merge the first pair of data bytes with the buffer byte and move on.
46127 LD A,E
46128 OR (HL)
46129 XOR D
46130 LD (HL),A
46131 INC HL
46132 POP DE Merge the second pair of data bytes with the buffer byte and move on.
46133 LD A,E
46134 OR (HL)
46135 XOR D
46136 LD (HL),A
46137 INC HL
46138 POP DE Merge the third pair of data bytes with the buffer byte and move on.
46139 LD A,E
46140 OR (HL)
46141 XOR D
46142 LD (HL),A
46143 INC HL
46144 POP DE Merge the fourth pair of data bytes with the buffer byte.
46145 LD A,E
46146 OR (HL)
46147 XOR D
46148 LD (HL),A
Move up to the start of the previous row of the buffer.
46149 LD A,L Subtract the number of bytes to step back (the operand of this instruction is modified) from the low byte of the buffer address.
46150 SUB 0
46152 LD L,A Keep the result.
46153 JP NC,DrawSprite_Aligned_Next Take a carry from the high byte if there was a borrow.
46156 DEC H
DrawSprite_Aligned_Next 46157 EXX Switch to the shadow registers, where B' holds the number of rows left to draw.
46158 DJNZ DrawSprite_Aligned_Row Loop back until every row of the sprite has been drawn.
46160 JP DrawSprite_Done Jump to DrawSprite_Done.
Prev: 45716 Up: Map Next: 46163