22 : vdp(vdp_), vram(vdp.getVRAM())
23 , limitSpritesSetting(renderSettings.getLimitSpritesSetting())
24 , frameStartTime(time)
38 updateSpritesMethod = &SpriteChecker::updateSprites1;
47 a = (a | (a >> 8)) & 0xFF00FF00;
48 a = (a | (a >> 4)) & 0xF0F0F0F0;
49 a = (a | (a >> 2)) & 0xCCCCCCCC;
50 a = (a | (a >> 1)) & 0xAAAAAAAA;
55 unsigned patternNr,
unsigned y)
58 unsigned index = patternNr * 8 + y;
61 pattern |= patternPtr[index + 16] << 16;
63 return !vdp.
isSpriteMag() ? pattern : doublePattern(pattern);
66 unsigned patternNr,
unsigned y)
69 unsigned index = patternNr * 8 + y;
70 const byte* patternPtr = (index & 1) ? ptr1 : ptr0;
74 pattern |= patternPtr[index + (16 / 2)] << 16;
76 return !vdp.
isSpriteMag() ? pattern : doublePattern(pattern);
79 void SpriteChecker::updateSprites1(
int limit)
84 checkSprites1(currentLine, limit);
88 if ((currentLine <= l0) && (l0 < limit)) {
89 checkSprites1(l0, l0 + 1);
96 inline void SpriteChecker::checkSprites1(
int minLine,
int maxLine)
120 bool limitSprites = limitSpritesSetting.
getBoolean();
123 int magSize = (mag + 1) *
size;
125 byte patternIndexMask =
size == 16 ? 0xFC : 0xFF;
126 int fifthSpriteNum = -1;
127 int fifthSpriteLine = 999;
130 for (; sprite < 32; ++sprite) {
131 int y = attributePtr[4 * sprite + 0];
134 for (
int line = minLine; line < maxLine; ++line) {
136 int displayLine = line + displayDelta;
137 int spriteLine = (displayLine - y) & 0xFF;
138 if (spriteLine >= magSize) {
140 line += 256 - spriteLine - 1;
144 int visibleIndex = spriteCount[line];
145 if (visibleIndex == 4) {
147 if (line < fifthSpriteLine) {
148 fifthSpriteLine = line;
149 fifthSpriteNum = sprite;
151 if (limitSprites)
continue;
154 SpriteInfo& sip = spriteBuffer[line][visibleIndex];
155 int patternIndex = attributePtr[4 * sprite + 2] & patternIndexMask;
156 if (mag) spriteLine /= 2;
157 sip.
pattern = calculatePatternNP(patternIndex, spriteLine);
158 sip.x = attributePtr[4 * sprite + 1];
159 byte colorAttrib = attributePtr[4 * sprite + 3];
160 if (colorAttrib & 0x80) sip.x -= 32;
161 sip.colorAttrib = colorAttrib;
163 spriteCount[line] = visibleIndex + 1;
169 if (fifthSpriteNum != -1) {
173 if ((status & 0xC0) == 0) {
174 status = 0x40 | (status & 0x20) | fifthSpriteNum;
177 if (~status & 0x40) {
179 status = (status & 0x20) |
std::min(sprite, 31);
208 for (
auto line :
xrange(minLine, maxLine)) {
209 int minXCollision = 999;
210 for (
int i = std::min<int>(4, spriteCount[line]); --i >= 1; ) {
211 auto color1 = spriteBuffer[line][i].
colorAttrib & 0xf;
212 if (!can0collide && (color1 == 0))
continue;
213 int x_i = spriteBuffer[line][i].
x;
215 for (
int j = i; --j >= 0; ) {
216 auto color2 = spriteBuffer[line][j].
colorAttrib & 0xf;
217 if (!can0collide && (color2 == 0))
continue;
219 int x_j = spriteBuffer[line][j].
x;
220 int dist = x_j - x_i;
221 if ((-magSize < dist) && (dist < magSize)) {
231 colPat &= (1 << (32 + x_i)) - 1;
235 assert(xCollision >= 0);
236 minXCollision =
std::min(minXCollision, xCollision);
241 if (minXCollision < 256) {
247 collisionX = minXCollision + 12;
254 void SpriteChecker::updateSprites2(
int limit)
260 checkSprites2(currentLine, limit);
264 if ((currentLine <= l0) && (l0 < limit)) {
265 checkSprites2(l0, l0 + 1);
272 inline void SpriteChecker::checkSprites2(
int minLine,
int maxLine)
282 bool limitSprites = limitSpritesSetting.
getBoolean();
285 int magSize = (mag + 1) *
size;
286 int patternIndexMask = (
size == 16) ? 0xFC : 0xFF;
287 int ninthSpriteNum = -1;
288 int ninthSpriteLine = 999;
294 auto [attributePtr0, attributePtr1] =
297 for (; sprite < 32; ++sprite) {
298 int y = attributePtr0[2 * sprite + 0];
301 for (
int line = minLine; line < maxLine; ++line) {
303 int displayLine = line + displayDelta;
304 int spriteLine = (displayLine - y) & 0xFF;
305 if (spriteLine >= magSize) {
307 line += 256 - spriteLine - 1;
311 int visibleIndex = spriteCount[line];
312 if (visibleIndex == 8) {
314 if (line < ninthSpriteLine) {
315 ninthSpriteLine = line;
316 ninthSpriteNum = sprite;
318 if (limitSprites)
continue;
321 if (mag) spriteLine /= 2;
322 int colorIndex = (~0u << 10) | (sprite * 16 + spriteLine);
326 SpriteInfo& sip = spriteBuffer[line][visibleIndex];
327 int patternIndex = attributePtr0[2 * sprite + 1] & patternIndexMask;
328 sip.
pattern = calculatePatternPlanar(patternIndex, spriteLine);
329 sip.x = attributePtr1[2 * sprite + 0];
330 if (colorAttrib & 0x80) sip.x -= 32;
331 sip.colorAttrib = colorAttrib;
334 spriteBuffer[line][visibleIndex + 1].
colorAttrib = 0;
335 spriteCount[line] = visibleIndex + 1;
339 const byte* attributePtr0 =
342 for (; sprite < 32; ++sprite) {
343 int y = attributePtr0[4 * sprite + 0];
346 for (
int line = minLine; line < maxLine; ++line) {
348 int displayLine = line + displayDelta;
349 int spriteLine = (displayLine - y) & 0xFF;
350 if (spriteLine >= magSize) {
352 line += 256 - spriteLine - 1;
356 int visibleIndex = spriteCount[line];
357 if (visibleIndex == 8) {
359 if (line < ninthSpriteLine) {
360 ninthSpriteLine = line;
361 ninthSpriteNum = sprite;
363 if (limitSprites)
continue;
366 if (mag) spriteLine /= 2;
367 int colorIndex = (~0u << 10) | (sprite * 16 + spriteLine);
376 SpriteInfo& sip = spriteBuffer[line][visibleIndex];
377 int patternIndex = attributePtr0[4 * sprite + 2] & patternIndexMask;
378 sip.
pattern = calculatePatternNP(patternIndex, spriteLine);
379 sip.x = attributePtr0[4 * sprite + 1];
380 if (colorAttrib & 0x80) sip.x -= 32;
381 sip.colorAttrib = colorAttrib;
391 spriteBuffer[line][visibleIndex + 1].
colorAttrib = 0;
392 spriteCount[line] = visibleIndex + 1;
399 if (ninthSpriteNum != -1) {
404 if ((status & 0xC0) == 0) {
405 status = 0x40 | (status & 0x20) | ninthSpriteNum;
408 if (~status & 0x40) {
410 status = (status & 0x20) |
std::min(sprite, 31);
441 for (
auto line :
xrange(minLine, maxLine)) {
442 int minXCollision = 999;
443 SpriteInfo* visibleSprites = spriteBuffer[line];
444 for (
int i = std::min<int>(8, spriteCount[line]); --i >= 1; ) {
446 if (!can0collide && ((colorAttrib1 & 0xf) == 0))
continue;
448 if (colorAttrib1 & 0x60)
continue;
450 int x_i = visibleSprites[i].x;
452 for (
int j = i; --j >= 0; ) {
453 auto colorAttrib2 = visibleSprites[j].colorAttrib;
454 if (!can0collide && ((colorAttrib2 & 0xf) == 0))
continue;
456 if (colorAttrib2 & 0x60)
continue;
459 int x_j = visibleSprites[j].x;
460 int dist = x_j - x_i;
461 if ((-magSize < dist) && (dist < magSize)) {
471 colPat &= (1 << (32 + x_i)) - 1;
475 assert(xCollision >= 0);
476 minXCollision =
std::min(minXCollision, xCollision);
481 if (minXCollision < 256) {
485 collisionX = minXCollision + 12;
494 template<
typename Archive>
512 ar.serialize(
"collisionX", collisionX,
513 "collisionY", collisionY);
514 if (ar.versionAtLeast(version, 2)) {
515 ar.serialize(
"currentLine", currentLine);
bool getBoolean() const noexcept
constexpr void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
Class containing all settings for renderers.
void frameStart(EmuTime::param time)
Signals the start of a new frame.
void reset(EmuTime::param time)
Puts the sprite checker in its initial state.
void serialize(Archive &ar, unsigned version)
uint32_t SpritePattern
Bitmap of length 32 describing a sprite pattern.
SpriteChecker(VDP &vdp, RenderSettings &renderSettings, EmuTime::param time)
Create a sprite checker.
VRAMWindow spriteAttribTable
VRAMWindow spritePatternTable
Unified implementation of MSX Video Display Processors (VDPs).
int getSpriteSize() const
Gets the sprite size in pixels (8/16).
byte getStatusReg0() const
Should only be used by SpriteChecker.
bool spritesEnabledFast() const
Same as spritesEnabled(), but may only be called in sprite mode 1 or 2.
void setSpriteStatus(byte value)
Should only be used by SpriteChecker.
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
int getLineZero() const
Get the absolute line number of display line zero.
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
EmuTime::param getFrameStartTime() const
bool canSpriteColor0Collide() const
Can a sprite which has color=0 collide with some other sprite?
bool isSpriteMag() const
Are sprites magnified?
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
byte readNP(unsigned index) const
Reads a byte from VRAM in its current state.
byte readPlanar(unsigned index) const
Similar to readNP, but now with planar addressing.
const byte * getReadArea(unsigned index, unsigned size) const
Gets a pointer to a contiguous part of the VRAM.
void setObserver(VRAMObserver *newObserver)
Register an observer on this VRAM window.
std::pair< const byte *, const byte * > getReadAreaPlanar(unsigned index, unsigned size) const
Similar to getReadArea(), but now with planar addressing mode.
constexpr unsigned countLeadingZeros(unsigned x)
Count the number of leading zero-bits in the given word.
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
This file implemented 3 utility functions:
void fill(ForwardRange &&range, const T &value)
size_t size(std::string_view utf8)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
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.
constexpr auto xrange(T e)