openMSX
SpriteConverter.hh
Go to the documentation of this file.
1 /*
2 TODO:
3 - Implement sprite pixels in Graphic 5.
4 */
5 
6 #ifndef SPRITECONVERTER_HH
7 #define SPRITECONVERTER_HH
8 
9 #include "SpriteChecker.hh"
10 #include "DisplayMode.hh"
11 #include "likely.hh"
12 #include "openmsx.hh"
13 
14 namespace openmsx {
15 
18 template <class Pixel>
20 {
21 public:
22  // TODO: Move some methods to .cc?
23 
29  explicit SpriteConverter(SpriteChecker& spriteChecker_)
30  : spriteChecker(spriteChecker_)
31  {
32  }
33 
37  void setTransparency(bool enabled)
38  {
39  transparency = enabled;
40  }
41 
46  {
47  mode = newMode;
48  }
49 
55  void setPalette(const Pixel* newPalette)
56  {
57  palette = newPalette;
58  }
59 
60  static bool clipPattern(int& x, SpriteChecker::SpritePattern& pattern,
61  int minX, int maxX)
62  {
63  int before = minX - x;
64  if (before > 0) {
65  if (before >= 32) {
66  // 32 pixels before minX -> not visible
67  return false;
68  }
69  pattern <<= before;
70  x = minX;
71  }
72  int after = maxX - x;
73  if (after < 32) {
74  // close to maxX (or past)
75  if (after <= 0) {
76  // past maxX -> not visible
77  return false;
78  }
79  int mask = 0x80000000;
80  pattern &= (mask >> (after - 1));
81  }
82  return true; // visible
83  }
84 
92  void drawMode1(int absLine, int minX, int maxX,
93  Pixel* __restrict pixelPtr) __restrict
94  {
95  // Determine sprites visible on this line.
96  const SpriteChecker::SpriteInfo* visibleSprites;
97  int visibleIndex =
98  spriteChecker.getSprites(absLine, visibleSprites);
99  // Optimisation: return at once if no sprites on this line.
100  // Lines without any sprites are very common in most programs.
101  if (visibleIndex == 0) return;
102 
103  // Render using overdraw.
104  while (visibleIndex--) {
105  // Get sprite info.
106  const SpriteChecker::SpriteInfo* sip =
107  &visibleSprites[visibleIndex];
108  Pixel colIndex = sip->colorAttrib & 0x0F;
109  // Don't draw transparent sprites in sprite mode 1.
110  // TODO: Verify on real V9938 that sprite mode 1 indeed
111  // ignores the transparency bit.
112  if (colIndex == 0) continue;
113  Pixel color = palette[colIndex];
114  SpriteChecker::SpritePattern pattern = sip->pattern;
115  int x = sip->x;
116  // Clip sprite pattern to render range.
117  if (!clipPattern(x, pattern, minX, maxX)) continue;
118  // Convert pattern to pixels.
119  Pixel* p = &pixelPtr[x];
120  while (pattern) {
121  // Draw pixel if sprite has a dot.
122  if (pattern & 0x80000000) {
123  *p = color;
124  }
125  // Advancing behaviour.
126  pattern <<= 1;
127  p++;
128  }
129  }
130  }
131 
142  template <unsigned MODE>
143  void drawMode2(int absLine, int minX, int maxX,
144  Pixel* __restrict pixelPtr) __restrict
145  {
146  // Determine sprites visible on this line.
147  const SpriteChecker::SpriteInfo* visibleSprites;
148  int visibleIndex =
149  spriteChecker.getSprites(absLine, visibleSprites);
150  // Optimisation: return at once if no sprites on this line.
151  // Lines without any sprites are very common in most programs.
152  if (visibleIndex == 0) return;
153 
154  // Sprites with CC=1 are only visible if preceded by a sprite
155  // with CC=0. Therefor search for first sprite with CC=0.
156  int first = 0;
157  do {
158  if (likely((visibleSprites[first].colorAttrib & 0x40) == 0)) {
159  break;
160  }
161  ++first;
162  } while (first < visibleIndex);
163  for (int i = visibleIndex - 1; i >= first; --i) {
164  const SpriteChecker::SpriteInfo& info = visibleSprites[i];
165  int x = info.x;
166  SpriteChecker::SpritePattern pattern = info.pattern;
167  // Clip sprite pattern to render range.
168  if (!clipPattern(x, pattern, minX, maxX)) continue;
169  byte c = info.colorAttrib & 0x0F;
170  if (c == 0 && transparency) continue;
171  while (pattern) {
172  if (pattern & 0x80000000) {
173  byte color = c;
174  // Merge in any following CC=1 sprites.
175  for (int j = i + 1; /*sentinel*/; ++j) {
176  const SpriteChecker::SpriteInfo& info2 =
177  visibleSprites[j];
178  if (!(info2.colorAttrib & 0x40)) break;
179  unsigned shift2 = x - info2.x;
180  if ((shift2 < 32) &&
181  ((info2.pattern << shift2) & 0x80000000)) {
182  color |= info2.colorAttrib & 0x0F;
183  }
184  }
185  if (MODE == DisplayMode::GRAPHIC5) {
186  Pixel pixL = palette[color >> 2];
187  Pixel pixR = palette[color & 3];
188  pixelPtr[x * 2 + 0] = pixL;
189  pixelPtr[x * 2 + 1] = pixR;
190  } else {
191  Pixel pix = palette[color];
192  if (MODE == DisplayMode::GRAPHIC6) {
193  pixelPtr[x * 2 + 0] = pix;
194  pixelPtr[x * 2 + 1] = pix;
195  } else {
196  pixelPtr[x] = pix;
197  }
198  }
199  }
200  ++x;
201  pattern <<= 1;
202  }
203  }
204  }
205 
206 private:
207  SpriteChecker& spriteChecker;
208 
211  const Pixel* palette;
212 
215  bool transparency;
216 
219  DisplayMode mode;
220 };
221 
222 } // namespace openmsx
223 
224 #endif
Utility class for converting VRAM contents to host pixels.
void setDisplayMode(DisplayMode newMode)
Notify SpriteConverter of a display mode change.
SpriteConverter(SpriteChecker &spriteChecker_)
Constructor.
byte colorAttrib
Bit 3..0 are index in palette.
void setPalette(const Pixel *newPalette)
Set palette to use for converting sprites.
void drawMode1(int absLine, int minX, int maxX, Pixel *pixelPtr)
Draw sprites in sprite mode 1.
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
Represents a VDP display mode.
Definition: DisplayMode.hh:14
uint32_t Pixel
void drawMode2(int absLine, int minX, int maxX, Pixel *pixelPtr)
Draw sprites in sprite mode 2.
static bool clipPattern(int &x, SpriteChecker::SpritePattern &pattern, int minX, int maxX)
int getSprites(int line, const SpriteInfo *&visibleSprites) const
Get sprites for a display line.
SpritePattern pattern
Pattern of this sprite line, corrected for magnification.
uint32_t SpritePattern
Bitmap of length 32 describing a sprite pattern.
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
Contains all the information to draw a line of a sprite.
void setTransparency(bool enabled)
Update the transparency setting.
#define likely(x)
Definition: likely.hh:14
int16_t x
X-coordinate of sprite, corrected for early clock.