Prev: A2F8 Up: Map Next: A57E
A303: Draw Sprites
Used by the routines at DrawObject and UpdateStarLayer.
Erases one sprite and draws another without flicker. It works out the rectangle that holds both sprites (which is at most seven bytes wide), copies that part of the screen to a buffer at F800, erases the first sprite from the buffer, draws the second sprite into the buffer and then copies the buffer back to the screen. The sprites are set up by SelectEraseSprite, SelectDrawSprite and ClipSecondSprite or ClipFirstSprite. A sprite with no rows is not drawn.
Input
B High byte of the shift table for the second sprite
B' High byte of the shift table for the first sprite
DE Address of the data of the second sprite
DE' Address of the data of the first sprite
IX Routine that draws the second sprite
IY Routine that erases the first sprite
DrawSprites A303 PUSH DE Save the address of the data of the second sprite.
A304 PUSH BC Stash BC on the stack.
A305 LD HL,($5C28) Fetch the widths of the two sprites in bytes.
A308 LD ($A2F8),HL Keep a copy of the widths.
A30B ADD HL,HL Multiply the widths by eight to get them in pixels.
A30C ADD HL,HL
A30D ADD HL,HL
A30E LD ($5C28),HL Store the widths in pixels.
A311 LD A,($A1D7) Fetch the number of rows of the first sprite.
A314 AND A Test it.
A315 JR NZ,DrawSprites_SecondPosition Jump to DrawSprites_SecondPosition if the sprite has rows.
A317 LD HL,($A1D5) Copy the position of the second sprite...
A31A LD ($A1D3),HL ...to the first sprite.
DrawSprites_SecondPosition A31D LD A,($A1D8) Fetch the number of rows of the second sprite.
A320 AND A Test it.
A321 JR NZ,DrawSprites_Wrapped Jump to DrawSprites_Wrapped if the sprite has rows.
A323 LD HL,($A1D3) Copy the position of the first sprite...
A326 LD ($A1D5),HL ...to the second sprite.
DrawSprites_Wrapped A329 LD A,($A2FA) Fetch the flag for sprites beyond the right of the playfield.
A32C AND A Test it.
A32D JR Z,DrawSprites_Top Jump to DrawSprites_Top if it is not set.
A32F LD A,($A1D3) Fetch the horizontal position of the first sprite.
A332 SUB $60 Take off 60.
A334 LD ($A1D3),A Store it.
A337 LD A,($A1D5) Fetch the horizontal position of the second sprite.
A33A SUB $60 Take off 60.
A33C LD ($A1D5),A Store it.
Find the bottom of the rectangle, which is the larger of the vertical positions of the two sprites (the rows of a sprite go up from its position).
DrawSprites_Top A33F LD A,($A1D4) Fetch the vertical position of the first sprite.
A342 LD E,A Store it in E.
A343 LD A,($A1D6) Fetch the vertical position of the second sprite.
A346 LD D,A Store it in D.
A347 CP E Is the second sprite higher than the first?
A348 JR NC,DrawSprites_TopFound Jump to DrawSprites_TopFound if so.
A34A LD A,E Use the position of the first sprite.
DrawSprites_TopFound A34B LD ($5C2D),A Store the bottom of the rectangle.
A34E LD H,A Keep it in H.
Find the top of the rectangle, which gives the number of rows.
A34F LD BC,($A1D7) Fetch the number of rows of each sprite.
A353 LD A,E Take the number of rows from the position of the first sprite...
A354 SUB C
A355 LD E,A
A356 LD A,D ...and from the position of the second sprite.
A357 SUB B
A358 CP E Is the top of the second sprite higher than that of the first?
A359 JR NC,DrawSprites_BottomFound Jump to DrawSprites_BottomFound if not.
A35B LD E,A Use the top of the second sprite.
DrawSprites_BottomFound A35C LD A,H Take the top from the bottom...
A35D SUB E
A35E INC A ...and add one to get the number of rows of the rectangle.
A35F LD ($CE37),A Store it.
Find the left of the rectangle, which is the lowest of the horizontal positions of the two sprites, rounded down to a whole byte.
A362 LD A,($A1D3) Fetch the horizontal position of the first sprite.
A365 LD E,A Store it in E.
A366 LD A,($A1D5) Fetch the horizontal position of the second sprite.
A369 LD D,A Store it in D.
A36A CP E Is the second sprite further to the left?
A36B JR C,DrawSprites_Left Jump to DrawSprites_Left if so.
A36D LD A,E Use the position of the first sprite.
DrawSprites_Left A36E AND %11111000 Round down to a whole byte.
A370 LD ($5C2C),A Store the left of the rectangle.
A373 LD L,A Keep it in L.
Find the right of the rectangle, which gives the number of bytes in each row.
A374 LD BC,($5C28) Fetch the widths of the sprites in pixels.
A378 LD A,E Work out the right of the first sprite relative to the left.
A379 SUB L
A37A ADD A,C
A37B LD E,A
A37C LD A,D Work out the right of the second sprite relative to the left.
A37D SUB L
A37E ADD A,B
A37F CP E Is the second sprite further to the right?
A380 JR NC,DrawSprites_Right Jump to DrawSprites_Right if so.
A382 LD A,E Use the right of the first sprite.
DrawSprites_Right A383 ADD A,$06 Add six to allow for shifting.
A385 LD C,A Store it in C.
A386 SRL A Divide it by eight to get the number of bytes in a row.
A388 SRL A
A38A SRL A
A38C LD ($CE35),A Store it.
A38F LD A,($A2FA) Fetch the flag for sprites beyond the right of the playfield.
A392 AND A Test it.
A393 JP Z,DrawSprites_Copy Jump to DrawSprites_Copy if it is not set.
The sprites reach beyond the right of the playfield. Work out how many bytes of each row are beyond A8, then copy that many from the left of the playfield at the end of each row of the buffer.
A396 LD A,L Fetch the left of the rectangle.
A397 ADD A,C Add the width in pixels.
A398 SUB $A8 Take off A8.
A39A SRL A Divide it by eight.
A39C SRL A
A39E SRL A
A3A0 LD B,A Store the number of bytes beyond in B.
A3A1 LD A,($CE35) Fetch the number of bytes in a row.
A3A4 SUB B Subtract the bytes beyond.
A3A5 LD ($A531),A Store it as the amount to skip at A530.
A3A8 LD ($A3DC),A Store it as the amount to skip at A3DB.
A3AB LD E,A Start the copy that far along each row of the buffer.
A3AC LD A,B Fetch the number of bytes beyond.
A3AD XOR %00000111 Flip the bottom three bits.
A3AF DEC A Turn it into a distance to jump into a run of copies...
A3B0 ADD A,A
A3B1 ADD A,$03
A3B3 LD ($A520),A ...and store it for the copy back to the screen at DrawSprites_ClipJump.
A3B6 LD ($A3CB),A Store it for the copy to the buffer at DrawSprites_WrapJump.
A3B9 LD C,$FF Set the counter that is used by LDI.
A3BB LD D,$F8 Use the buffer.
A3BD LD L,$08 Use the left of the playfield.
A3BF CALL GetScreenAddress Find the screen address.
A3C2 LD ($CE43),HL Keep the screen address of the left of the playfield.
A3C5 LD A,($CE37) Fetch the number of rows.
A3C8 LD B,A Store it in B.
DrawSprites_WrapRow A3C9 PUSH HL Save the screen address of the row.
DrawSprites_WrapJump A3CA DJNZ DrawSprites_WrapJump Jump into the run of copies.
A3CC JP DrawSprites_Erase Jump to DrawSprites_Erase when the rows are done.
DrawSprites_WrapCopy A3CF LDI Copy a byte of the row to the buffer.
A3D1 LDI Copy a byte of the row to the buffer.
A3D3 LDI Copy a byte of the row to the buffer.
A3D5 LDI Copy a byte of the row to the buffer.
A3D7 LDI Copy a byte of the row to the buffer.
A3D9 LDI Copy a byte of the row to the buffer.
A3DB LD A,$00 Move to the start of the next row of the buffer.
A3DD ADD A,E Add the amount to skip.
A3DE LD E,A Store it in E.
A3DF POP HL Restore the screen address of the row.
A3E0 DEC H Move up a pixel row.
A3E1 LD A,H Fetch the high byte.
A3E2 INC A Add one.
A3E3 AND %00000111 Keep the bits that give the pixel row.
A3E5 JP NZ,DrawSprites_WrapRow Jump to DrawSprites_WrapRow if the row is still in the same cell.
A3E8 LD A,L Fetch the low byte.
A3E9 SUB $20 Move up a row of cells.
A3EB LD L,A Store it.
A3EC JP C,DrawSprites_WrapRow Jump to DrawSprites_WrapRow if that crossed a third of the screen.
A3EF LD A,H Fetch the high byte.
A3F0 ADD A,$08 Add eight to correct it.
A3F2 LD H,A Store it.
A3F3 JP DrawSprites_WrapRow Jump to DrawSprites_WrapRow.
Copy the rectangle from the screen to the buffer.
DrawSprites_Copy A3F6 LD DE,$F800 Use the buffer.
A3F9 LD A,($CE35) Fetch the number of bytes in a row.
A3FC XOR %00000111 Flip the bottom three bits.
A3FE ADD A,A Turn it into a distance to jump into a run of copies...
A3FF ADD A,$03
A401 LD ($A553),A ...and store it for the copy back to the screen at DrawSprites_CopyAllJump.
A404 LD ($A415),A Store it for the copy to the buffer at DrawSprites_CopyJump.
A407 CALL GetScreenAddress Find the screen address of the bottom left of the rectangle.
A40A LD ($CE43),HL Keep it.
A40D LD C,$FF Set the counter that is used by LDI.
A40F LD A,($CE37) Fetch the number of rows.
A412 LD B,A Store it in B.
DrawSprites_CopyRow A413 PUSH HL Save the screen address of the row.
DrawSprites_CopyJump A414 DJNZ DrawSprites_CopyRow Jump into the run of copies.
A416 JP DrawSprites_Erase Jump to DrawSprites_Erase when the rows are done.
DrawSprites_CopyBytes A419 LDI Copy a byte of the row to the buffer.
A41B LDI Copy a byte of the row to the buffer.
A41D LDI Copy a byte of the row to the buffer.
A41F LDI Copy a byte of the row to the buffer.
A421 LDI Copy a byte of the row to the buffer.
A423 LDI Copy a byte of the row to the buffer.
A425 LDI Copy a byte of the row to the buffer.
A427 POP HL Restore the screen address of the row.
A428 DEC H Move up a pixel row.
A429 LD A,H Fetch the high byte.
A42A INC A Add one.
A42B AND %00000111 Keep the bits that give the pixel row.
A42D JP NZ,DrawSprites_CopyRow Jump to DrawSprites_CopyRow if the row is still in the same cell.
A430 LD A,L Fetch the low byte.
A431 SUB $20 Move up a row of cells.
A433 LD L,A Store it.
A434 JP C,DrawSprites_CopyRow Jump to DrawSprites_CopyRow if that crossed a third of the screen.
A437 LD A,H Fetch the high byte.
A438 ADD A,$08 Add eight to correct it.
A43A LD H,A Store it.
A43B JP DrawSprites_CopyRow Jump to DrawSprites_CopyRow.
Erase the first sprite from the buffer.
DrawSprites_Erase A43E POP HL Discard the extra screen address.
A43F POP BC Bring BC back off the stack.
A440 POP DE Restore the address of the data of the second sprite.
A441 EXX Switch to the registers of the first sprite.
A442 LD A,($A1D7) Fetch the number of rows of the first sprite.
A445 AND A Test it.
A446 JP Z,DrawSprites_Draw Jump to DrawSprites_Draw if there is nothing to erase.
A449 LD HL,($A1D3) Fetch the position of the first sprite.
A44C CALL FindBufferAddress Find its address in the buffer.
A44F LD A,($A2F8) Fetch the width of the first sprite.
A452 LD C,A Store it in C.
A453 LD A,B Fetch the high byte of the shift table.
A454 CP $F8 Jump to DrawSprites_EraseSkip if the sprite is not aligned to a byte.
A456 JR NZ,DrawSprites_EraseSkip
A458 DEC C An aligned sprite is one byte narrower.
DrawSprites_EraseSkip A459 LD A,($CE35) Fetch the number of bytes in a row.
A45C SUB C Take off the width to get the amount to skip to the next row.
A45D LD ($A6D6),A Store it at A6D5 for aligned sprites...
A460 LD ($A728),A ...and at A727 for shifted sprites.
A463 LD A,($A1D7) Fetch the number of rows of the first sprite.
A466 EX AF,AF' Store it.
A467 JP (IY) Erase the sprite.
This entry point is used by the routines at EraseAlignedRowInBuffer and EraseShiftedRowInBuffer.
Draw the second sprite into the buffer.
DrawSprites_Draw A469 EXX Switch to the registers of the second sprite (the main set).
A46A LD A,($A1D8) Fetch the number of rows of the second sprite.
A46D AND A Test it.
A46E JP Z,DrawSprites_CopyBack Jump to DrawSprites_CopyBack if there is nothing to draw.
A471 LD HL,($A1D5) Fetch the position of the second sprite.
A474 CALL FindBufferAddress Find its address in the buffer.
A477 LD A,($A2F9) Fetch the width of the second sprite.
A47A LD C,A Store it in C.
A47B LD A,B Fetch the high byte of the shift table.
A47C CP $F8 Jump to DrawSprites_DrawSkip if the sprite is not aligned to a byte.
A47E JR NZ,DrawSprites_DrawSkip
A480 DEC C An aligned sprite is one byte narrower.
DrawSprites_DrawSkip A481 LD A,($CE35) Fetch the number of bytes in a row.
A484 SUB C Take off the width to get the amount to skip to the next row.
A485 LD ($A751),A Store it at A750 for aligned sprites...
A488 LD ($A799),A ...and at A798 for shifted sprites.
A48B DEC A Take one off.
A48C LD ($A4C5),A Store it at A4C4.
A48F LD ($BA8D),HL Keep the address of the sprite in the buffer.
A492 LD A,($A1D8) Fetch the number of rows of the second sprite.
A495 EX AF,AF' Store it.
A496 JP (IX) Draw the sprite.
This entry point is used by the routines at DrawAlignedRowInBuffer and DrawShiftedRowInBuffer.
When the value at A302 is not zero, dissolve the second sprite in the buffer by clearing some of its pixels using one of the masks at A2FB.
DrawSprites_Dissolve A498 LD A,($A302) Fetch the dissolve value.
A49B AND A Test it.
A49C JP Z,DrawSprites_CopyBack Jump to DrawSprites_CopyBack if the sprite is not dissolving.
A49F AND %00001111 Keep the bottom four bits.
A4A1 LD HL,$A2FA Use the masks.
A4A4 CALL AddAToHL Add the dissolve value.
A4A7 LD D,(HL) Fetch the mask.
A4A8 LD HL,($BA8D) Fetch the address of the sprite in the buffer.
A4AB LD A,($A2F9) Fetch the width of the second sprite.
A4AE LD E,A Store it in E.
A4AF LD A,($A1D8) Fetch the number of rows of the second sprite.
A4B2 LD C,A Store it in C.
A4B3 LD A,($A1D5) Fetch the horizontal position of the second sprite.
A4B6 AND %00000111 Keep the bottom three bits.
A4B8 JR Z,DrawSprites_DissolveRow Jump to DrawSprites_DissolveRow if the sprite is aligned to a byte.
A4BA INC E A shifted sprite is one byte wider.
DrawSprites_DissolveRow A4BB LD B,E Set the number of bytes in a row.
DrawSprites_DissolveByte A4BC LD A,D Fetch the mask.
A4BD AND (HL) Apply it to the byte.
A4BE LD (HL),A Store the byte.
A4BF RRC D Rotate the mask.
A4C1 INC L Move on to the next byte.
A4C2 DJNZ DrawSprites_DissolveByte Loop back to DrawSprites_DissolveByte for each byte of the row.
A4C4 LD A,$00 Move on to the start of the next row of the buffer.
A4C6 ADD A,L Add the amount to skip.
A4C7 LD L,A Store it in L.
A4C8 DEC C Count the rows.
A4C9 JR NZ,DrawSprites_DissolveRow Loop back to DrawSprites_DissolveRow for each row.
Copy the buffer back to the screen, without going past the left or right edge of the playfield.
DrawSprites_CopyBack A4CB LD DE,($CE43) Fetch the screen address of the bottom left of the rectangle.
A4CF LD HL,$F800 Use the buffer.
A4D2 LD A,($A2FA) Fetch the flag for sprites beyond the right of the playfield.
A4D5 AND A Test it.
A4D6 JR Z,DrawSprites_Clip Jump to DrawSprites_Clip if it is not set.
A4D8 LD A,($A531) Fetch the amount to skip.
A4DB LD L,A Start the copy that far along each row of the buffer.
A4DC JP DrawSprites_ClipRows Jump to DrawSprites_ClipRows.
DrawSprites_Clip A4DF LD A,($CE35) Fetch the number of bytes in a row.
A4E2 ADD A,A Multiply it by eight to get the width in pixels.
A4E3 ADD A,A
A4E4 ADD A,A
A4E5 LD B,A Store it in B.
A4E6 LD A,($5C2C) Fetch the left of the rectangle.
A4E9 AND A Test it.
A4EA JR Z,DrawSprites_ClipLeft Jump to DrawSprites_ClipLeft if it is zero.
A4EC LD C,A Store the left in C.
A4ED ADD A,$17 Add 17.
A4EF ADD A,B Add the width in pixels.
A4F0 JP NC,DrawSprites_CopyAll Jump to DrawSprites_CopyAll if the rectangle ends within the screen.
A4F3 JR DrawSprites_ClipRight Jump to DrawSprites_ClipRight.
DrawSprites_ClipLeft A4F5 INC E Skip the first byte of the buffer...
A4F6 INC L ...and the first byte of the screen.
A4F7 LD A,($CE35) Fetch the number of bytes in a row.
A4FA DEC A Take one off.
A4FB JR DrawSprites_ClipSkip Jump to DrawSprites_ClipSkip.
DrawSprites_ClipRight A4FD LD A,$EE Subtract the left from EE...
A4FF SUB C ...to get the width that fits.
A500 SRL A Divide it by eight to get the number of bytes.
A502 SRL A
A504 SRL A
DrawSprites_ClipSkip A506 LD B,A Store the number of bytes to copy in B.
A507 LD A,($CE35) Fetch the number of bytes in a row.
A50A SUB B Subtract the number of bytes to copy.
A50B LD ($A531),A Store it as the amount to skip at A530.
A50E LD A,B Fetch the number of bytes to copy.
A50F XOR %00000111 Flip the bottom three bits.
A511 DEC A Work out the distance to jump into the run of copies...
A512 ADD A,A
A513 ADD A,$03
A515 LD ($A520),A ...and store it at DrawSprites_ClipJump.
DrawSprites_ClipRows A518 LD C,$FF Set the counter that is used by LDI.
A51A LD A,($CE37) Fetch the number of rows.
A51D LD B,A Store it in B.
DrawSprites_ClipRow A51E PUSH DE Save the screen address of the row.
DrawSprites_ClipJump A51F DJNZ DrawSprites_ClipRow Jump into the run of copies.
A521 JP DrawSprites_Done Jump to DrawSprites_Done when the rows are done.
DrawSprites_ClipBytes A524 LDI Copy a byte of the row to the screen.
A526 LDI Copy a byte of the row to the screen.
A528 LDI Copy a byte of the row to the screen.
A52A LDI Copy a byte of the row to the screen.
A52C LDI Copy a byte of the row to the screen.
A52E LDI Copy a byte of the row to the screen.
A530 LD A,$00 Move to the start of the next row of the buffer.
A532 ADD A,L Add the amount to skip.
A533 LD L,A Store it in L.
A534 POP DE Restore the screen address of the row.
A535 DEC D Move up a pixel row.
A536 LD A,D Fetch the high byte.
A537 INC A Add one.
A538 AND %00000111 Keep the bits that give the pixel row.
A53A JP NZ,DrawSprites_ClipRow Jump to DrawSprites_ClipRow if the row is still in the same cell.
A53D LD A,E Fetch the low byte.
A53E SUB $20 Move up a row of cells.
A540 LD E,A Store it.
A541 JP C,DrawSprites_ClipRow Jump to DrawSprites_ClipRow if that crossed a third of the screen.
A544 LD A,D Fetch the high byte.
A545 ADD A,$08 Add eight to correct it.
A547 LD D,A Store it.
A548 JP DrawSprites_ClipRow Jump to DrawSprites_ClipRow.
DrawSprites_CopyAll A54B LD A,($CE37) Fetch the number of rows.
A54E LD B,A Store it in B.
A54F LD C,$FF Set the counter that is used by LDI.
DrawSprites_CopyAllRow A551 PUSH DE Save the screen address of the row.
DrawSprites_CopyAllJump A552 DJNZ DrawSprites_CopyAllJump Jump into the run of copies.
A554 JP DrawSprites_Done Jump to DrawSprites_Done when the rows are done.
DrawSprites_CopyAllBytes A557 LDI Copy a byte of the row to the screen.
A559 LDI Copy a byte of the row to the screen.
A55B LDI Copy a byte of the row to the screen.
A55D LDI Copy a byte of the row to the screen.
A55F LDI Copy a byte of the row to the screen.
A561 LDI Copy a byte of the row to the screen.
A563 LDI Copy a byte of the row to the screen.
A565 POP DE Restore the screen address of the row.
A566 DEC D Move up a pixel row.
A567 LD A,D Fetch the high byte.
A568 INC A Add one.
A569 AND %00000111 Keep the bits that give the pixel row.
A56B JP NZ,DrawSprites_CopyAllRow Jump to DrawSprites_CopyAllRow if the row is still in the same cell.
A56E LD A,E Fetch the low byte.
A56F SUB $20 Move up a row of cells.
A571 LD E,A Store it.
A572 JP C,DrawSprites_CopyAllRow Jump to DrawSprites_CopyAllRow if that crossed a third of the screen.
A575 LD A,D Fetch the high byte.
A576 ADD A,$08 Add eight to correct it.
A578 LD D,A Store it.
A579 JP DrawSprites_CopyAllRow Jump to DrawSprites_CopyAllRow.
DrawSprites_Done A57C POP DE Discard the extra screen address.
A57D RET Return.
Prev: A2F8 Up: Map Next: A57E