openMSX
SpriteConverter.hh
Go to the documentation of this file.
1/*
2TODO:
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 "openmsx.hh"
12#include <concepts>
13
14namespace openmsx {
15
18template<std::unsigned_integral Pixel>
20{
21public:
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 // Verified on real V9958: TP bit also has effect in
111 // sprite mode 1.
112 if (colIndex == 0 && transparency) continue;
113 Pixel color = palette[colIndex];
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 ((visibleSprites[first].colorAttrib & 0x40) == 0) [[likely]] {
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;
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 constexpr (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 constexpr (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
206private:
207 SpriteChecker& spriteChecker;
208
211 const Pixel* palette;
212
215 bool transparency;
216
219 DisplayMode mode;
220};
221
222} // namespace openmsx
223
224#endif
Represents a VDP display mode.
Definition: DisplayMode.hh:16
uint32_t SpritePattern
Bitmap of length 32 describing a sprite pattern.
int getSprites(int line, const SpriteInfo *&visibleSprites) const
Get sprites for a display line.
Utility class for converting VRAM contents to host pixels.
SpriteConverter(SpriteChecker &spriteChecker_)
Constructor.
void drawMode2(int absLine, int minX, int maxX, Pixel *pixelPtr)
Draw sprites in sprite mode 2.
void drawMode1(int absLine, int minX, int maxX, Pixel *pixelPtr)
Draw sprites in sprite mode 1.
void setPalette(const Pixel *newPalette)
Set palette to use for converting sprites.
void setTransparency(bool enabled)
Update the transparency setting.
void setDisplayMode(DisplayMode newMode)
Notify SpriteConverter of a display mode change.
static bool clipPattern(int &x, SpriteChecker::SpritePattern &pattern, int minX, int maxX)
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint32_t Pixel
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:127
constexpr nibble mask[4][13]
Definition: RP5C01.cc:34
Contains all the information to draw a line of a sprite.
SpritePattern pattern
Pattern of this sprite line, corrected for magnification.
byte colorAttrib
Bit 3..0 are index in palette.
int16_t x
X-coordinate of sprite, corrected for early clock.