User Tools

Site Tools


base:20-pixel_sprite_interleave

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Last revisionBoth sides next revision
base:20-pixel_sprite_interleave [2020-10-15 14:15] – created raistlinbase: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 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 Sprite Interleave =====
  
-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 "fix" the tearing that occurs via a data trick.+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 "fix" the glitches that occur via a data trick.
  
 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 "glitch" you would normally see from changing the sprite value "too soon" by making sure that the equivalent line of each sprite is the same.+The 20px technique, then, fixes the "glitch" you would normally see from changing the sprite value "too soon" by making sure that the equivalent line of each sprite, at the point that the sprite value is updated, is identical.
  
-When the technique is workingroughly, you should have:-+For a typical screentherefore, 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 duplicates... line 20 of row 0 should be duplicated into row 1line 19 of row 1 into row 2, etcAnd we also need to "roll" the sprite data accordingly as well.+As you can see, we have several places where the sprite data needs to be duplicated: 
 +  * 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 "roll" the sprite data for each row as well.
  
-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 way to update the sprite values would of course be something like:
  
 <code> <code>
Line 47: Line 55:
       inx       inx
       stx ScreenAddr + $3f8 + 1       stx ScreenAddr + $3f8 + 1
-      ...+      inx 
 +      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
 </code> </code>
  
-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:-
  
 <code> <code>
       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.. ie. 64 here
       STA ScreenAddr + $3f8 + 4       STA ScreenAddr + $3f8 + 4
       INX       INX
       SAX ScreenAddr + $3f8 + 1       SAX ScreenAddr + $3f8 + 1
-      ...+      STA ScreenAddr + $3f8 + 5 
 +      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 "waste" 1 pixel line of sprite data instead of 5. +  * PRO: we save screen buffer memory; 
-  * 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: we only "waste" 1 pixel line of sprite data instead of 5
- +  * 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.