Advertisement
paul_nicholls

c64-multiplexer2.c

Jun 27th, 2023 (edited)
834
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.12 KB | None | 0 0
  1. // A flexible sprite multiplexer routine for 32 sprites.
  2. // Usage:
  3. // - Once:
  4. // - plexInit(screen): Initialize the data structures and set the screen address
  5. // Each frame:
  6. // - Set x-pos, y-pos and pointer in PLEX_XPOS[id], PLEX_YPOS[id], PLEX_PTR[id]
  7. // - set enabled, color and multicolor in PLEX_ENABLED[id], PLEX_COLOR[id], PLEX_MULTICOLOR[id]
  8. // - plexSort() Sorts the sprites according to y-positions and prepares for showing them. This uses an insertion sort that is quite fast when the relative order of the sprites does not change very much.
  9. // - plexShowSprite() Shows the next sprite by copying values from PLEX_XXX[] to an actual sprite. Actual sprites are used round-robin. This should be called once for each of the 24 virtual sprites.
  10. // - plexFreeNextYpos() Returns the Y-position where the next sprite is available to be shown (ie. the next pos where the next sprite is no longer in use showing something else).
  11. // - plexShowNextYpos() Returns the Y-position of the next sprite to show.
  12. //
  13. // In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 32 sprites have been shown.
  14. // TODO: Let the caller specify the number of sprites to use (or add PLEX_ENABLE[PLEX_COUNT])
  15.  
  16. #include <c64-multiplexer2.h>
  17. #include <c64.h>
  18.  
  19. // The number of sprites in the multiplexer
  20. const char PLEX_COUNT = 32;
  21.  
  22. //--------------------------------------------    
  23. //--------------------------------------------    
  24. // new sprite stuff
  25. // The sprite enable for each multiplexer sprite; 0 = 0ff, 1 = on
  26. char PLEX_ENABLED[PLEX_COUNT];
  27.  
  28. // The sprite color for each multiplexer sprite
  29. char PLEX_COLOR[PLEX_COUNT];
  30.  
  31. // The sprite multicolor enable for each multiplexer sprite; 0 = hi-res, 1 = multicolor
  32. char PLEX_MULTICOLOR[PLEX_COUNT];
  33. //--------------------------------------------    
  34. //--------------------------------------------    
  35.  
  36. // The x-positions of the multiplexer sprites (0x000-0x1ff)
  37. unsigned int PLEX_XPOS[PLEX_COUNT];
  38.  
  39. // The y-positions of the multiplexer sprites.
  40. char PLEX_YPOS[PLEX_COUNT];
  41.  
  42. // The sprite pointers for the multiplexed sprites
  43. char PLEX_PTR[PLEX_COUNT];
  44.  
  45. // The address of the sprite pointers on the current screen (screen+0x3f8).
  46. char* volatile PLEX_SCREEN_PTR = (char*)0x400+0x3f8;
  47.  
  48. // Indexes of the plex-sprites sorted by sprite y-position. Each call to plexSort() will fix the sorting if changes to the Y-positions have ruined it.
  49. char PLEX_SORTED_IDX[PLEX_COUNT];
  50.  
  51. // Variables controlling the showing of sprites
  52.  
  53. // The index in the PLEX tables of the next sprite to show
  54. volatile char plex_show_idx=0;
  55. // The index the next sprite to use for showing (sprites are used round-robin)
  56. volatile char plex_sprite_idx=0;
  57. // The MSB bit of the next sprite to use for showing
  58. volatile char plex_sprite_msb=1;
  59.  
  60. // Initialize the multiplexer data structures
  61. void plexInit(char* screen) {
  62.     plexSetScreen(screen);
  63.     for(char i: 0..PLEX_COUNT-1) {
  64.         PLEX_SORTED_IDX[i] = i;
  65.     }
  66. }
  67.  
  68. // Set the address of the current screen used for setting sprite pointers (at screen+0x3f8)
  69. inline void plexSetScreen(char* screen) {
  70.     PLEX_SCREEN_PTR = screen+0x3f8;
  71. }
  72.  
  73. // Ensure that the indices in PLEX_SORTED_IDX is sorted based on the y-positions in PLEX_YPOS
  74. // Assumes that the positions are nearly sorted already (as each sprite just moves a bit)
  75. // Uses an insertion sort:
  76. // 1. Moves a marker (m) from the start to end of the array. Every time the marker moves forward all elements before the marker are sorted correctly.
  77. // 2a. If the next element after the marker is larger that the current element
  78. //     the marker can be moved forwards (as the sorting is correct).
  79. // 2b. If the next element after the marker is smaller than the current element:
  80. //     elements before the marker are shifted right one at a time until encountering one smaller than the current one.
  81. //      It is then inserted at the spot. Now the marker can move forward.
  82. void plexSort() {
  83.     for(char m: 0..PLEX_COUNT-2) {
  84.         char nxt_idx = PLEX_SORTED_IDX[m+1];
  85.         char nxt_y = PLEX_YPOS[nxt_idx];
  86.         if(nxt_y<PLEX_YPOS[PLEX_SORTED_IDX[m]]) {
  87.             // Shift values until we encounter a value smaller than nxt_y
  88.             char s = m;
  89.             do {
  90.                 PLEX_SORTED_IDX[s+1] = PLEX_SORTED_IDX[s];
  91.                 s--;
  92.             } while((s!=0xff) && (nxt_y<PLEX_YPOS[PLEX_SORTED_IDX[s]]));
  93.             // store the mark at the found position
  94.             s++;
  95.             PLEX_SORTED_IDX[s] = nxt_idx;
  96.         }
  97.     }
  98.     // Prepare for showing the sprites
  99.     plex_show_idx = 0;
  100.     plex_sprite_idx = 0;
  101.     plex_sprite_msb = 1;
  102.     plexFreePrepare();
  103. }
  104.  
  105. // Show the next sprite.
  106. // plexSort() prepares showing the sprites
  107. void plexShowSprite() {
  108.     char plex_sprite_idx2 = plex_sprite_idx*2;
  109.     char ypos = PLEX_YPOS[PLEX_SORTED_IDX[plex_show_idx]];
  110.     SPRITES_YPOS[plex_sprite_idx2] = ypos;
  111.     plexFreeAdd(ypos);
  112.     PLEX_SCREEN_PTR[plex_sprite_idx] = PLEX_PTR[PLEX_SORTED_IDX[plex_show_idx]];
  113.     char xpos_idx = PLEX_SORTED_IDX[plex_show_idx];
  114.     SPRITES_XPOS[plex_sprite_idx2] = (char)PLEX_XPOS[xpos_idx];
  115.  
  116.     //--------------------------------------------    
  117.     //--------------------------------------------    
  118.     // new sprite stuff
  119.     SPRITES_COLOR[plex_sprite_idx] = (char)PLEX_COLOR[xpos_idx];
  120.  
  121.     if(PLEX_MULTICOLOR[xpos_idx]!=0) {
  122.       VICII->SPRITES_MC |= plex_sprite_msb;
  123.     } else {
  124.       VICII->SPRITES_MC &= (0xff^plex_sprite_msb);
  125.     }
  126.  
  127.     if(PLEX_ENABLED[xpos_idx]!=0) {
  128.       VICII->SPRITES_ENABLE |= plex_sprite_msb;
  129.     } else {
  130.       VICII->SPRITES_ENABLE &= (0xff^plex_sprite_msb);
  131.     }
  132.     //--------------------------------------------    
  133.     //--------------------------------------------    
  134.  
  135.     if(BYTE1(PLEX_XPOS[xpos_idx])!=0) {
  136.         *SPRITES_XMSB |= plex_sprite_msb;
  137.     } else {
  138.         *SPRITES_XMSB &= (0xff^plex_sprite_msb);
  139.     }
  140.     plex_sprite_idx = (plex_sprite_idx+1)&7;
  141.     plex_show_idx++;
  142.     plex_sprite_msb <<=1;
  143.     if(plex_sprite_msb==0) {
  144.         plex_sprite_msb = 1;
  145.     }
  146. }
  147.  
  148. // Get the y-position of the next sprite to show
  149. inline char plexShowNextYpos() {
  150.     return PLEX_YPOS[PLEX_SORTED_IDX[plex_show_idx]];
  151. }
  152.  
  153. // Contains the Y-position where each sprite is free again. PLEX_FREE_YPOS[s] holds the Y-position where sprite s is free to use again.
  154. char PLEX_FREE_YPOS[8];
  155.  
  156. // The index of the sprite that is free next. Since sprites are used round-robin this moves forward each time a sprite is shown.
  157. volatile char plex_free_next = 0;
  158.  
  159. // Prepare for a new frame. Initialize free to zero for all sprites.
  160. inline void plexFreePrepare() {
  161.     for( char s: 0..7) {
  162.         PLEX_FREE_YPOS[s] = 0;
  163.     }
  164.     plex_free_next = 0;
  165. }
  166.  
  167. // Get the Y-position where the next sprite to be shown is free to use.
  168. inline char plexFreeNextYpos() {
  169.     return PLEX_FREE_YPOS[plex_free_next];
  170. }
  171.  
  172. // Update the data structure to reflect that a sprite has been shown. This sprite will be free again after 21 lines.
  173. inline void plexFreeAdd(char ypos) {
  174.     PLEX_FREE_YPOS[plex_free_next] =  ypos+22;
  175.     plex_free_next = (plex_free_next+1)&7;
  176. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement