Subversion Repositories Kolibri OS

Rev

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

  1. // DGen/SDL v1.16+
  2. // New raster effects engine
  3. // I'd like to thank the Mac folks for giving me a good template to work from.
  4. // This is just a cheap rehash of their code, except friendlier to other bit
  5. // depths. :) I also put in a few little optimizations, like blank checking
  6. // and especially the sprites.
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <stdint.h>
  12. #include <assert.h>
  13. #include "system.h"
  14. #include "md.h"
  15. #include "pd.h"
  16. #include "rc-vars.h"
  17.  
  18. // This is marked each time the palette is updated. Handy for the 8bpp
  19. // implementation, so we don't waste time changing the palette unnecessarily.
  20. int pal_dirty;
  21.  
  22. // Macros, to route draw_tile and draw_tile_solid to the right handler
  23. #define draw_tile(which, line, where) \
  24.         switch(Bpp)\
  25.           {\
  26.           case 1:\
  27.             draw_tile1((which),(line),(where)); break;\
  28.           case 2:\
  29.             draw_tile2((which),(line),(where)); break;\
  30.           case 3:\
  31.             draw_tile3((which),(line),(where)); break;\
  32.           case 4:\
  33.             draw_tile4((which),(line),(where)); break;\
  34.           }
  35.  
  36. #define draw_tile_solid(which, line, where) \
  37.         switch(Bpp)\
  38.           {\
  39.           case 1:\
  40.             draw_tile1_solid((which),(line),(where)); break;\
  41.           case 2:\
  42.             draw_tile2_solid((which),(line),(where)); break;\
  43.           case 3:\
  44.             draw_tile3_solid((which),(line),(where)); break;\
  45.           case 4:\
  46.             draw_tile4_solid((which),(line),(where)); break;\
  47.           }
  48.  
  49. // Silly utility function, get a big-endian word
  50. #ifdef WORDS_BIGENDIAN
  51. static inline int get_word(unsigned char *where)
  52.   { return (int)(*(unsigned short*)where); }
  53. #else
  54. static inline int get_word(unsigned char *where)
  55.   { return (where[0] << 8) | where[1]; }
  56. #endif
  57.  
  58. // Tile pixel masks
  59. #ifdef WORDS_BIGENDIAN
  60. #  define PIXEL0 (0xf0000000)
  61. #  define PIXEL1 (0x0f000000)
  62. #  define PIXEL2 (0x00f00000)
  63. #  define PIXEL3 (0x000f0000)
  64. #  define PIXEL4 (0x0000f000)
  65. #  define PIXEL5 (0x00000f00)
  66. #  define PIXEL6 (0x000000f0)
  67. #  define PIXEL7 (0x0000000f)
  68. #  define SHIFT0 (28)
  69. #  define SHIFT1 (24)
  70. #  define SHIFT2 (20)
  71. #  define SHIFT3 (16)
  72. #  define SHIFT4 (12)
  73. #  define SHIFT5 ( 8)
  74. #  define SHIFT6 ( 4)
  75. #  define SHIFT7 ( 0)
  76. #else // WORDS_BIGENDIAN
  77. #  define PIXEL0 (0x000000f0)
  78. #  define PIXEL1 (0x0000000f)
  79. #  define PIXEL2 (0x0000f000)
  80. #  define PIXEL3 (0x00000f00)
  81. #  define PIXEL4 (0x00f00000)
  82. #  define PIXEL5 (0x000f0000)
  83. #  define PIXEL6 (0xf0000000)
  84. #  define PIXEL7 (0x0f000000)
  85. #  define SHIFT0 ( 4)
  86. #  define SHIFT1 ( 0)
  87. #  define SHIFT2 (12)
  88. #  define SHIFT3 ( 8)
  89. #  define SHIFT4 (20)
  90. #  define SHIFT5 (16)
  91. #  define SHIFT6 (28)
  92. #  define SHIFT7 (24)
  93. #endif // WORDS_BIGENDIAN
  94.  
  95. #ifdef WITH_X86_TILES
  96. extern "C" {
  97.  
  98. void asm_tiles_init(unsigned char *vram,
  99.                     unsigned char *reg,
  100.                     unsigned *highpal);
  101.  
  102. void drawtile1(int which, int line, unsigned char *where);
  103. void drawtile1_solid(int which, int line, unsigned char *where);
  104. void drawtile2(int which, int line, unsigned char *where);
  105. void drawtile2_solid(int which, int line, unsigned char *where);
  106. void drawtile3(int which, int line, unsigned char *where);
  107. void drawtile3_solid(int which, int line, unsigned char *where);
  108. void drawtile4(int which, int line, unsigned char *where);
  109. void drawtile4_solid(int which, int line, unsigned char *where);
  110. }
  111.  
  112. // Pass off these calls to assembler counterparts
  113. inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
  114.   { drawtile1_solid(which, line, where); }
  115.  
  116. inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
  117.   { drawtile1(which, line, where); }
  118.  
  119. inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
  120.   { drawtile2_solid(which, line, where); }
  121.  
  122. inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
  123.   { drawtile2(which, line, where); }
  124.  
  125. inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
  126.   { drawtile3_solid(which, line, where); }
  127.  
  128. inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
  129.   { drawtile3(which, line, where); }
  130.  
  131. inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
  132.   { drawtile4_solid(which, line, where); }
  133.  
  134. inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
  135.   { drawtile4(which, line, where); }
  136.  
  137. #else // WITH_X86_TILES
  138.  
  139. static bool has_zero_nibbles(uint32_t u32)
  140. {
  141.         return ((u32 - 0x11111111) & ~u32 & 0x88888888);
  142. }
  143.  
  144. // Blit tile solidly, for 1 byte-per-pixel
  145. inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
  146. {
  147.   unsigned tile, pal;
  148.  
  149.   pal = (which >> 9 & 0x30); // Determine which 16-color palette
  150.  
  151.   if(which & 0x1000) // y flipped
  152.     line ^= 7; // take from the bottom, instead of the top
  153.  
  154.   if(reg[12] & 2) // interlace
  155.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  156.   else
  157.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  158.  
  159.   // Blit the tile!
  160.   if(which & 0x800) // x flipped
  161.     {
  162.       *(where  ) = ((tile & PIXEL7)>>SHIFT7) | pal;
  163.       *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
  164.       *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
  165.       *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
  166.       *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
  167.       *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
  168.       *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
  169.       *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
  170.     } else {
  171.       *(where  ) = ((tile & PIXEL0)>>SHIFT0) | pal;
  172.       *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
  173.       *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
  174.       *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
  175.       *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
  176.       *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
  177.       *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
  178.       *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
  179.     }
  180. }
  181.  
  182. // Blit tile, leaving color zero transparent, for 1 byte per pixel
  183. inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
  184. {
  185.   unsigned tile, pal;
  186.  
  187.   pal = (which >> 9 & 0x30); // Determine which 16-color palette
  188.  
  189.   if(which & 0x1000) // y flipped
  190.     line ^= 7; // take from the bottom, instead of the top
  191.  
  192.   if(reg[12] & 2) // interlace
  193.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  194.   else
  195.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  196.   // If the tile is all 0's, why waste the time?
  197.   if(!tile) return;
  198.  
  199.   // If the tile doesn't have any transparent pixels, draw it solidly.
  200.   if (!has_zero_nibbles(tile)) {
  201.     if (which & 0x800) {
  202.       // x flipped
  203.       *(where  ) = ((tile & PIXEL7)>>SHIFT7) | pal;
  204.       *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
  205.       *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
  206.       *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
  207.       *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
  208.       *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
  209.       *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
  210.       *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
  211.     }
  212.     else {
  213.       *(where  ) = ((tile & PIXEL0)>>SHIFT0) | pal;
  214.       *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
  215.       *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
  216.       *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
  217.       *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
  218.       *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
  219.       *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
  220.       *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
  221.     }
  222.     return;
  223.   }
  224.  
  225.   // Blit the tile!
  226.   if(which & 0x800) // x flipped
  227.     {
  228.       if(tile & PIXEL7) *(where  ) = ((tile & PIXEL7)>>SHIFT7) | pal;
  229.       if(tile & PIXEL6) *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
  230.       if(tile & PIXEL5) *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
  231.       if(tile & PIXEL4) *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
  232.       if(tile & PIXEL3) *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
  233.       if(tile & PIXEL2) *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
  234.       if(tile & PIXEL1) *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
  235.       if(tile & PIXEL0) *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
  236.     } else {
  237.       if(tile & PIXEL0) *(where  ) = ((tile & PIXEL0)>>SHIFT0) | pal;
  238.       if(tile & PIXEL1) *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
  239.       if(tile & PIXEL2) *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
  240.       if(tile & PIXEL3) *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
  241.       if(tile & PIXEL4) *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
  242.       if(tile & PIXEL5) *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
  243.       if(tile & PIXEL6) *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
  244.       if(tile & PIXEL7) *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
  245.     }
  246. }
  247.  
  248. // Blit tile solidly, for 2 byte-per-pixel
  249. inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
  250. {
  251.   unsigned tile, temp, *pal;
  252.   unsigned short *wwhere = (unsigned short*)where;
  253.  
  254.   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
  255.   temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
  256.  
  257.   if(which & 0x1000) // y flipped
  258.     line ^= 7; // take from the bottom, instead of the top
  259.  
  260.   if(reg[12] & 2) // interlace
  261.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  262.   else
  263.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  264.  
  265.   // Blit the tile!
  266.   if(which & 0x800) // x flipped
  267.     {
  268.       *(wwhere  ) = pal[((tile & PIXEL7)>>SHIFT7)];
  269.       *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
  270.       *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
  271.       *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
  272.       *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
  273.       *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
  274.       *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
  275.       *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
  276.     } else {
  277.       *(wwhere  ) = pal[((tile & PIXEL0)>>SHIFT0)];
  278.       *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
  279.       *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
  280.       *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
  281.       *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
  282.       *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
  283.       *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
  284.       *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
  285.     }
  286.   // Restore the original color
  287.   *pal = temp;
  288. }
  289.  
  290. // Blit tile, leaving color zero transparent, for 2 byte per pixel
  291. inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
  292. {
  293.   unsigned tile, *pal;
  294.   unsigned short *wwhere = (unsigned short*)where;
  295.  
  296.   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
  297.  
  298.   if(which & 0x1000) // y flipped
  299.     line ^= 7; // take from the bottom, instead of the top
  300.  
  301.   if(reg[12] & 2) // interlace
  302.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  303.   else
  304.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  305.   // If the tile is all 0's, why waste the time?
  306.   if(!tile) return;
  307.  
  308.   // If the tile doesn't have any transparent pixels, draw it solidly.
  309.   if (!has_zero_nibbles(tile)) {
  310.     if (which & 0x800) {
  311.       // x flipped
  312.       *(wwhere  ) = pal[((tile & PIXEL7)>>SHIFT7)];
  313.       *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
  314.       *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
  315.       *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
  316.       *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
  317.       *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
  318.       *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
  319.       *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
  320.     }
  321.     else {
  322.       *(wwhere  ) = pal[((tile & PIXEL0)>>SHIFT0)];
  323.       *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
  324.       *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
  325.       *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
  326.       *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
  327.       *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
  328.       *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
  329.       *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
  330.     }
  331.     return;
  332.   }
  333.  
  334.   // Blit the tile!
  335.   if(which & 0x800) // x flipped
  336.     {
  337.       if(tile & PIXEL7) *(wwhere  ) = pal[((tile & PIXEL7)>>SHIFT7)];
  338.       if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
  339.       if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
  340.       if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
  341.       if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
  342.       if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
  343.       if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
  344.       if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
  345.     } else {
  346.       if(tile & PIXEL0) *(wwhere  ) = pal[((tile & PIXEL0)>>SHIFT0)];
  347.       if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
  348.       if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
  349.       if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
  350.       if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
  351.       if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
  352.       if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
  353.       if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
  354.     }
  355. }
  356.  
  357. inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
  358. {
  359.   unsigned tile, temp, *pal;
  360.   uint24_t *wwhere = (uint24_t *)where;
  361.  
  362.   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
  363.   temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
  364.  
  365.   if(which & 0x1000) // y flipped
  366.     line ^= 7; // take from the bottom, instead of the top
  367.  
  368.   if(reg[12] & 2) // interlace
  369.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  370.   else
  371.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  372.  
  373.   // Blit the tile!
  374.   if(which & 0x800) // x flipped
  375.     {
  376.       u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
  377.       u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
  378.       u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
  379.       u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
  380.       u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
  381.       u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
  382.       u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
  383.       u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
  384.     } else {
  385.       u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
  386.       u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
  387.       u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
  388.       u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
  389.       u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
  390.       u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
  391.       u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
  392.       u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
  393.     }
  394.   // Restore the original color
  395.   *pal = temp;
  396. }
  397.  
  398. inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
  399. {
  400.   unsigned tile, *pal;
  401.   uint24_t *wwhere = (uint24_t *)where;
  402.  
  403.   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
  404.  
  405.   if(which & 0x1000) // y flipped
  406.     line ^= 7; // take from the bottom, instead of the top
  407.  
  408.   if(reg[12] & 2) // interlace
  409.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  410.   else
  411.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  412.   // If it's empty, why waste the time?
  413.   if(!tile) return;
  414.  
  415.   // If the tile doesn't have any transparent pixels, draw it solidly.
  416.   if (!has_zero_nibbles(tile)) {
  417.     if (which & 0x800) {
  418.       // x flipped
  419.       u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
  420.       u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
  421.       u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
  422.       u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
  423.       u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
  424.       u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
  425.       u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
  426.       u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
  427.     }
  428.     else {
  429.       u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
  430.       u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
  431.       u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
  432.       u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
  433.       u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
  434.       u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
  435.       u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
  436.       u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
  437.     }
  438.     return;
  439.   }
  440.  
  441.   // Blit the tile!
  442.   if(which & 0x800) // x flipped
  443.     {
  444.       if (tile & PIXEL7)
  445.                 u24cpy(&wwhere[0],
  446.                        (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
  447.       if(tile & PIXEL6)
  448.                 u24cpy(&wwhere[1],
  449.                        (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
  450.       if(tile & PIXEL5)
  451.                 u24cpy(&wwhere[2],
  452.                        (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
  453.       if(tile & PIXEL4)
  454.                 u24cpy(&wwhere[3],
  455.                        (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
  456.       if(tile & PIXEL3)
  457.                 u24cpy(&wwhere[4],
  458.                        (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
  459.       if(tile & PIXEL2)
  460.                 u24cpy(&wwhere[5],
  461.                        (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
  462.       if(tile & PIXEL1)
  463.                 u24cpy(&wwhere[6],
  464.                        (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
  465.       if(tile & PIXEL0)
  466.                 u24cpy(&wwhere[7],
  467.                        (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
  468.     } else {
  469.       if(tile & PIXEL0)
  470.                 u24cpy(&wwhere[0],
  471.                        (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
  472.       if(tile & PIXEL1)
  473.                 u24cpy(&wwhere[1],
  474.                        (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
  475.       if(tile & PIXEL2)
  476.                 u24cpy(&wwhere[2],
  477.                        (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
  478.       if(tile & PIXEL3)
  479.                 u24cpy(&wwhere[3],
  480.                        (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
  481.       if(tile & PIXEL4)
  482.                 u24cpy(&wwhere[4],
  483.                        (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
  484.       if(tile & PIXEL5)
  485.                 u24cpy(&wwhere[5],
  486.                        (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
  487.       if(tile & PIXEL6)
  488.                 u24cpy(&wwhere[6],
  489.                        (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
  490.       if(tile & PIXEL7)
  491.                 u24cpy(&wwhere[7],
  492.                        (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
  493.     }
  494. }
  495.  
  496. // Blit tile solidly, for 4 byte-per-pixel
  497. inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
  498. {
  499.   unsigned tile, temp, *pal;
  500.   unsigned *wwhere = (unsigned*)where;
  501.  
  502.   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
  503.   temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
  504.  
  505.   if(which & 0x1000) // y flipped
  506.     line ^= 7; // take from the bottom, instead of the top
  507.  
  508.   if(reg[12] & 2) // interlace
  509.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  510.   else
  511.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  512.  
  513.   // Blit the tile!
  514.   if(which & 0x800) // x flipped
  515.     {
  516.       *(wwhere  ) = pal[((tile & PIXEL7)>>SHIFT7)];
  517.       *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
  518.       *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
  519.       *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
  520.       *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
  521.       *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
  522.       *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
  523.       *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
  524.     } else {
  525.       *(wwhere  ) = pal[((tile & PIXEL0)>>SHIFT0)];
  526.       *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
  527.       *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
  528.       *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
  529.       *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
  530.       *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
  531.       *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
  532.       *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
  533.     }
  534.   // Restore the original color
  535.   *pal = temp;
  536. }
  537.  
  538. // Blit tile, leaving color zero transparent, for 4 byte per pixel
  539. inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
  540. {
  541.   unsigned tile, *pal;
  542.   unsigned *wwhere = (unsigned*)where;
  543.  
  544.   pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
  545.  
  546.   if(which & 0x1000) // y flipped
  547.     line ^= 7; // take from the bottom, instead of the top
  548.  
  549.   if(reg[12] & 2) // interlace
  550.     tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
  551.   else
  552.     tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
  553.   // If the tile is all 0's, why waste the time?
  554.   if(!tile) return;
  555.  
  556.   // If the tile doesn't have any transparent pixels, draw it solidly.
  557.   if (!has_zero_nibbles(tile)) {
  558.     if (which & 0x800) {
  559.       // x flipped
  560.       *(wwhere  ) = pal[((tile & PIXEL7)>>SHIFT7)];
  561.       *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
  562.       *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
  563.       *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
  564.       *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
  565.       *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
  566.       *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
  567.       *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
  568.     }
  569.     else {
  570.       *(wwhere  ) = pal[((tile & PIXEL0)>>SHIFT0)];
  571.       *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
  572.       *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
  573.       *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
  574.       *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
  575.       *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
  576.       *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
  577.       *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
  578.     }
  579.     return;
  580.   }
  581.  
  582.   // Blit the tile!
  583.   if(which & 0x800) // x flipped
  584.     {
  585.       if(tile & PIXEL7) *(wwhere  ) = pal[((tile & PIXEL7)>>SHIFT7)];
  586.       if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
  587.       if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
  588.       if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
  589.       if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
  590.       if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
  591.       if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
  592.       if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
  593.     } else {
  594.       if(tile & PIXEL0) *(wwhere  ) = pal[((tile & PIXEL0)>>SHIFT0)];
  595.       if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
  596.       if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
  597.       if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
  598.       if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
  599.       if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
  600.       if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
  601.       if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
  602.     }
  603. }
  604. #endif // WITH_X86_TILES
  605.  
  606. // Draw the window (front or back)
  607. void md_vdp::draw_window(int line, int front)
  608. {
  609.   int size;
  610.   int x, y, w, start;
  611.   int pl, add;
  612.   int total_window;
  613.   unsigned char *where;
  614.   int which;
  615.   // Set everything up
  616.   y = line >> 3;
  617.   total_window = (y < (reg[18]&0x1f)) ^ (reg[18] >> 7);
  618.  
  619.   // Wide or narrow
  620.   size = (reg[12] & 1)? 64 : 32;
  621.  
  622.   pl = (reg[3] << 10) + ((y&0x3f)*size*2);
  623.  
  624.   // Wide(320) or narrow(256)?
  625.   if(reg[12] & 1)
  626.     {
  627.       w = 40;
  628.       start = -8;
  629.     } else {
  630.       w = 32;
  631.       start = 24;
  632.     }
  633.   add = -2;
  634.   where = dest + (start * (int)Bpp);
  635.         for (x = -1; (x < w); ++x) {
  636.                 if (!total_window) {
  637.                         if (reg[17] & 0x80) {
  638.                                 if (x < ((reg[17] & 0x1f) << 1))
  639.                                         goto skip;
  640.                         }
  641.                         else {
  642.                                 if (x >= ((reg[17] & 0x1f) << 1))
  643.                                         goto skip;
  644.                         }
  645.                 }
  646.                 which = get_word(((unsigned char *)vram) +
  647.                                  (pl + (add & ((size - 1) << 1))));
  648.                 if ((which >> 15) == front)
  649.                         draw_tile(which, (line & 7), where);
  650.         skip:
  651.                 add += 2;
  652.                 where += Bpp_times8;
  653.         }
  654. }
  655.  
  656. inline void md_vdp::get_sprite_info(struct sprite_info& info, int index)
  657. {
  658.         uint_fast16_t prop;
  659.  
  660.         info.sprite = (sprite_base + (index << 3));
  661.  
  662.         // Get the sprite's location
  663.         info.y = get_word(info.sprite);
  664.         info.x = (get_word(info.sprite + 6) & 0x1ff);
  665.  
  666.         // Interlace?
  667.         // XXX
  668.         // "& 1" below is a workaround for a GCC (g++) <= 4.2.1 bug seen
  669.         // in OpenBSD.
  670.         // info.inter is a bit-field member of size 1 that normally cannot
  671.         // store anything other than 0 or 1, but which does in practice,
  672.         // causing info.tile to point to a bad address and crashing.
  673.         info.inter = ((reg[12] >> 1) & 1);
  674.  
  675.         // Properties
  676.         prop = get_word(info.sprite + 4);
  677.         info.prio = (prop >> 15);
  678.         info.xflip = (prop >> 11);
  679.         info.yflip = (prop >> 12);
  680.         info.tile = (uint32_t *)(vram + ((prop & 0x07ff) << (5 + info.inter)));
  681.  
  682.         if (info.inter)
  683.                 info.y = ((info.y & 0x3fe) >> 1);
  684.         else
  685.                 info.y &= 0x1ff;
  686.  
  687.         info.x -= 0x80;
  688.         info.y -= 0x80;
  689.  
  690.         // Narrow mode?
  691.         if (!(reg[12] & 1))
  692.                 info.x += 32;
  693.  
  694.         info.tw = (((info.sprite[2] >> 2) & 0x03) + 1);
  695.         info.th = ((info.sprite[2] & 0x03) + 1);
  696.         info.w = (info.tw << 3);
  697.         info.h = (info.th << 3);
  698. }
  699.  
  700. void md_vdp::sprite_masking_overflow(int line)
  701. {
  702.         int masking_sprite_index;
  703.         bool masking_effective;
  704.         int frame_limit;
  705.         int line_limit;
  706.         int dots;
  707.         int i;
  708.  
  709.         /*
  710.          * Search for the highest priority sprite with x = 0. Call this sprite
  711.          * s0.  Any sprite with a lower priority than s0 (therefore higher
  712.          * index in the array) is not drawn on the scanlines that s0 occupies
  713.          * on the y-axis. This is called sprite masking and is used by games
  714.          * like Streets of Rage and Lotus Turbo Challenge.
  715.          *
  716.          * Thanks for Charles MacDonald for explaining this to me (vext01).
  717.          *
  718.          * This loop also limits the number of sprites per line, which is 20
  719.          * in H40 and 16 in H32 _or_ 320 pixels wide in H40 and 256 pixels
  720.          * wide in H32, with a possibility for the last sprite to be only
  721.          * partially drawn.
  722.          */
  723.         masking_sprite_index = -1;
  724.         // If sprites on the previous line overflowed, sprite masking becomes
  725.         // effective by default for the current line (it normally isn't).
  726.         masking_effective = (sprite_overflow_line == (line - 1));
  727.         // Set sprites and dots limits for the current line.
  728.         if (reg[12] & 1) {
  729.                 frame_limit = 80;
  730.                 line_limit = 20;
  731.                 dots = 320;
  732.         }
  733.         else {
  734.                 frame_limit = 64;
  735.                 line_limit = 16;
  736.                 dots = 256;
  737.         }
  738.         for (i = 0; i < sprite_count; i++) {
  739.                 int x, y, w, h;
  740.                 int idx;
  741.                 uint8_t *sprite;
  742.  
  743.                 // First, make sure the frame limit hasn't been reached.
  744.                 idx = sprite_order[i];
  745.                 if (idx >= frame_limit) {
  746.                         if (masking_sprite_index == -1)
  747.                                 masking_sprite_index = (i - 1);
  748.                         break;
  749.                 }
  750.                 // Get current sprite coordinates and dimensions.
  751.                 sprite = (sprite_base + (idx << 3));
  752.                 x = get_word(sprite + 6) & 0x1ff;
  753.                 y = get_word(sprite);
  754.                 if (reg[12] & 2)
  755.                         y = ((y & 0x3fe) >> 1);
  756.                 else
  757.                         y &= 0x1ff;
  758.                 h = (((sprite[2] & 0x03) << 3) + 8);
  759.                 w = (((sprite[2] << 1) & 0x18) + 8);
  760.                 // If this sprite isn't found on the current line, skip it.
  761.                 if (!(((line + 0x80) >= y) && ((line + 0x80) < (y + h))))
  762.                         continue;
  763.                 // Substract sprite from the dots limit and decrease the
  764.                 // sprites limit.
  765.                 dots -= w;
  766.                 --line_limit;
  767.                 // If this sprite is not a masking sprite (x != 0), sprite
  768.                 // masking becomes effective. The next sprite with (x == 0)
  769.                 // will be a masking sprite.
  770.                 if (x != 0)
  771.                         masking_effective = true;
  772.                 // If a dot overflow occured, update sprite_overflow_line with
  773.                 // the current line. This update must be done only once for a
  774.                 // given line.
  775.                 if (dots <= 0) {
  776.                         sprite_overflow_line = line;
  777.                         // If no masking sprite index has been set so far, do
  778.                         // it now.  Otherwise reset dots, because this sprite
  779.                         // must not be truncated.
  780.                         if (masking_sprite_index == -1)
  781.                                 masking_sprite_index = i;
  782.                         else
  783.                                 dots = 0;
  784.                         // Don't process any more sprites, exit from the loop.
  785.                         break;
  786.                 }
  787.                 // Check whether sprites limit has been reached.
  788.                 if (line_limit == 0) {
  789.                         // If no masking sprite index has been set so far, do
  790.                         // it now.
  791.                         if (masking_sprite_index == -1)
  792.                                 masking_sprite_index = i;
  793.                         // Trigger sprite overflow bit (d6).
  794.                         belongs.coo5 |= 0x40;
  795.                         // Don't process any more sprites, exit from the loop.
  796.                         break;
  797.                 }
  798.                 // If sprite masking is effective and the current sprite is a
  799.                 // masking sprite (x == 0), if we haven't already found one
  800.                 // before, use this one, then continue to process the sprites
  801.                 // list as we still need to know whether a dot overflow
  802.                 // occured.
  803.                 if ((masking_effective) &&
  804.                     (x == 0) &&
  805.                     (masking_sprite_index == -1))
  806.                         masking_sprite_index = i;
  807.         }
  808.         // If no masking sprite index was found, display them all.
  809.         if (masking_sprite_index == -1)
  810.                 masking_sprite_index = (sprite_count - 1);
  811.         masking_sprite_index_cache = masking_sprite_index;
  812.         dots_cache = dots;
  813. }
  814.  
  815. inline void md_vdp::sprite_mask_add(uint8_t* dest, int pitch,
  816.                                     struct sprite_info& info, int value)
  817. {
  818.         uint32_t *tile = info.tile;
  819.         int len = (info.tw * info.h);
  820.         int lines = (8 << info.inter);
  821.         int line = 0;
  822.         int wrap = 0;
  823.         int unit = 1;
  824.  
  825.         dest += info.x;
  826.         dest += (pitch * info.y);
  827.         if (info.yflip) {
  828.                 dest += (pitch * (info.h - 1));
  829.                 pitch = -pitch;
  830.         }
  831.         if (info.xflip) {
  832.                 dest += (info.w - 1);
  833.                 unit = -unit;
  834.         }
  835.         while (len) {
  836.                 uint_fast32_t dots = be2h32(*tile);
  837.                 unsigned int tmp;
  838.  
  839.                 for (tmp = 0; (tmp != 8); ++tmp) {
  840.                         assert(dest >= (uint8_t *)sprite_mask);
  841.                         assert(dest < ((uint8_t *)sprite_mask +
  842.                                        sizeof(sprite_mask)));
  843.                         /*
  844.                          * If a non-transparent sprite dot has already been
  845.                          * drawn here, trigger the collision bit (d5).
  846.                          * FIXME: doing this here is hackish and doesn't take
  847.                          * sprites with the high priority bit into account.
  848.                          */
  849.                         if (*dest != 0xff)
  850.                                 belongs.coo5 |= 0x20;
  851. #ifdef WORDS_BIGENDIAN
  852.                         if (dots & 0x0000000f)
  853.                                 *dest = value;
  854.                         dots >>= 4;
  855. #else
  856.                         if (dots & 0xf0000000)
  857.                                 *dest = value;
  858.                         dots <<= 4;
  859. #endif
  860.                         dest += unit;
  861.                 }
  862.                 ++tile;
  863.                 ++line;
  864.                 if (line == lines) {
  865.                         /* Next tile. */
  866.                         line = 0;
  867.                         ++wrap;
  868.                         if (wrap == info.th) {
  869.                                 /* Next tiles column. */
  870.                                 dest -= (pitch * (info.h - 1));
  871.                                 wrap = 0;
  872.                         }
  873.                         else {
  874.                                 /* Next tiles row. */
  875.                                 dest += (pitch - (8 * unit));
  876.                         }
  877.                 }
  878.                 else {
  879.                         /* Next line of dots. */
  880.                         dest -= (8 * unit);
  881.                         dest += pitch;
  882.                 }
  883.                 --len;
  884.         }
  885. }
  886.  
  887. void md_vdp::sprite_mask_generate()
  888. {
  889.         int i;
  890.  
  891.         memset(sprite_mask, 0xff, sizeof(sprite_mask));
  892.         for (i = (sprite_count - 1); (i >= 0); --i) {
  893.                 sprite_info info;
  894.  
  895.                 get_sprite_info(info, sprite_order[i]);
  896.                 // We only care about sprites with the low priority bit unset.
  897.                 if (info.prio)
  898.                         continue;
  899.                 // Don't bother with hidden sprites.
  900.                 if ((info.x >= 320) || ((info.x + info.w) < 0))
  901.                         continue;
  902.                 if ((info.y >= 256) || ((info.y + info.h) < 0))
  903.                         continue;
  904.                 info.x += 0x80;
  905.                 info.y += 0x80;
  906.                 // Draw overlap mask for this sprite in a 512x512 virtual area.
  907.                 sprite_mask_add((uint8_t *)sprite_mask, sizeof(sprite_mask[0]),
  908.                                 info, i);
  909.         }
  910. }
  911.  
  912. void md_vdp::draw_sprites(int line, bool front)
  913. {
  914.   unsigned int which;
  915.   int tx, ty, x, y, xend, ysize, yoff, i, masking_sprite_index;
  916.   int dots;
  917.   unsigned char *where;
  918. #ifdef WITH_DEBUG_VDP
  919.   static int ant[2];
  920.   static unsigned long ant_last[2];
  921.   unsigned long ant_cur;
  922.  
  923.   if ((dgen_vdp_sprites_boxing) && (line == 0)) {
  924.     ant_cur = pd_usecs();
  925.     if ((ant_cur - ant_last[front]) > 100000) {
  926.       ant_last[front] = ant_cur;
  927.       ant[front] ^= 1;
  928.     }
  929.   }
  930. #endif
  931.   masking_sprite_index = masking_sprite_index_cache;
  932.   dots = dots_cache;
  933.   // If dots_cache is less than zero, draw the first sprite partially.
  934.   if (dots > 0)
  935.     dots = 0;
  936.   // Sprites have to be in reverse order :P
  937.   for (i = masking_sprite_index; i >= 0; --i)
  938.     {
  939.       sprite_info info;
  940.  
  941.       get_sprite_info(info, sprite_order[i]);
  942.       // Only do it if it's on the right priority.
  943.       if (info.prio == front)
  944.         {
  945.           which = get_word(info.sprite + 4);
  946.           // Get the sprite's location
  947.           y = info.y;
  948.           x = info.x;
  949.           yoff = (line - y);
  950.           xend = ((info.w - 8) + x);
  951.           // Partial draw if negative.
  952.           xend += dots;
  953.           ysize = ((info.h - 8) >> 3);
  954.           // Render if this sprite's on this line
  955.           if(xend > -8 && x < 320 && yoff >= 0 && yoff <= (ysize<<3)+7)
  956.             {
  957.               ty = yoff & 7;
  958.               // y flipped?
  959.               if(which & 0x1000)
  960.                 which += ysize - (yoff >> 3);
  961.               else
  962.                 which += (yoff >> 3);
  963.               ++ysize;
  964.               // Unconditionally draw this sprite. It's supposed to always
  965.               // appear on top of other sprites.
  966.               if (!front) {
  967.                 // x flipped?
  968.                 if (which & 0x800) {
  969.                   where = dest + (xend * (int)Bpp);
  970.                   for(tx = xend; tx >= x; tx -= 8)
  971.                     {
  972.                       if(tx > -8 && tx < 320)
  973.                         draw_tile(which, ty, where);
  974.                       which += ysize;
  975.                       where -= Bpp_times8;
  976.                     }
  977.                 }
  978.                 else {
  979.                   where = dest + (x * (int)Bpp);
  980.                   for(tx = x; tx <= xend; tx += 8)
  981.                     {
  982.                       if(tx > -8 && tx < 320)
  983.                         draw_tile(which, ty, where);
  984.                       which += ysize;
  985.                       where += Bpp_times8;
  986.                     }
  987.                 }
  988.               }
  989.               // Draw sprite with the high priority bit set only where it's
  990.               // not covered by a higher priority sprite (lower index in the
  991.               // list) but with this bit unset. Those have already been drawn
  992.               // during the previous pass.
  993.               else {
  994.                 union {
  995.                   uint32_t t4[8];
  996.                   uint24_t t3[8];
  997.                   uint16_t t2[8];
  998.                   uint8_t t1[8];
  999.                 } tile;
  1000.  
  1001.                 // x flipped?
  1002.                 if (which & 0x800) {
  1003.                   where = dest + (xend * (int)Bpp);
  1004.                   for (tx = xend; (tx >= x); tx -= 8) {
  1005.                     if ((tx > -8) && (tx < 320)) {
  1006.                       int xx;
  1007.                       int xo;
  1008.  
  1009.                       memcpy(tile.t1, where, Bpp_times8);
  1010.                       draw_tile(which, ty, tile.t1);
  1011.                       for (xx = tx, xo = 0; (xo != 8); ++xo, ++xx)
  1012.                         if (sprite_mask[(line + 0x80)][(xx + 0x80)] >= i)
  1013.                           memcpy(&dest[(xx * (int)Bpp)],
  1014.                                  &tile.t1[(xo * (int)Bpp)],
  1015.                                  (int)Bpp);
  1016.                     }
  1017.                     which += ysize;
  1018.                     where -= Bpp_times8;
  1019.                   }
  1020.                 }
  1021.                 else {
  1022.                   where = dest + (x * (int)Bpp);
  1023.                   for (tx = x; (tx <= xend); tx += 8) {
  1024.                     if ((tx > -8) && (tx < 320)) {
  1025.                       int xx;
  1026.                       int xo;
  1027.  
  1028.                       memcpy(tile.t1, where, Bpp_times8);
  1029.                       draw_tile(which, ty, tile.t1);
  1030.                       for (xx = tx, xo = 0; (xo != 8); ++xo, ++xx)
  1031.                         if (sprite_mask[(line + 0x80)][(xx + 0x80)] >= i)
  1032.                           memcpy(&dest[(xx * (int)Bpp)],
  1033.                                  &tile.t1[(xo * (int)Bpp)],
  1034.                                  (int)Bpp);
  1035.                     }
  1036.                     which += ysize;
  1037.                     where += Bpp_times8;
  1038.                   }
  1039.                 }
  1040.               }
  1041. #ifdef WITH_DEBUG_VDP
  1042.               if (dgen_vdp_sprites_boxing) {
  1043.                 uint32_t color[2] = {
  1044.                   (uint32_t)dgen_vdp_sprites_boxing_bg,
  1045.                   (uint32_t)dgen_vdp_sprites_boxing_fg
  1046.                 };
  1047.                 int ph;
  1048.                 int fx;
  1049.  
  1050.                 if ((ph = 0, (y == line)) ||
  1051.                     (ph = 1, ((y + info.h - 1) == line)))
  1052.                   for (fx = (ant[front] ^ ph); (fx < info.w); fx += 2)
  1053.                     draw_pixel(this->bmap, (info.x + fx),
  1054.                                line, color[info.prio]);
  1055.                 else
  1056.                   draw_pixel(this->bmap,
  1057.                              (((line & 1) == ant[front]) ?
  1058.                               (info.x + info.w - 1) : info.x),
  1059.                              line, color[info.prio]);
  1060.               }
  1061. #endif
  1062.             }
  1063.         }
  1064.       dots = 0;
  1065.     }
  1066. }
  1067.  
  1068. // The body for the next few functions is in an extraneous header file.
  1069. // Phil, I hope I left enough in this file for GLOBAL to hack it right. ;)
  1070. // Thanks to John Stiles for this trick :)
  1071.  
  1072. void md_vdp::draw_plane_back0(int line)
  1073. {
  1074. #define FRONT 0
  1075. #define PLANE 0
  1076. #include "ras-drawplane.h"
  1077. #undef PLANE
  1078. #undef FRONT
  1079. }
  1080.  
  1081. void md_vdp::draw_plane_back1(int line)
  1082. {
  1083. #define FRONT 0
  1084. #define PLANE 1
  1085. #include "ras-drawplane.h"
  1086. #undef PLANE
  1087. #undef FRONT
  1088. }
  1089.  
  1090. void md_vdp::draw_plane_front0(int line)
  1091. {
  1092. #define FRONT 1
  1093. #define PLANE 0
  1094. #include "ras-drawplane.h"
  1095. #undef PLANE
  1096. #undef FRONT
  1097. }
  1098.  
  1099. void md_vdp::draw_plane_front1(int line)
  1100. {
  1101. #define FRONT 1
  1102. #define PLANE 1
  1103. #include "ras-drawplane.h"
  1104. #undef PLANE
  1105. #undef FRONT
  1106. }
  1107.  
  1108. // Allow frame components to be hidden when WITH_DEBUG_VDP is defined.
  1109. #ifdef WITH_DEBUG_VDP
  1110. #define vdp_hide_if(a, b) ((a) ? (void)0 : (void)(b))
  1111. #else
  1112. #define vdp_hide_if(a, b) (void)(b)
  1113. #endif
  1114.  
  1115. // The main interface function, to generate a scanline
  1116. void md_vdp::draw_scanline(struct bmap *bits, int line)
  1117. {
  1118.   unsigned *ptr, i;
  1119.   // Set the destination in the bmap
  1120.   bmap = bits;
  1121.   dest = bits->data + (bits->pitch * (line + 8) + 16);
  1122.   // If bytes per pixel hasn't yet been set, do it
  1123.   if ((Bpp == 0) || (Bpp != BITS_TO_BYTES(bits->bpp)))
  1124.     {
  1125.            if(bits->bpp <= 8)  Bpp = 1;
  1126.       else if(bits->bpp <= 16) Bpp = 2;
  1127.       else if(bits->bpp <= 24) Bpp = 3;
  1128.       else                     Bpp = 4;
  1129.       Bpp_times8 = Bpp << 3; // used for tile blitting
  1130. #ifdef WITH_X86_TILES
  1131.       asm_tiles_init(vram, reg, highpal); // pass these values to the asm tiles
  1132. #endif
  1133.     }
  1134.  
  1135.   // If the palette's been changed, update it
  1136.   if(dirt[0x34] & 2)
  1137.     {
  1138.       ptr = highpal;
  1139.       // What color depth are we?
  1140.       switch(bits->bpp)
  1141.         {
  1142.         case 24:
  1143. #ifdef WORDS_BIGENDIAN
  1144.                 for (i = 0; (i < 128); i += 2)
  1145.                         *ptr++ = (((cram[(i + 1)] & 0x0e) << 28) |
  1146.                                   ((cram[(i + 1)] & 0xe0) << 16) |
  1147.                                   ((cram[i] & 0x0e) << 12));
  1148.                 break;
  1149. #else
  1150.                 for (i = 0; (i < 128); i += 2)
  1151.                         *ptr++ = (((cram[(i + 1)] & 0x0e) << 4) |
  1152.                                   ((cram[(i + 1)] & 0xe0) << 16) |
  1153.                                   ((cram[i] & 0x0e) << 12));
  1154.                 break;
  1155. #endif
  1156.         case 32:
  1157.           for(i = 0; i < 128; i += 2)
  1158.             *ptr++ = ((cram[i+1]&0x0e) << 20) |
  1159.                      ((cram[i+1]&0xe0) << 8 ) |
  1160.                      ((cram[i]  &0x0e) << 4 );
  1161.           break;
  1162.         case 16:
  1163.           for(i = 0; i < 128; i += 2)
  1164.             *ptr++ = ((cram[i+1]&0x0e) << 12) |
  1165.                      ((cram[i+1]&0xe0) << 3 ) |
  1166.                      ((cram[i]  &0x0e) << 1 );
  1167.           break;
  1168.         case 15:
  1169.           for(i = 0; i < 128; i += 2)
  1170.             *ptr++ = ((cram[i+1]&0x0e) << 11) |
  1171.                      ((cram[i+1]&0xe0) << 2 ) |
  1172.                      ((cram[i]  &0x0e) << 1 );
  1173.           break;
  1174.         case 8:
  1175.         default:
  1176.           // Let the hardware palette sort it out :P
  1177.           for(i = 0; i < 64; ++i) *ptr++ = i;
  1178.         }
  1179.       // Clean up the dirt
  1180.       dirt[0x34] &= ~2;
  1181.       pal_dirty = 1;
  1182.     }
  1183.   // Render the screen if it's turned on
  1184.   if(reg[1] & 0x40)
  1185.     {
  1186.       // Recalculate the sprite order, if it's dirty
  1187.       if((dirt[0x30] & 0x20) || (dirt[0x34] & 1))
  1188.         {
  1189.           unsigned next = 0;
  1190.           // Max number of sprites per frame: 80 in H40, 64 in H32.
  1191.           int max = ((reg[12] & 1) ? 80 : 64);
  1192.           // Find the sprite base in VRAM
  1193.           sprite_base = vram + (reg[5]<<9);
  1194.           // Order the sprites
  1195.           sprite_count = sprite_order[0] = 0;
  1196.           do {
  1197.             next = sprite_base[(next << 3) + 3];
  1198.             sprite_order[++sprite_count] = next;
  1199.           } while (next && sprite_count < max);
  1200.           // Clean up the dirt
  1201.           dirt[0x30] &= ~0x20; dirt[0x34] &= ~1;
  1202.           // Generate overlap mask for sprites with high priority bit
  1203.           sprite_mask_generate();
  1204.         }
  1205.       // Calculate sprite masking and overflow.
  1206.       sprite_masking_overflow(line);
  1207.       // Draw, from the bottom up
  1208.       // Low priority
  1209.       vdp_hide_if(dgen_vdp_hide_plane_b, draw_plane_back1(line));
  1210.       vdp_hide_if(dgen_vdp_hide_plane_a, draw_plane_back0(line));
  1211.       vdp_hide_if(dgen_vdp_hide_plane_w, draw_window(line, 0));
  1212.       vdp_hide_if(dgen_vdp_hide_sprites, draw_sprites(line, 0));
  1213.       // High priority
  1214.       vdp_hide_if(dgen_vdp_hide_plane_b, draw_plane_front1(line));
  1215.       vdp_hide_if(dgen_vdp_hide_plane_a, draw_plane_front0(line));
  1216.       vdp_hide_if(dgen_vdp_hide_plane_w, draw_window(line, 1));
  1217.       vdp_hide_if(dgen_vdp_hide_sprites, draw_sprites(line, 1));
  1218.     } else {
  1219.       // The display is off, paint it black
  1220.       // Do it a dword at a time
  1221.       unsigned *destl = (unsigned*)dest;
  1222.       for(i = 0; i < (80 * Bpp); ++i) destl[i] = 0;
  1223.     }
  1224.  
  1225.   // If we're in narrow (256) mode, cut off the messy edges
  1226.   if(!(reg[12] & 1))
  1227.     {
  1228.       unsigned *destl = (unsigned*)dest;
  1229.       for(i = 0; i < Bpp_times8; ++i)
  1230.         destl[i] = destl[i + (72 * Bpp)] = 0;
  1231.     }
  1232. }
  1233.  
  1234. void md_vdp::draw_pixel(struct bmap *bits, int x, int y, uint32_t rgb)
  1235. {
  1236.         uint8_t *out;
  1237.  
  1238.         if ((x < 0) || (x >= bits->w) || (y < 0) || (y >= bits->h))
  1239.                 return;
  1240.         out = ((bits->data + (bits->pitch * (y + 8) + 16)) +
  1241.                (x * BITS_TO_BYTES(bits->bpp)));
  1242.         switch (bits->bpp) {
  1243.                 uint16_t tmp;
  1244.  
  1245.         case 32:
  1246.                 memcpy(out, &rgb, sizeof(rgb));
  1247.                 break;
  1248.         case 24:
  1249.                 u24cpy((uint24_t *)out,
  1250.                        (const uint24_t *)((uint8_t *)&rgb + 1));
  1251.                 break;
  1252.         case 16:
  1253.                 tmp = (((rgb >> 5) & 0xf800) |
  1254.                        ((rgb >> 3) & 0x07e0) |
  1255.                        (rgb & 0x1f));
  1256.                 memcpy(out, &tmp, sizeof(tmp));
  1257.                 break;
  1258.         case 15:
  1259.                 tmp = (((rgb >> 6) & 0x7c00) |
  1260.                        ((rgb >> 3) & 0x03e0) |
  1261.                        (rgb & 0x1f));
  1262.                 memcpy(out, &tmp, sizeof(tmp));
  1263.                 break;
  1264.         }
  1265. }
  1266.