base:20-pixel_sprite_interleave
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revisionLast revisionBoth sides next revision | ||
base:20-pixel_sprite_interleave [2020-10-15 14:15] – created raistlin | base:20-pixel_sprite_interleave [2020-10-15 15:02] – raistlin | ||
---|---|---|---|
Line 4: | Line 4: | ||
Original idea and help from Christopher Jam for 20-pixel interleave technique | Original idea and help from Christopher Jam for 20-pixel interleave technique | ||
- | ===== Intro ===== | + | === Intro === |
- | When using large arrays of sprites, eg. an 8x10 array, it can be tricky to do this without having gaps or problems. Annoyingly, C64 sprites are 21 pixels tall - so it's not possible to have this array without at least one row of sprites being around a bad line - where there simply aren't enough cycles to update all the sprite values. | + | When using large arrays of sprites, eg. an 8x10 array, it can be tricky to do this without having gaps or glitches. Annoyingly, C64 sprites are 21 pixels tall - so it's not possible to have this array without at least one row of sprites being around a bad line - where there simply aren't enough cycles to update all the sprite values. |
- | This becomes especially problematic when you're dealing with varying D011 - eg. in the intro sequence of "The Dive" where we have bitmap upscroller behind a sprite array. | + | This becomes especially problematic when you're dealing with varying D011 - eg. in the intro sequence of "The Dive" where we have a bitmap upscroller behind a sprite array. |
There are a few techniques available to help with these sprite arrays - and each has their pros/cons that I'll go into later. | There are a few techniques available to help with these sprite arrays - and each has their pros/cons that I'll go into later. | ||
Line 18: | Line 18: | ||
- | ===== 20-pixel Interleave ===== | + | ===== 20-pixel |
- | Here we update all of the sprite values around each 20th line of the screen - just after the 19th line out of every 20 - and we " | + | Here we update all of the sprite values around each 20th line of the screen - just after the 19th line out of every 20 - and we " |
To understand this technique, you need to understand what changing the sprite value means if you're part way through a sprite. If you change from sprite 64 to 72, for example, on the 6th line of a sprite, the sprite will continue to be drawn from the 6th line - but it will now be the 6th line of sprite 72 rather than 64. | To understand this technique, you need to understand what changing the sprite value means if you're part way through a sprite. If you change from sprite 64 to 72, for example, on the 6th line of a sprite, the sprite will continue to be drawn from the 6th line - but it will now be the 6th line of sprite 72 rather than 64. | ||
- | The 20px technique, then, fixes the " | + | The 20px technique, then, fixes the " |
- | When the technique is working, roughly, you should have:- | + | For a typical screen, therefore, you should have:- |
Y=[ 0, 20] .. lines 0-19 of row 0 and line 20 of either row 0 or row 1 | Y=[ 0, 20] .. lines 0-19 of row 0 and line 20 of either row 0 or row 1 | ||
Y=[ 20, 40] .. lines 20 and 0-18 of row 1 and line 19 of either row 1 or row 2 | Y=[ 20, 40] .. lines 20 and 0-18 of row 1 and line 19 of either row 1 or row 2 | ||
Line 33: | Line 33: | ||
Y=[180,200] .. lines 12-20 and 0-11 of row 9 | Y=[180,200] .. lines 12-20 and 0-11 of row 9 | ||
- | So we have several | + | As you can see, we have several |
+ | * line 20 of row 0 into line 20 of row 1 | ||
+ | * line 19 of row 1 into line 19 of row 2 | ||
+ | * ... | ||
+ | * line 12 of row 8 into line 12 of row 9 | ||
+ | We also need to " | ||
- | Given all that, you still need to update all 8 sprite values in as few cycles as possible. And you need to start the update from as close as possible to the right position. | + | |
+ | === Updating Sprite Values === | ||
+ | |||
+ | Often, especially when dealing with a vertically scrolling screen, or the addition of opening the side borders or other effects, you still need to update all 8 sprite values in as few cycles as possible. | ||
For this, it's worth knowing about a neat little trick. | For this, it's worth knowing about a neat little trick. | ||
- | The most basic way to update the sprite values would of course be: | + | The most basic and obvious |
< | < | ||
Line 47: | Line 55: | ||
inx | inx | ||
stx ScreenAddr + $3f8 + 1 | stx ScreenAddr + $3f8 + 1 | ||
- | | + | |
+ | stx ScreenAddr + $3f8 + 2 | ||
+ | inx | ||
+ | stx ScreenAddr + $3f8 + 3 | ||
+ | inx | ||
+ | stx ScreenAddr + $3f8 + 4 | ||
+ | inx | ||
+ | stx ScreenAddr + $3f8 + 5 | ||
+ | inx | ||
+ | stx ScreenAddr + $3f8 + 6 | ||
inx | inx | ||
stx ScreenAddr + $3f8 + 7 | stx ScreenAddr + $3f8 + 7 | ||
</ | </ | ||
- | What matters to us here is the cycle count between our first write to the sprite values and our last. So that's 7x2 + 7x4 = 42. To reduce this, we can use the illegal opcode, SAX:- | + | What matters to us here is the cycle count between our first write to the sprite values and our last. So that's 7x2 + 7x4 = 42 cycles. To reduce this, we can use the illegal opcode, SAX:- |
< | < | ||
LDA #64 + 4 | LDA #64 + 4 | ||
- | LDX #fb | + | LDX #$fb |
- | SAX ScreenAddr + $3f8 + 0; <-- SAX will write A&X .. ie. 64 in this case (we mask out bit 2) | + | SAX ScreenAddr + $3f8 + 0; <-- SAX will write "A & X" |
STA ScreenAddr + $3f8 + 4 | STA ScreenAddr + $3f8 + 4 | ||
INX | INX | ||
SAX ScreenAddr + $3f8 + 1 | SAX ScreenAddr + $3f8 + 1 | ||
- | | + | |
+ | INX | ||
+ | SAX ScreenAddr + $3f8 + 2 | ||
+ | STA ScreenAddr + $3f8 + 6 | ||
INX | INX | ||
SAX ScreenAddr + $3f8 + 3 | SAX ScreenAddr + $3f8 + 3 | ||
Line 70: | Line 90: | ||
=== Pros/Cons === | === Pros/Cons === | ||
- | |||
- | As we don't need 2 screen buffers, this means:- | ||
- | * PRO: we save screen buffer memory; | ||
- | * PRO: in many cases we can simplify screen drawing code. | ||
Compared to the alternative 16-pixel interleave technique (updating $D018):- | Compared to the alternative 16-pixel interleave technique (updating $D018):- | ||
- | * PRO: we only " | + | |
- | * CON: we need to duplicate some data - which can have a performance impact if the sprites are being drawn to in realtime | + | * PRO: in many cases we can simplify screen drawing code; |
- | + | | |
- | + | * PRO: to cover the screen height we only need 10 rows (80 sprites) instead of 13 (104); | |
+ | * CON: we need to duplicate some data - which can have a performance impact if the sprites are being drawn to in realtime. | ||