[Scummvm-git-logs] scummvm master -> 9fca5a7789acdc3a03051e62a91cd5be98bd7825
dreammaster
noreply at scummvm.org
Tue Feb 10 05:55:54 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
9fca5a7789 MM: XEEN: Replaced SpriteDrawer class
Commit: 9fca5a7789acdc3a03051e62a91cd5be98bd7825
https://github.com/scummvm/scummvm/commit/9fca5a7789acdc3a03051e62a91cd5be98bd7825
Author: PaweŠGóralski (20125592+n0kturnal at users.noreply.github.com)
Date: 2026-02-10T16:54:39+11:00
Commit Message:
MM: XEEN: Replaced SpriteDrawer class
Replaced oop code with single function without virtual drawPixel() function calls,
new / delete operators are not needed, reduced number of internal checks done
previously several times per pixel draw internally in SpriteDrawer subclasses.
Static constants are now local. Speeds up rendering on slower machines
(like Atari TOS). I've tried to replicate original code intent and most variables
are named nearly the same unless there was clash between interface variables
and internals.
Changed paths:
engines/mm/shared/xeen/sprites.cpp
engines/mm/shared/xeen/sprites.h
diff --git a/engines/mm/shared/xeen/sprites.cpp b/engines/mm/shared/xeen/sprites.cpp
index 73ade399541..26733654ea9 100644
--- a/engines/mm/shared/xeen/sprites.cpp
+++ b/engines/mm/shared/xeen/sprites.cpp
@@ -128,115 +128,126 @@ void SpriteResource::clear() {
_index.clear();
}
+/**
+ * Scale a co-ordinate value based on the passed scaling mask
+*/
+static inline uint getScaledVal(int xy, uint16 &scaleMask) {
+ if (!xy)
+ return 0;
+
+ uint result = 0;
+ for (int idx = 0; idx < xy; ++idx) {
+ uint bit = (scaleMask >> 15) & 1;
+ scaleMask = ((scaleMask & 0x7fff) << 1) + bit;
+ result += bit;
+ }
+
+ return result;
+}
+
void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos,
- uint flags, int scale) const {
+ uint flags, int scale) const {
draw(dest, frame, destPos, Common::Rect(0, 0, dest.w, dest.h), flags, scale);
}
-void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos,
- const Common::Rect &bounds, uint flags, int scale) const {
- Common::Rect r = bounds;
- if (flags & SPRFLAG_BOTTOM_CLIPPED)
- r.clip(SCREEN_WIDTH, _clippedBottom);
+static inline void drawPixel2(byte *dest, const byte pixel, byte *destLeft, byte *destRight, byte *destTop, byte *destBottom, int pitch, uint16 &random1, uint16 &random2, uint16 mask1, uint16 mask2) {
+ static const int8 DRAWER2_DELTA[64] = {
+ -3, 3, 0, 0, 0, 0, 0, 0,
+ -5, 5, 0, 0, 0, 0, 0, 0,
+ -7, 7, 0, 0, 0, 0, 0, 0,
+ -9, 9, 0, 0, 0, 0, 0, 0,
+ -7, 7, 0, 0, 0, 0, 0, 0,
+ -9, 9, 0, 0, 0, 0, 0, 0,
+ -11, 11, 0, 0, 0, 0, 0, 0,
+ -13, 13, 0, 0, 0, 0, 0, 0
+ };
- // Create drawer to handle the rendering
- SpriteDrawer *drawer;
- switch (flags & SPRFLAG_MODE_MASK) {
- case SPRFLAG_DRAWER1:
- drawer = new SpriteDrawer1(_data, _filesize, flags & 0x1F);
- break;
- case SPRFLAG_DRAWER2:
- drawer = new SpriteDrawer2(_data, _filesize, flags & 0x1F);
- break;
- case SPRFLAG_DRAWER3:
- drawer = new SpriteDrawer3(_data, _filesize, flags & 0x1F);
- break;
- case SPRFLAG_DRAWER5:
- drawer = new SpriteDrawer5(_data, _filesize, flags & 0x1F);
- break;
- case SPRFLAG_DRAWER6:
- drawer = new SpriteDrawer6(_data, _filesize, flags & 0x1F);
- break;
- default:
- drawer = new SpriteDrawer(_data, _filesize);
- break;
- }
+ bool flag = (random1 & 0x8000) != 0;
+ random1 = (int)((uint16)random1 << 1) - random2 - (flag ? 1 : 0);
- // WORKAROUND: Crash clicking Vertigo well in Clouds
- if (frame < (int)_index.size()) {
- if (!_index[frame]._override.empty()) {
- const Graphics::ManagedSurface &src = _index[frame]._override;
- if (flags & Shared::Xeen::SPRFLAG_RESIZE)
- dest.create(src.w, src.h);
- dest.blitFrom(src, destPos);
- } else {
- // Sprites can consist of separate background & foreground
- drawer->draw(dest, _index[frame]._offset1, destPos, r, flags, scale);
- if (_index[frame]._offset2)
- drawer->draw(dest, _index[frame]._offset2, destPos, r, flags, scale);
+ bool newCf = (random2 & 1);
+ random2 = (random2 >> 1) | (flag ? 0x8000 : 0);
+ flag = newCf;
+
+ newCf = (random2 & 1);
+ random2 = (random2 >> 1) | (flag ? 0x8000 : 0);
+ flag = newCf;
+
+ random2 ^= random1;
+
+ dest += DRAWER2_DELTA[(random2 & mask1 & mask2) / 2];
+ if (dest >= destLeft && dest < destRight) {
+ dest += pitch * DRAWER2_DELTA[((random2 >> 8) & mask1 & mask2) / 2];
+
+ if (dest >= destTop && dest < destBottom) {
+ *dest = pixel;
}
}
-
- delete drawer;
}
-void SpriteResource::draw(XSurface &dest, int frame) const {
- draw(dest, frame, Common::Point());
-}
+static inline void drawPixel3(byte *dest, const byte pixel, const uint16 mask, const uint16 offset, byte *palette) {
+ // WORKAROUND: This is slightly different then the original:
+ // 1) The original has bunches of black pixels appearing. This does index increments to avoid such pixels
+ // 2) It also prevents any pixels being drawn in the single initial frame until the palette is set
+ const byte level = (pixel & mask) - offset + (*dest & 0xf);
-void SpriteResource::draw(Graphics::ManagedSurface *dest, int frame, const Common::Point &destPos) const {
- XSurface tmp;
- tmp.w = dest->w;
- tmp.h = dest->h;
- tmp.pitch = dest->pitch;
- tmp.format = dest->format;
- tmp.setPixels(dest->getPixels());
+ if (level >= 0x80) {
+ *dest &= 0xf0;
+ } else if (level <= 0xf) {
+ *dest = (*dest & 0xf0) | level;
+ } else {
+ *dest |= 0xf;
+ }
- draw(tmp, frame, destPos);
+ //
+ while (*dest < 0xff && !palette[*dest * 3] && !palette[*dest * 3 + 1] && !palette[*dest * 3 + 2])
+ ++ *dest;
}
+static inline void drawPixel5(byte *dest, const byte pixel, const uint16 threshold, uint16 &random1, uint16 &random2) {
+ bool flag = (random1 & 0x8000) != 0;
+ random1 = (int)((uint16)random1 << 1) - random2 - (flag ? 1 : 0);
-Common::Point SpriteResource::getFrameSize(int frame) const {
- Common::MemoryReadStream f(_data, _filesize);
- Common::Point frameSize;
+ bool newCf = (random2 & 1);
+ random2 = (random2 >> 1) | (flag ? 0x8000 : 0);
+ flag = newCf;
- for (int idx = 0; idx < (_index[frame]._offset2 ? 2 : 1); ++idx) {
- f.seek((idx == 0) ? _index[frame]._offset1 : _index[frame]._offset2);
- int xOffset = f.readUint16LE();
- int width = f.readUint16LE();
- int yOffset = f.readUint16LE();
- int height = f.readUint16LE();
+ newCf = (random2 & 1);
+ random2 = (random2 >> 1) | (flag ? 0x8000 : 0);
+ flag = newCf;
- frameSize.x = MAX((int)frameSize.x, xOffset + width);
- frameSize.y = MAX((int)frameSize.y, yOffset + height);
- }
+ random2 ^= random1;
- return frameSize;
+ if (random2 > threshold)
+ *dest = pixel;
}
-/*------------------------------------------------------------------------*/
+static inline void drawSprite(byte *data, size_t filesize, XSurface &dest, uint16 offset, const Common::Point &pt, const Common::Rect &clipRect, uint flags, int scale) {
+ // regular drawer
+ const SpriteFlags drawerFlag = static_cast<SpriteFlags>(flags & SPRFLAG_MODE_MASK);
+
+ byte *destTop = nullptr, *destBottom = nullptr;
+ byte *destLeft = nullptr, *destRight = nullptr;
+ int pitch = 0;
-void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
- const Common::Rect &clipRect, uint flags, int scale) {
static const uint SCALE_TABLE[] = {
0xFFFF, 0xFFEF, 0xEFEF, 0xEFEE, 0xEEEE, 0xEEAE, 0xAEAE, 0xAEAA,
0xAAAA, 0xAA8A, 0x8A8A, 0x8A88, 0x8888, 0x8880, 0x8080, 0x8000
};
- static const int PATTERN_STEPS[] = { 0, 1, 1, 1, 2, 2, 3, 3, 0, -1, -1, -1, -2, -2, -3, -3 };
assert((scale & SCALE_MASK) < 16);
uint16 scaleMask = SCALE_TABLE[scale & SCALE_MASK];
uint16 scaleMaskX = scaleMask, scaleMaskY = scaleMask;
- bool flipped = (flags & SPRFLAG_HORIZ_FLIPPED) != 0;
+ const bool flipped = (flags & SPRFLAG_HORIZ_FLIPPED) != 0;
int xInc = flipped ? -1 : 1;
- bool enlarge = (scale & SCALE_ENLARGE) != 0;
+ const bool enlarge = (scale & SCALE_ENLARGE) != 0;
- _destTop = (byte *)dest.getBasePtr(clipRect.left, clipRect.top);
- _destBottom = (byte *)dest.getBasePtr(clipRect.right, clipRect.bottom - 1);
- _pitch = dest.pitch;
+ destTop = (byte *)dest.getBasePtr(clipRect.left, clipRect.top);
+ destBottom = (byte *)dest.getBasePtr(clipRect.right, clipRect.bottom - 1);
+ pitch = dest.pitch;
// Get cell header
- Common::MemoryReadStream f(_data, _filesize);
+ Common::MemoryReadStream f(data, filesize);
f.seek(offset);
int xOffset = f.readUint16LE();
int width = f.readUint16LE();
@@ -306,9 +317,10 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
// Build up the line
int byteCount, opr1, opr2;
int32 pos;
- for (byteCount = 1; byteCount < lineLength; ) {
+ for (byteCount = 1; byteCount < lineLength;) {
// The next byte is an opcode that determines what operators are to follow and how to interpret them.
- int opcode = f.readByte(); ++byteCount;
+ int opcode = f.readByte();
+ ++byteCount;
// Decode the opcode
int len = opcode & 0x1F;
@@ -325,7 +337,8 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
break;
case 2: // The following byte is an index into the color table, draw it len + 3 times.
- opr1 = f.readByte(); ++byteCount;
+ opr1 = f.readByte();
+ ++byteCount;
for (int i = 0; i < len + 3; ++i) {
*lineP = opr1;
lineP += xInc;
@@ -333,7 +346,8 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
break;
case 3: // Stream copy command.
- opr1 = f.readUint16LE(); byteCount += 2;
+ opr1 = f.readUint16LE();
+ byteCount += 2;
pos = f.pos();
f.seek(-opr1, SEEK_CUR);
@@ -346,8 +360,10 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
break;
case 4: // The following two bytes are indexes into the color table, draw the pair len + 2 times.
- opr1 = f.readByte(); ++byteCount;
- opr2 = f.readByte(); ++byteCount;
+ opr1 = f.readByte();
+ ++byteCount;
+ opr2 = f.readByte();
+ ++byteCount;
for (int i = 0; i < len + 2; ++i) {
*lineP = opr1;
lineP += xInc;
@@ -361,19 +377,23 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
break;
case 6: // Pattern command.
- case 7:
+ case 7: {
+
// The pattern command has a different opcode format
+ static const int PATTERN_STEPS[] = {0, 1, 1, 1, 2, 2, 3, 3, 0, -1, -1, -1, -2, -2, -3, -3};
+
len = opcode & 0x07;
cmd = (opcode >> 2) & 0x0E;
- opr1 = f.readByte(); ++byteCount;
+ opr1 = f.readByte();
+ ++byteCount;
for (int i = 0; i < len + 3; ++i) {
*lineP = opr1;
lineP += xInc;
opr1 += PATTERN_STEPS[cmd + (i % 2)];
}
- break;
-
+ }
+ break;
default:
break;
}
@@ -385,13 +405,15 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
// Handle drawing out the line
byte *destP = (byte *)dest.getBasePtr(destPos.x, destPos.y);
- _destLeft = (byte *)dest.getBasePtr(
- (flags & SPRFLAG_SCENE_CLIPPED) ? SCENE_CLIP_LEFT : clipRect.left, destPos.y);
- _destRight = (byte *)dest.getBasePtr(
- (flags & SPRFLAG_SCENE_CLIPPED) ? SCENE_CLIP_RIGHT : clipRect.right, destPos.y);
+ destLeft = (byte *)dest.getBasePtr(
+ (flags & SPRFLAG_SCENE_CLIPPED) ? SCENE_CLIP_LEFT : clipRect.left, destPos.y);
+ destRight = (byte *)dest.getBasePtr(
+ (flags & SPRFLAG_SCENE_CLIPPED) ? SCENE_CLIP_RIGHT : clipRect.right, destPos.y);
int16 xp = destPos.x;
lineP = &tempLine[SCREEN_WIDTH];
+ const byte idx = flags & 0x1F;
+
for (int xCtr = 0; xCtr < width; ++xCtr, ++lineP) {
bit = (scaleMaskX >> 15) & 1;
scaleMaskX = ((scaleMaskX & 0x7fff) << 1) + bit;
@@ -402,12 +424,154 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
if (*lineP != -1 && xp >= bounds.left && xp < bounds.right) {
drawBounds.left = MIN(drawBounds.left, xp);
drawBounds.right = MAX((int)drawBounds.right, xp + 1);
- drawPixel(destP, (byte)*lineP);
- if (enlarge) {
- drawPixel(destP + SCREEN_WIDTH, (byte)*lineP);
- drawPixel(destP + 1, (byte)*lineP);
- drawPixel(destP + 1 + SCREEN_WIDTH, (byte)*lineP);
+
+ switch (drawerFlag) {
+ case SPRFLAG_DRAWER1: {
+ // Draw a sprite frame based on a passed offset into the data stream
+ static const byte DRAWER1_OFFSET[24] = {
+ 0x30, 0xC0, 0xB0, 0x10, 0x41, 0x20, 0x40, 0x21, 0x48, 0x46, 0x43, 0x40,
+ 0xD0, 0xD3, 0xD6, 0xD8, 0x01, 0x04, 0x07, 0x0A, 0xEA, 0xEE, 0xF2, 0xF6
+ };
+
+ static const byte DRAWER1_MASK[24] = {
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07
+ };
+
+ const byte offset1 = DRAWER1_OFFSET[idx];
+ const byte mask = DRAWER1_MASK[idx];
+ const byte pixel = (((byte)*lineP) & mask) + offset1;
+
+ (*destP) = pixel;
+
+ if (enlarge) {
+ *(destP + SCREEN_WIDTH) = pixel;
+ *(destP + 1) = pixel;
+ *(destP + 1 + SCREEN_WIDTH) = pixel;
+ }
+ }
+ break;
+ case SPRFLAG_DRAWER2: {
+ // Scrambles up the sprite by drawing many of the pixels randomly at a horizontal or vertical offset
+ static const byte DRAWER2_MASK1[32] = {
+ 3, 0, 3, 0, 3, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static const byte DRAWER2_MASK2[16] = {
+ 0x7E, 0x7E, 0x7E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E,
+ 0x1E, 0x1E, 0x1E, 0x1E, 0x0E, 0x0E, 0x0E, 0x0E
+ };
+
+ const uint16 mask21 = DRAWER2_MASK1[idx];
+ const uint16 mask22 = DRAWER2_MASK2[idx];
+
+ MM::MMEngine *engine = static_cast<MM::MMEngine *>(g_engine);
+ assert(engine != nullptr);
+
+ uint16 random1 = engine->getRandomNumber(0xffff);
+ uint16 random2 = engine->getRandomNumber(0xffff);
+ const byte pixel = (byte)*lineP;
+
+ drawPixel2(destP, pixel, destLeft, destRight, destTop, destBottom, pitch, random1, random2, mask21, mask22);
+
+ if (enlarge) {
+ drawPixel2(destP + SCREEN_WIDTH, pixel, destLeft, destRight, destTop, destBottom, pitch, random1, random2, mask21, mask22);
+ drawPixel2(destP + 1, pixel, destLeft, destRight, destTop, destBottom, pitch, random1, random2, mask21, mask22);
+ drawPixel2(destP + 1 + SCREEN_WIDTH, pixel, destLeft, destRight, destTop, destBottom, pitch, random1, random2, mask21, mask22);
+ }
}
+ break;
+ case SPRFLAG_DRAWER3: {
+ // Draws the sprite as faint ghostly, see-through.
+ static const uint16 DRAWER3_MASK[4] = { 1, 3, 7, 15 };
+ static const uint16 DRAWER3_OFFSET[4] = { 1, 2, 4, 8 };
+
+ const uint16 offsetLocal = DRAWER3_OFFSET[idx];
+ const uint16 mask = DRAWER3_MASK[idx];
+
+ byte palette[256 * 3];
+ g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT);
+
+ bool hasPalette = false;
+ for (byte *pal = palette; pal < palette + PALETTE_SIZE && !hasPalette; ++pal) {
+ hasPalette = *pal != 0;
+ }
+
+ // nothing to do if hasPalette is true
+ if (hasPalette) {
+ const byte pixel = (byte)*lineP;
+ drawPixel3(destP, pixel, mask, offsetLocal, palette);
+
+ if (enlarge) {
+ drawPixel3(destP + SCREEN_WIDTH, pixel, mask, offsetLocal, palette);
+ drawPixel3(destP + 1, pixel, mask, offsetLocal, palette);
+ drawPixel3(destP + 1 + SCREEN_WIDTH, pixel, mask, offsetLocal, palette);
+ }
+ }
+ }
+ break;
+ case SPRFLAG_DRAWER4: {
+ static const byte DRAWER4_THRESHOLD[4] = { 4, 7, 10, 13 };
+ const byte threshold = DRAWER4_THRESHOLD[idx];
+ const byte pixel = (byte)*lineP;
+
+ if ((pixel & 0xf) >= threshold) {
+ *destP = pixel;
+
+ if (enlarge) {
+ *(destP + SCREEN_WIDTH) = pixel;
+ *(destP + 1) = pixel;
+ *(destP + 1 + SCREEN_WIDTH) = pixel;
+ }
+ }
+ }
+ break;
+ case SPRFLAG_DRAWER5: {
+ // Draws a sprite with a fuzziness effect where only some pixels of the sprite are randomly drawn
+ static const uint16 DRAWER5_THRESHOLD[4] = { 0x3333, 0x6666, 0x999A, 0xCCCD };
+ static const uint16 threshold = DRAWER5_THRESHOLD[idx];
+
+ MM::MMEngine *engine = static_cast<MM::MMEngine *>(g_engine);
+ uint16 random1 = engine->getRandomNumber(0xffff);
+ uint16 random2 = engine->getRandomNumber(0xffff);
+
+ const byte pixel = (byte)*lineP;
+ drawPixel5(destP, pixel, threshold, random1, random2);
+
+ if (enlarge) {
+ drawPixel5(destP + SCREEN_WIDTH, pixel, threshold, random1, random2);
+ drawPixel5(destP + 1, pixel, threshold, random1, random2);
+ drawPixel5(destP + 1 + SCREEN_WIDTH, pixel, threshold, random1, random2);
+ }
+ }
+ break;
+ case SPRFLAG_DRAWER6: {
+ static const byte DRAWER6_MASK[16] = { 1, 2, 4, 8, 1, 3, 7, 15, 8, 12, 14, 15, 1, 2, 1, 2 };
+ const byte mask = DRAWER6_MASK[idx];
+ const byte pixel = (byte)*lineP ^ mask;
+
+ *destP = pixel;
+
+ if (enlarge) {
+ *(destP + SCREEN_WIDTH) = pixel;
+ *(destP + 1) = pixel;
+ *(destP + 1 + SCREEN_WIDTH) = pixel;
+ }
+ }
+ break;
+ default: {
+ const byte pixel = (byte)*lineP;
+ *destP = pixel;
+
+ if (enlarge) {
+ *(destP + SCREEN_WIDTH) = pixel;
+ *(destP + 1) = pixel;
+ *(destP + 1 + SCREEN_WIDTH) = pixel;
+ }
+ }
+ break;
+ };
}
++xp;
@@ -430,186 +594,66 @@ void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt,
if (!drawBounds.isEmpty())
dest.addDirtyRect(drawBounds);
}
-}
-uint SpriteDrawer::getScaledVal(int xy, uint16 &scaleMask) {
- if (!xy)
- return 0;
-
- uint result = 0;
- for (int idx = 0; idx < xy; ++idx) {
- uint bit = (scaleMask >> 15) & 1;
- scaleMask = ((scaleMask & 0x7fff) << 1) + bit;
- result += bit;
- }
-
- return result;
-}
-
-void SpriteDrawer::drawPixel(byte *dest, byte pixel) {
- *dest = pixel;
-}
-
-void SpriteDrawer::rcr(uint16 &val, bool &cf) {
- bool newCf = (val & 1);
- val = (val >> 1) | (cf ? 0x8000 : 0);
- cf = newCf;
}
-/*------------------------------------------------------------------------*/
-
-static const byte DRAWER1_OFFSET[24] = {
- 0x30, 0xC0, 0xB0, 0x10, 0x41, 0x20, 0x40, 0x21, 0x48, 0x46, 0x43, 0x40,
- 0xD0, 0xD3, 0xD6, 0xD8, 0x01, 0x04, 0x07, 0x0A, 0xEA, 0xEE, 0xF2, 0xF6
-};
-
-static const byte DRAWER1_MASK[24] = {
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07
-};
-
-SpriteDrawer1::SpriteDrawer1(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) {
- _offset = DRAWER1_OFFSET[index];
- _mask = DRAWER1_MASK[index];
-}
-
-void SpriteDrawer1::drawPixel(byte *dest, byte pixel) {
- *dest = (pixel & _mask) + _offset;
-}
-
-/*------------------------------------------------------------------------*/
-
-static const byte DRAWER2_MASK1[32] = {
- 3, 0, 3, 0, 3, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0,
- 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static const byte DRAWER2_MASK2[16] = {
- 0x7E, 0x7E, 0x7E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E,
- 0x1E, 0x1E, 0x1E, 0x1E, 0x0E, 0x0E, 0x0E, 0x0E
-};
-
-static const int8 DRAWER2_DELTA[64] = {
- -3, 3, 0, 0, 0, 0, 0, 0,
- -5, 5, 0, 0, 0, 0, 0, 0,
- -7, 7, 0, 0, 0, 0, 0, 0,
- -9, 9, 0, 0, 0, 0, 0, 0,
- -7, 7, 0, 0, 0, 0, 0, 0,
- -9, 9, 0, 0, 0, 0, 0, 0,
- -11, 11, 0, 0, 0, 0, 0, 0,
- -13, 13, 0, 0, 0, 0, 0, 0
-};
-
-SpriteDrawer2::SpriteDrawer2(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) {
- _mask1 = DRAWER2_MASK1[index];
- _mask2 = DRAWER2_MASK2[index];
-
- MM::MMEngine *engine = static_cast<MM::MMEngine *>(g_engine);
- _random1 = engine->getRandomNumber(0xffff);
- _random2 = engine->getRandomNumber(0xffff);
-}
-
-void SpriteDrawer2::drawPixel(byte *dest, byte pixel) {
- bool flag = (_random1 & 0x8000) != 0;
- _random1 = (int)((uint16)_random1 << 1) - _random2 - (flag ? 1 : 0);
-
- rcr(_random2, flag);
- rcr(_random2, flag);
- _random2 ^= _random1;
-
- dest += DRAWER2_DELTA[(_random2 & _mask1 & _mask2) / 2];
- if (dest >= _destLeft && dest < _destRight) {
- dest += _pitch * DRAWER2_DELTA[((_random2 >> 8) &_mask1 &_mask2) / 2];
+void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos, const Common::Rect &bounds, uint flags, int scale) const {
+ Common::Rect r = bounds;
- if (dest >= _destTop && dest < _destBottom) {
- *dest = pixel;
- }
+ if (flags & SPRFLAG_BOTTOM_CLIPPED) {
+ r.clip(SCREEN_WIDTH, _clippedBottom);
}
-}
-
-/*------------------------------------------------------------------------*/
-
-static const uint16 DRAWER3_MASK[4] = { 1, 3, 7, 15 };
-static const uint16 DRAWER3_OFFSET[4] = { 1, 2, 4, 8 };
-
-SpriteDrawer3::SpriteDrawer3(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) {
- _offset = DRAWER3_OFFSET[index];
- _mask = DRAWER3_MASK[index];
-
- g_system->getPaletteManager()->grabPalette(_palette, 0, PALETTE_COUNT);
- _hasPalette = false;
- for (byte *pal = _palette; pal < _palette + PALETTE_SIZE && !_hasPalette; ++pal)
- _hasPalette = *pal != 0;
-}
-
-void SpriteDrawer3::drawPixel(byte *dest, byte pixel) {
- // WORKAROUND: This is slightly different then the original:
- // 1) The original has bunches of black pixels appearing. This does index increments to avoid such pixels
- // 2) It also prevents any pixels being drawn in the single initial frame until the palette is set
- if (_hasPalette) {
- byte level = (pixel & _mask) - _offset + (*dest & 0xf);
- if (level >= 0x80) {
- *dest &= 0xf0;
- } else if (level <= 0xf) {
- *dest = (*dest & 0xf0) | level;
+ // WORKAROUND: Crash clicking Vertigo well in Clouds
+ if (frame < (int)_index.size()) {
+ if (!_index[frame]._override.empty()) {
+ const Graphics::ManagedSurface &src = _index[frame]._override;
+ if (flags & Shared::Xeen::SPRFLAG_RESIZE)
+ dest.create(src.w, src.h);
+ dest.blitFrom(src, destPos);
} else {
- *dest |= 0xf;
- }
+ // Sprites can consist of separate background & foreground
+ drawSprite(_data, _filesize, dest, _index[frame]._offset1, destPos, r, flags, scale);
- //
- while (*dest < 0xff && !_palette[*dest * 3] && !_palette[*dest * 3 + 1] && !_palette[*dest * 3 + 2])
- ++ *dest;
+ if (_index[frame]._offset2) {
+ drawSprite(_data, _filesize, dest, _index[frame]._offset2, destPos, r, flags, scale);
+ }
+ }
}
}
-/*------------------------------------------------------------------------*/
-
-static const byte DRAWER4_THRESHOLD[4] = { 4, 7, 10, 13 };
-
-SpriteDrawer4::SpriteDrawer4(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) {
- _threshold = DRAWER4_THRESHOLD[index];
-}
-
-void SpriteDrawer4::drawPixel(byte *dest, byte pixel) {
- if ((pixel & 0xf) >= _threshold)
- *dest = pixel;
+void SpriteResource::draw(XSurface &dest, int frame) const {
+ draw(dest, frame, Common::Point());
}
-/*------------------------------------------------------------------------*/
-
-static const uint16 DRAWER5_THRESHOLD[4] = { 0x3333, 0x6666, 0x999A, 0xCCCD };
-
-SpriteDrawer5::SpriteDrawer5(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) {
- _threshold = DRAWER5_THRESHOLD[index];
+void SpriteResource::draw(Graphics::ManagedSurface *dest, int frame, const Common::Point &destPos) const {
+ XSurface tmp;
+ tmp.w = dest->w;
+ tmp.h = dest->h;
+ tmp.pitch = dest->pitch;
+ tmp.format = dest->format;
+ tmp.setPixels(dest->getPixels());
- MM::MMEngine *engine = static_cast<MM::MMEngine *>(g_engine);
- _random1 = engine->getRandomNumber(0xffff);
- _random2 = engine->getRandomNumber(0xffff);
+ draw(tmp, frame, destPos);
}
-void SpriteDrawer5::drawPixel(byte *dest, byte pixel) {
- bool flag = (_random1 & 0x8000) != 0;
- _random1 = (int)((uint16)_random1 << 1) - _random2 - (flag ? 1 : 0);
-
- rcr(_random2, flag);
- rcr(_random2, flag);
- _random2 ^= _random1;
-
- if (_random2 > _threshold)
- *dest = pixel;
-}
-/*------------------------------------------------------------------------*/
+Common::Point SpriteResource::getFrameSize(int frame) const {
+ Common::MemoryReadStream f(_data, _filesize);
+ Common::Point frameSize;
-static const byte DRAWER6_MASK[16] = { 1, 2, 4, 8, 1, 3, 7, 15, 8, 12, 14, 15, 1, 2, 1, 2 };
+ for (int idx = 0; idx < (_index[frame]._offset2 ? 2 : 1); ++idx) {
+ f.seek((idx == 0) ? _index[frame]._offset1 : _index[frame]._offset2);
+ int xOffset = f.readUint16LE();
+ int width = f.readUint16LE();
+ int yOffset = f.readUint16LE();
+ int height = f.readUint16LE();
-SpriteDrawer6::SpriteDrawer6(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) {
- _mask = DRAWER6_MASK[index];
-}
+ frameSize.x = MAX((int)frameSize.x, xOffset + width);
+ frameSize.y = MAX((int)frameSize.y, yOffset + height);
+ }
-void SpriteDrawer6::drawPixel(byte *dest, byte pixel) {
- *dest = pixel ^ _mask;
+ return frameSize;
}
} // End of namespace Xeen
diff --git a/engines/mm/shared/xeen/sprites.h b/engines/mm/shared/xeen/sprites.h
index 504f6513105..7a87ad4909e 100644
--- a/engines/mm/shared/xeen/sprites.h
+++ b/engines/mm/shared/xeen/sprites.h
@@ -71,7 +71,7 @@ protected:
* Draw the sprite onto the given surface
*/
void draw(XSurface &dest, int frame, const Common::Point &destPos,
- const Common::Rect &bounds, uint flags = 0, int scale = 0) const;
+ const Common::Rect &bounds, uint flags = 0, int scale = 0) const;
/**
* Deep copy assuming that the current instance is clean
@@ -101,20 +101,20 @@ public:
/**
* Draw a sprite onto a surface
- * @param dest Destination surface
- * @param frame Frame number
- * @param destPos Destination position
- * @param flags Flags
- * @param scale Scale: 0=No scale, SCALE_ENLARGE=Enlarge it
- * 1..15 -> reduces the sprite: the higher, the smaller it'll be
+ * @param dest Destination surface
+ * @param frame Frame number
+ * @param destPos Destination position
+ * @param flags Flags
+ * @param scale Scale: 0=No scale, SCALE_ENLARGE=Enlarge it
+ * 1..15 -> reduces the sprite: the higher, the smaller it'll be
*/
void draw(XSurface &dest, int frame, const Common::Point &destPos,
- uint flags = 0, int scale = 0) const;
+ uint flags = 0, int scale = 0) const;
/**
* Draw the sprite onto the given surface
- * @param dest Destination surface
- * @param frame Frame number
+ * @param dest Destination surface
+ * @param frame Frame number
*/
void draw(XSurface &dest, int frame) const;
@@ -151,155 +151,6 @@ public:
}
};
-/**
- * Basic sprite drawer
- */
-class SpriteDrawer {
-private:
- byte *_data = nullptr;
- size_t _filesize = 0;
-protected:
- byte *_destTop = nullptr, *_destBottom = nullptr;
- byte *_destLeft = nullptr, *_destRight = nullptr;
- int _pitch = 0;
-private:
- /**
- * Scale a co-ordinate value based on the passed scaling mask
- */
- static uint getScaledVal(int xy, uint16 &scaleMask);
-protected:
- /**
- * Roll carry right opcode emulation
- */
- void rcr(uint16 &val, bool &cf);
-
- /**
- * Output a pixel
- */
- virtual void drawPixel(byte *dest, byte pixel);
-public:
- /**
- * Constructor
- */
- SpriteDrawer(byte *data, size_t filesize) : _data(data), _filesize(filesize) {
- }
-
- /**
- * Destructor
- */
- virtual ~SpriteDrawer() {
- }
-
- /**
- * Draw a sprite frame based on a passed offset into the data stream
- */
- void draw(XSurface &dest, uint16 offset, const Common::Point &pt,
- const Common::Rect &clipRect, uint flags, int scale);
-};
-
-class SpriteDrawer1 : public SpriteDrawer {
-private:
- byte _offset = 0, _mask = 0;
-protected:
- /**
- * Output a pixel
- */
- void drawPixel(byte *dest, byte pixel) override;
-public:
- /**
- * Constructor
- */
- SpriteDrawer1(byte *data, size_t filesize, int index);
-};
-
-/**
- * Scrambles up the sprite by drawing many of the pixels randomly
- * at a horizontal or vertical offset
- */
-class SpriteDrawer2 : public SpriteDrawer {
-private:
- uint16 _mask1 = 0, _mask2 = 0;
- uint16 _random1 = 0, _random2 = 0;
-private:
- /**
- * Output a pixel
- */
- void drawPixel(byte *dest, byte pixel) override;
-public:
- /**
- * Constructor
- */
- SpriteDrawer2(byte *data, size_t filesize, int index);
-};
-
-/**
- * Draws the sprite as faint ghostly, see-through.
- */
-class SpriteDrawer3 : public SpriteDrawer {
-private:
- uint16 _offset = 0, _mask = 0;
- byte _palette[256 * 3];
- bool _hasPalette = false;
-private:
- /**
- * Output a pixel
- */
- void drawPixel(byte *dest, byte pixel) override;
-public:
- /**
- * Constructor
- */
- SpriteDrawer3(byte *data, size_t filesize, int index);
-};
-
-class SpriteDrawer4 : public SpriteDrawer {
-private:
- byte _threshold = 0;
-protected:
- /**
- * Output a pixel
- */
- void drawPixel(byte *dest, byte pixel) override;
-public:
- /**
- * Constructor
- */
- SpriteDrawer4(byte *data, size_t filesize, int index);
-};
-
-/**
- * Draws a sprite with a fuzziness effect where only some pixels of the sprite are randomly drawn
- */
-class SpriteDrawer5 : public SpriteDrawer {
-private:
- uint16 _threshold = 0, _random1 = 0, _random2 = 0;
-protected:
- /**
- * Output a pixel
- */
- void drawPixel(byte *dest, byte pixel) override;
-public:
- /**
- * Constructor
- */
- SpriteDrawer5(byte *data, size_t filesize, int index);
-};
-
-class SpriteDrawer6 : public SpriteDrawer {
-private:
- byte _mask = 0;
-protected:
- /**
- * Output a pixel
- */
- void drawPixel(byte *dest, byte pixel) override;
-public:
- /**
- * Constructor
- */
- SpriteDrawer6(byte *data, size_t filesize, int index);
-};
-
} // End of namespace Xeen
} // End of namespace Shared
} // End of namespace MM
More information about the Scummvm-git-logs
mailing list