Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Looks up a vertical scroll value and sets some related variables.
  3.  */
  4. #undef LOOKUP_YSCROLL_REC
  5. #define LOOKUP_YSCROLL_REC(rec_no)                                      \
  6.         do {                                                            \
  7.                 yscroll_amount = get_word(vsram + rec_no * 2) & 0x7ff;  \
  8.                                                                         \
  9.                 /* interlace ? */                                       \
  10.                 if (reg[12] & 2)                                        \
  11.                         yscroll_amount >>= 1;                           \
  12.                                                                         \
  13.                 /* Offset for the line */                               \
  14.                 yscroll_amount += line;                                 \
  15.                                                                         \
  16.                 yoff = ((yscroll_amount >> 3) & (ysize - 1));           \
  17.                 tile_line = (tiles + ((xsize * yoff) & 0x1fff));        \
  18.                 scan = (yscroll_amount & 7);                            \
  19.         }                                                               \
  20.         while (0)
  21.  
  22. {
  23.         int xsize, ysize;
  24.         int x, scan = 0, w, xstart;
  25.         static int sizes[4] = { 32, 64, 64, 128 };
  26.         unsigned which;
  27.         unsigned char *where, *hscroll_rec_ptr, *tiles, *tile_line = NULL;
  28.         int xoff, yoff, xoff_mask;
  29.         int hscroll_amount, yscroll_amount = 0;
  30.         uint8_t two_cell_vscroll = 0;
  31.  
  32.         /*
  33.          * when VSCR bit is set in register 11, this is 'per 2-cell'
  34.          * vertical scrolling as opposed to full screen vscrolling.
  35.          */
  36.         two_cell_vscroll = ((reg[11] >> 2) & 0x1);
  37.  
  38. #if PLANE == 0
  39.         // Plane 0 is only where the window isn't
  40.         // This should make Herzog Zwei split screen work perfectly, and clean
  41.         // up those little glitches on Sonic 3's level select.
  42.         if (reg[18] & 0x80) {
  43.                 // Window goes down, plane 0 goes up! :)
  44.                 if ((line >> 3) >= (reg[18] & 0x1f))
  45.                         return;
  46.         }
  47.         else {
  48.                 // Window goes up, plane 0 goes down
  49.                 if ((line >> 3) < (reg[18] & 0x1f))
  50.                         return;
  51.         }
  52. #endif
  53.  
  54.         /*
  55.          * Get the vertical/horizontal scroll plane sizes
  56.          *
  57.          * 0b00: 32 cell
  58.          * 0b01: 64 cell
  59.          * 0b10: prohibited, but unlicensed games use this
  60.          *       turns out to be 64.
  61.          * 0b11: 128 cell
  62.          */
  63.         xsize = (sizes[(reg[16] & 3)] << 1);
  64.         ysize = sizes[((reg[16] >> 4) & 3)];
  65.  
  66.         /*
  67.          * Here we compute pointer to the beginning of the  hscroll table.
  68.          * The base address of the table is stored in reg[13] << 10.
  69.          */
  70. #if PLANE == 0
  71.         hscroll_rec_ptr = (vram + ((reg[13] << 10) & 0xfc00));
  72.         tiles = (vram + (reg[2] << 10));
  73. #else // PLANE == 1
  74.         hscroll_rec_ptr = (vram + ((reg[13] << 10) & 0xfc00) + 2);
  75.         tiles = (vram + (reg[4] << 13));
  76. #endif
  77.  
  78.         // Wide or narrow?
  79.         if (reg[12] & 1) {
  80.                 w = 40;
  81.                 xstart = -8;
  82.         }
  83.         else {
  84.                 w = 32;
  85.                 xstart = 24;
  86.         }
  87.  
  88.         /*
  89.          * Lookup the horizontal offset.
  90.          * See Charles MacDonald's genvdp.txt for explanation.
  91.          */
  92.         switch (reg[11] & 3) {
  93.         case 0:
  94.                 // full screen
  95.                 // NOP - pointer in the right place
  96.                 break;
  97.         case 1:
  98.                 // invalid, but populous uses it
  99.                 hscroll_rec_ptr += ((line & 7) << 2);
  100.                 break;
  101.         case 2:
  102.                 // per tile
  103.                 hscroll_rec_ptr += ((line & ~7) << 2);
  104.                 break;
  105.         case 3:
  106.                 // per line
  107.                 hscroll_rec_ptr += (line << 2);
  108.                 break;
  109.         }
  110.  
  111.         hscroll_amount = get_word(hscroll_rec_ptr);
  112.         xoff_mask = xsize - 1;
  113.         xoff = ((-(hscroll_amount>>3) - 1)<<1) & xoff_mask;
  114.         where = dest + (xstart + (hscroll_amount & 7)) * (int) Bpp;
  115.  
  116.         /*
  117.          * If this is not column vscroll mode, we look up the
  118.          * whole screen vertical scroll value once and once only.
  119.          */
  120.         if (two_cell_vscroll == 0)
  121.                 LOOKUP_YSCROLL_REC(PLANE);
  122.  
  123.         /*
  124.          * Loop cells, we draw 2 more cells than expected (-1 and w) because
  125.          * previously off-screen cells can be horizontally scrolled on-screen.
  126.          */
  127.         for (x = -1; (x <= w); x++) {
  128.                 /*
  129.                  * If we are in 2-cell vscroll mode then lookup the amount by
  130.                  * which we should scroll this tile.
  131.                  *
  132.                  * If we are not in 2-cell vscroll then we looked up the value
  133.                  * for the whole screen vscroll earlier.
  134.                  *
  135.                  * We lookup vscroll values on even x values and this is the
  136.                  * vscroll value for the next two cells. Note that cell -1 is
  137.                  * a special case as we never looked up the vscroll value for
  138.                  * cell -2.
  139.                  */
  140.                 if ((two_cell_vscroll) && ((x % 2 == 0) || (x == -1))) {
  141.  
  142.                         /*
  143.                          * Note that the underflow and overflow of the table
  144.                          * for cell -1 and cell w is intentional.
  145.                          *
  146.                          * http://gendev.spritesmind.net/forum/viewtopic.php?t=737&postdays=0&postorder=asc&start=30
  147.                          */
  148.                         uint8_t cell_index = (uint8_t) x % w;
  149.                         int vscroll_rec_no = 2 * (cell_index / 2);
  150.  
  151.                         /*
  152.                          * The records alternate, PLANE A, PLANE B, PLANE A,
  153.                          * ...
  154.                          */
  155. #if PLANE == 1
  156.                         vscroll_rec_no++;
  157. #endif
  158.                         LOOKUP_YSCROLL_REC(vscroll_rec_no);
  159.                 }
  160.  
  161. #if PLANE == 0
  162.                 if (reg[17] & 0x80) {
  163.                         // Don't draw where the window will be
  164.                         if (x >= ((reg[17] & 0x1f) << 1))
  165.                                 goto skip;
  166.                 }
  167.                 else {
  168.                         // + 1 so scroll layers in Sonic look right
  169.                         if ((x + 1) < ((reg[17] & 0x1f) << 1))
  170.                                 goto skip;
  171.                 }
  172. #endif
  173.                 which = get_word(tile_line + xoff);
  174.  
  175. #if (FRONT == 0) && (PLANE == 1)
  176.                 draw_tile_solid(which, scan, where);
  177. #elif FRONT == 1
  178.                 if (which >> 15)
  179.                         draw_tile(which, scan, where);
  180. #else
  181.                 if (!(which >> 15))
  182.                         draw_tile(which, scan, where);
  183. #endif
  184.  
  185. #if PLANE == 0
  186.         skip:
  187. #endif
  188.                 where += Bpp_times8;
  189.                 xoff = ((xoff + 2) & xoff_mask);
  190.         }
  191. }
  192.