SpriteConverter.hh 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. TODO:
  3. - Implement sprite pixels in Graphic 5.
  4. */
  5. #ifndef SPRITECONVERTER_HH
  6. #define SPRITECONVERTER_HH
  7. #include "SpriteChecker.hh"
  8. #include "DisplayMode.hh"
  9. #include "likely.hh"
  10. #include "openmsx.hh"
  11. namespace openmsx {
  12. /** Utility class for converting VRAM contents to host pixels.
  13. */
  14. template <class Pixel>
  15. class SpriteConverter
  16. {
  17. public:
  18. // TODO: Move some methods to .cc?
  19. /** Constructor.
  20. * After construction, also call the various set methods to complete
  21. * initialisation.
  22. * @param spriteChecker_ Delivers the sprite data to be rendered.
  23. */
  24. explicit SpriteConverter(SpriteChecker& spriteChecker_)
  25. : spriteChecker(spriteChecker_)
  26. {
  27. }
  28. /** Update the transparency setting.
  29. * @param enabled The new value.
  30. */
  31. void setTransparency(bool enabled)
  32. {
  33. transparency = enabled;
  34. }
  35. /** Notify SpriteConverter of a display mode change.
  36. * @param newMode The new display mode.
  37. */
  38. void setDisplayMode(DisplayMode newMode)
  39. {
  40. mode = newMode;
  41. }
  42. /** Set palette to use for converting sprites.
  43. * This palette is stored by reference, so any modifications to it
  44. * will be used while drawing.
  45. * @param newPalette 16-entry array containing the sprite palette.
  46. */
  47. void setPalette(const Pixel* newPalette)
  48. {
  49. palette = newPalette;
  50. }
  51. static bool clipPattern(int& x, SpriteChecker::SpritePattern& pattern,
  52. int minX, int maxX)
  53. {
  54. int before = minX - x;
  55. if (before > 0) {
  56. if (before >= 32) {
  57. // 32 pixels before minX -> not visible
  58. return false;
  59. }
  60. pattern <<= before;
  61. x = minX;
  62. }
  63. int after = maxX - x;
  64. if (after < 32) {
  65. // close to maxX (or past)
  66. if (after <= 0) {
  67. // past maxX -> not visible
  68. return false;
  69. }
  70. int mask = 0x80000000;
  71. pattern &= (mask >> (after - 1));
  72. }
  73. return true; // visible
  74. }
  75. /** Draw sprites in sprite mode 1.
  76. * @param absLine Absolute line number.
  77. * Range is [0..262) for NTSC and [0..313) for PAL.
  78. * @param minX Minimum X coordinate to draw (inclusive).
  79. * @param maxX Maximum X coordinate to draw (exclusive).
  80. * @param pixelPtr Pointer to memory to draw to.
  81. */
  82. void drawMode1(int absLine, int minX, int maxX,
  83. Pixel* __restrict pixelPtr) __restrict
  84. {
  85. // Determine sprites visible on this line.
  86. const SpriteChecker::SpriteInfo* visibleSprites;
  87. int visibleIndex =
  88. spriteChecker.getSprites(absLine, visibleSprites);
  89. // Optimisation: return at once if no sprites on this line.
  90. // Lines without any sprites are very common in most programs.
  91. if (visibleIndex == 0) return;
  92. // Render using overdraw.
  93. while (visibleIndex--) {
  94. // Get sprite info.
  95. const SpriteChecker::SpriteInfo* sip =
  96. &visibleSprites[visibleIndex];
  97. Pixel colIndex = sip->colorAttrib & 0x0F;
  98. // Don't draw transparent sprites in sprite mode 1.
  99. // Verified on real V9958: TP bit also has effect in
  100. // sprite mode 1.
  101. if (colIndex == 0 && transparency) continue;
  102. Pixel color = palette[colIndex];
  103. SpriteChecker::SpritePattern pattern = sip->pattern;
  104. int x = sip->x;
  105. // Clip sprite pattern to render range.
  106. if (!clipPattern(x, pattern, minX, maxX)) continue;
  107. // Convert pattern to pixels.
  108. Pixel* p = &pixelPtr[x];
  109. while (pattern) {
  110. // Draw pixel if sprite has a dot.
  111. if (pattern & 0x80000000) {
  112. *p = color;
  113. }
  114. // Advancing behaviour.
  115. pattern <<= 1;
  116. p++;
  117. }
  118. }
  119. }
  120. /** Draw sprites in sprite mode 2.
  121. * Make sure the pixel pointers point to a large enough memory area:
  122. * 256 pixels for ZOOM_256 and ZOOM_REAL in 256-pixel wide modes;
  123. * 512 pixels for ZOOM_REAL in 512-pixel wide modes.
  124. * @param absLine Absolute line number.
  125. * Range is [0..262) for NTSC and [0..313) for PAL.
  126. * @param minX Minimum X coordinate to draw (inclusive).
  127. * @param maxX Maximum X coordinate to draw (exclusive).
  128. * @param pixelPtr Pointer to memory to draw to.
  129. */
  130. template <unsigned MODE>
  131. void drawMode2(int absLine, int minX, int maxX,
  132. Pixel* __restrict pixelPtr) __restrict
  133. {
  134. // Determine sprites visible on this line.
  135. const SpriteChecker::SpriteInfo* visibleSprites;
  136. int visibleIndex =
  137. spriteChecker.getSprites(absLine, visibleSprites);
  138. // Optimisation: return at once if no sprites on this line.
  139. // Lines without any sprites are very common in most programs.
  140. if (visibleIndex == 0) return;
  141. // Sprites with CC=1 are only visible if preceded by a sprite
  142. // with CC=0. Therefor search for first sprite with CC=0.
  143. int first = 0;
  144. do {
  145. if (likely((visibleSprites[first].colorAttrib & 0x40) == 0)) {
  146. break;
  147. }
  148. ++first;
  149. } while (first < visibleIndex);
  150. for (int i = visibleIndex - 1; i >= first; --i) {
  151. const SpriteChecker::SpriteInfo& info = visibleSprites[i];
  152. int x = info.x;
  153. SpriteChecker::SpritePattern pattern = info.pattern;
  154. // Clip sprite pattern to render range.
  155. if (!clipPattern(x, pattern, minX, maxX)) continue;
  156. byte c = info.colorAttrib & 0x0F;
  157. if (c == 0 && transparency) continue;
  158. while (pattern) {
  159. if (pattern & 0x80000000) {
  160. byte color = c;
  161. // Merge in any following CC=1 sprites.
  162. for (int j = i + 1; /*sentinel*/; ++j) {
  163. const SpriteChecker::SpriteInfo& info2 =
  164. visibleSprites[j];
  165. if (!(info2.colorAttrib & 0x40)) break;
  166. unsigned shift2 = x - info2.x;
  167. if ((shift2 < 32) &&
  168. ((info2.pattern << shift2) & 0x80000000)) {
  169. color |= info2.colorAttrib & 0x0F;
  170. }
  171. }
  172. if (MODE == DisplayMode::GRAPHIC5) {
  173. Pixel pixL = palette[color >> 2];
  174. Pixel pixR = palette[color & 3];
  175. pixelPtr[x * 2 + 0] = pixL;
  176. pixelPtr[x * 2 + 1] = pixR;
  177. } else {
  178. Pixel pix = palette[color];
  179. if (MODE == DisplayMode::GRAPHIC6) {
  180. pixelPtr[x * 2 + 0] = pix;
  181. pixelPtr[x * 2 + 1] = pix;
  182. } else {
  183. pixelPtr[x] = pix;
  184. }
  185. }
  186. }
  187. ++x;
  188. pattern <<= 1;
  189. }
  190. }
  191. }
  192. private:
  193. SpriteChecker& spriteChecker;
  194. /** The current sprite palette.
  195. */
  196. const Pixel* palette;
  197. /** VDP transparency setting (R#8, bit5).
  198. */
  199. bool transparency;
  200. /** The current display mode.
  201. */
  202. DisplayMode mode;
  203. };
  204. } // namespace openmsx
  205. #endif