aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/messages.cpp20
-rw-r--r--engines/mads/messages.h23
-rw-r--r--engines/mads/msurface.cpp176
-rw-r--r--engines/mads/msurface.h21
-rw-r--r--engines/mads/scene.cpp20
-rw-r--r--engines/mads/sprites.cpp89
-rw-r--r--engines/mads/sprites.h7
7 files changed, 332 insertions, 24 deletions
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index 3b6663e71d..11db00f1b9 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -305,7 +305,7 @@ TextDisplayList::TextDisplayList(MADSEngine *vm) : _vm(vm) {
}
}
-void TextDisplayList::clear() {
+void TextDisplayList::reset() {
for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i)
(*this)[i]._active = false;
}
@@ -361,18 +361,16 @@ void TextDisplayList::setDirtyAreas2() {
}
}
-void TextDisplayList::draw(MSurface *view) {
- error("TODO");
- /*
- for (uint idx = 0; idx < _entries.size(); ++idx) {
- if (_entries[idx]._active && (_entries[idx]._expire >= 0)) {
- _entries[idx]._font->setColors(_entries[idx]._color1, _entries[idx]._color2, 0);
- _entries[idx]._font->writeString(view, _entries[idx]._msg,
- Common::Point(_entries[idx]._bounds.left, _entries[idx]._bounds.top),
- _entries[idx]._bounds.width(), _entries[idx]._spacing);
+void TextDisplayList::draw(MSurface *s) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ TextDisplay &td = (*this)[idx];
+ if (td._active && (td._expire >= 0)) {
+ td._font->setColors(0xFF, td._color1, td._color2, 0);
+ td._font->writeString(s, td._msg,
+ Common::Point(td._bounds.left, td._bounds.top),
+ td._bounds.width(), td._spacing);
}
}
- */
}
void TextDisplayList::cleanUp() {
diff --git a/engines/mads/messages.h b/engines/mads/messages.h
index 1357b98d03..19a0115f94 100644
--- a/engines/mads/messages.h
+++ b/engines/mads/messages.h
@@ -108,11 +108,6 @@ public:
class TextDisplayList: public Common::Array<TextDisplay> {
private:
MADSEngine *_vm;
-
- /**
- * Determine dirty areas for active text areas
- */
- void setDirtyAreas2();
public:
TextDisplayList(MADSEngine *vm);
@@ -122,8 +117,17 @@ public:
void expire(int idx);
int add(int xp, int yp, uint fontColor, int charSpacing, const Common::String &, Font *font);
- void clear();
- void draw(MSurface *view);
+
+ /**
+ * Reset all of the text display entries in the list to inactive
+ */
+ void reset();
+
+ /**
+ * Draw any text in the list to the specified surface
+ * @param surface Surface
+ */
+ void draw(MSurface *s);
/**
* Determine dirty areas for active text areas
@@ -131,6 +135,11 @@ public:
void setDirtyAreas();
/**
+ * Secondary setup dirty areas for the text areas
+ */
+ void setDirtyAreas2();
+
+ /**
* Deactivates any text display entries that are finished
*/
void cleanUp();
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index 5f7b37b1cd..aed00f5553 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -244,6 +244,168 @@ void MSurface::copyFrom(MSurface *src, const Common::Rect &srcBounds,
}
}
+void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
+ MSurface *depthsSurface, int scale, int transparentColor) {
+
+ int destX = destPos.x, destY = destPos.y;
+ if (scale == 100) {
+ // Copy the specified area
+ Common::Rect copyRect(0, 0, src->getWidth(), src->getHeight());
+
+ if (destX < 0) {
+ copyRect.left += -destX;
+ destX = 0;
+ }
+ else if (destX + copyRect.width() > w) {
+ copyRect.right -= destX + copyRect.width() - w;
+ }
+ if (destY < 0) {
+ copyRect.top += -destY;
+ destY = 0;
+ }
+ else if (destY + copyRect.height() > h) {
+ copyRect.bottom -= destY + copyRect.height() - h;
+ }
+
+ if (!copyRect.isValidRect())
+ return;
+
+ byte *data = src->getData();
+ byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
+ byte *depthsData = depthsSurface->getData();
+ byte *depthsPtr = depthsData + (depthsSurface->pitch * destY) + destX;
+ byte *destPtr = (byte *)pixels + (destY * pitch) + destX;
+
+ // 100% scaling variation
+ for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
+ // Copy each byte one at a time checking against the depth
+ for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) {
+ if ((depth <= (depthsPtr[xCtr] & 0x7f)) && (srcPtr[xCtr] != transparentColor))
+ destPtr[xCtr] = srcPtr[xCtr];
+ }
+
+ srcPtr += src->getWidth();
+ depthsPtr += depthsSurface->getWidth();
+ destPtr += getWidth();
+ }
+
+ return;
+ }
+
+ // Start of draw logic for scaled sprites
+ const byte *srcPixelsP = src->getData();
+
+ int destRight = this->getWidth() - 1;
+ int destBottom = this->getHeight() - 1;
+ bool normalFrame = true; // TODO: false for negative frame numbers
+ int frameWidth = src->getWidth();
+ int frameHeight = src->getHeight();
+
+ int highestDim = MAX(frameWidth, frameHeight);
+ bool lineDist[MADS_SCREEN_WIDTH];
+ int distIndex = 0;
+ int distXCount = 0, distYCount = 0;
+
+ int distCtr = 0;
+ do {
+ distCtr += scale;
+ if (distCtr < 100) {
+ lineDist[distIndex] = false;
+ }
+ else {
+ lineDist[distIndex] = true;
+ distCtr -= 100;
+
+ if (distIndex < frameWidth)
+ ++distXCount;
+
+ if (distIndex < frameHeight)
+ ++distYCount;
+ }
+ } while (++distIndex < highestDim);
+
+ destX -= distXCount / 2;
+ destY -= distYCount - 1;
+
+ // Check x bounding area
+ int spriteLeft = 0;
+ int spriteWidth = distXCount;
+ int widthAmount = destX + distXCount - 1;
+
+ if (destX < 0) {
+ spriteWidth += destX;
+ spriteLeft -= destX;
+ }
+ widthAmount -= destRight;
+ if (widthAmount > 0)
+ spriteWidth -= widthAmount;
+
+ int spriteRight = spriteLeft + spriteWidth;
+ if (spriteWidth <= 0)
+ return;
+ if (!normalFrame) {
+ destX += distXCount - 1;
+ spriteLeft = -(distXCount - spriteRight);
+ spriteRight = (-spriteLeft + spriteWidth);
+ }
+
+ // Check y bounding area
+ int spriteTop = 0;
+ int spriteHeight = distYCount;
+ int heightAmount = destY + distYCount - 1;
+
+ if (destY < 0) {
+ spriteHeight += destY;
+ spriteTop -= destY;
+ }
+ heightAmount -= destBottom;
+ if (heightAmount > 0)
+ spriteHeight -= heightAmount;
+ int spriteBottom = spriteTop + spriteHeight;
+
+ if (spriteHeight <= 0)
+ return;
+
+ byte *destPixelsP = this->getBasePtr(destX + spriteLeft, destY + spriteTop);
+ const byte *depthPixelsP = depthsSurface->getBasePtr(destX + spriteLeft, destY + spriteTop);
+
+ spriteLeft = (spriteLeft * (normalFrame ? 1 : -1));
+
+ // Loop through the lines of the sprite
+ for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src->pitch) {
+ if (!lineDist[yp])
+ // Not a display line, so skip it
+ continue;
+ // Check whether the sprite line is in the display range
+ ++sprY;
+ if ((sprY >= spriteBottom) || (sprY < spriteTop))
+ continue;
+
+ // Found a line to display. Loop through the pixels
+ const byte *srcP = srcPixelsP;
+ const byte *depthP = depthPixelsP;
+ byte *destP = destPixelsP;
+ for (int xp = 0, sprX = 0; xp < frameWidth; ++xp, ++srcP) {
+ if (xp < spriteLeft)
+ // Not yet reached start of display area
+ continue;
+ if (!lineDist[sprX++])
+ // Not a display pixel
+ continue;
+
+ if ((*srcP != transparentColor) && (depth <= (*depthP & 0x7f)))
+ *destP = *srcP;
+
+ ++destP;
+ ++depthP;
+ }
+
+ // Move to the next destination line
+ destPixelsP += this->pitch;
+ depthPixelsP += depthsSurface->pitch;
+ }
+}
+
void MSurface::translate(Common::Array<RGB6> &palette) {
for (int y = 0; y < this->h; ++y) {
byte *pDest = getBasePtr(0, y);
@@ -254,4 +416,18 @@ void MSurface::translate(Common::Array<RGB6> &palette) {
}
}
+MSurface *MSurface::flipHorizontal() const {
+ MSurface *dest = new MSurface(this->w, this->h);
+
+ for (int y = 0; y < this->h; ++y) {
+ const byte *srcP = getBasePtr(this->w - 1, y);
+ byte *destP = dest->getData();
+
+ for (int x = 0; x < this->w; ++x)
+ *destP++ = *srcP--;
+ }
+
+ return dest;
+}
+
} // End of namespace MADS
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index 7043cd4eff..c797033859 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -127,6 +127,11 @@ public:
byte *getBasePtr(int x, int y) { return (byte *)Graphics::Surface::getBasePtr(x, y); }
/**
+ * Returns a pointer to a given position within the surface
+ */
+ const byte *getBasePtr(int x, int y) const { return (const byte *)Graphics::Surface::getBasePtr(x, y); }
+
+ /**
* Clears the surface
*/
void empty();
@@ -142,6 +147,17 @@ public:
int transparentColor = -1);
/**
+ * Copys a sub-section of another surface into the current one.
+ * @param src Source surface
+ * @param destPos Destination position to draw in current surface
+ * @param depth Depth of sprite
+ * @param depthSurface Depth surface to use with sprite depth
+ * @param transparentColor Transparency palette index
+ */
+ void copyFrom(MSurface *src, const Common::Point &destPos, int depth, MSurface *depthSurface,
+ int scale, int transparentColor = -1);
+
+ /**
* Copies the surface to a given destination surface
*/
void copyTo(MSurface *dest, int transparentColor = -1) {
@@ -167,6 +183,11 @@ public:
* Translates the pixels of an image used the passed palette with RGB mapping
*/
void translate(Common::Array<RGB6> &palette);
+
+ /**
+ * Create a new surface which is a flipped horizontal copy of the current one
+ */
+ MSurface *flipHorizontal() const;
};
} // End of namespace MADS
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
index 1d489ddb2d..7359562180 100644
--- a/engines/mads/scene.cpp
+++ b/engines/mads/scene.cpp
@@ -423,18 +423,30 @@ void Scene::doFrame() {
}
void Scene::drawElements(bool transitionFlag, bool surfaceFlag) {
- // Draw any background objects
+ // Draw any sprites
+ _dirtyAreas.clear();
_spriteSlots.drawBackground();
+ // Process dirty areas
+ _textDisplay.setDirtyAreas();
+
// Merge any identified dirty areas
- _dirtyAreas.merge(1, _dirtyAreas.size());
+ _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
// Copy dirty areas to the main display surface
_dirtyAreas.copy(&_vm->_screen, &_backgroundSurface, _posAdjust);
- // Set dirty areas
+ // Handle dirty areas for foreground objects
_spriteSlots.setDirtyAreas();
- _textDisplay.setDirtyAreas();
+ _textDisplay.setDirtyAreas2();
+ _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+
+
+ // Draw foreground sprites
+ _spriteSlots.drawForeground(&_vm->_screen);
+
+ // Draw text elements onto the view
+ _textDisplay.draw(&_vm->_screen);
//
_vm->_screen.setPointer(&_vm->_screen);
diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp
index e7349f6c60..aa15f665f4 100644
--- a/engines/mads/sprites.cpp
+++ b/engines/mads/sprites.cpp
@@ -36,6 +36,24 @@ enum {
kMarker = 2
};
+#define TRANSPARENT_COLOR_INDEX 0xFF
+
+class DepthEntry {
+public:
+ int depth;
+ int index;
+
+ DepthEntry(int depthAmt, int indexVal) { depth = depthAmt; index = indexVal; }
+};
+
+bool sortHelper(const DepthEntry &entry1, const DepthEntry &entry2) {
+ return entry1.depth < entry2.depth;
+}
+
+typedef Common::List<DepthEntry> DepthList;
+
+/*------------------------------------------------------------------------*/
+
MSprite::MSprite(): MSurface() {
_encoding = 0;
}
@@ -105,6 +123,10 @@ void MSprite::loadSprite(Common::SeekableReadStream *source) {
}
}
+byte MSprite::getTransparencyIndex() const {
+ return TRANSPARENT_COLOR_INDEX;
+}
+
/*------------------------------------------------------------------------*/
MADSEngine *SpriteSlot::_vm = nullptr;
@@ -233,6 +255,71 @@ void SpriteSlots::drawBackground() {
}
}
+void SpriteSlots::drawForeground(MSurface *s) {
+ DepthList depthList;
+ Scene &scene = _vm->_game->_scene;
+
+ // Get a list of sprite object depths for active objects
+ for (uint i = 0; i < size(); ++i) {
+ if ((*this)[i]._spriteType >= ST_NONE) {
+ DepthEntry rec(16 - (*this)[i]._depth, i);
+ depthList.push_back(rec);
+ }
+ }
+
+ // Sort the list in order of the depth
+ Common::sort(depthList.begin(), depthList.end(), sortHelper);
+
+ // Loop through each of the objects
+ DepthList::iterator i;
+ for (i = depthList.begin(); i != depthList.end(); ++i) {
+ DepthEntry &de = *i;
+ SpriteSlot &slot = (*this)[de.index];
+ assert(slot._spritesIndex < (int)scene._sprites.size());
+ SpriteAsset &spriteSet = *scene._sprites[slot._spritesIndex];
+
+ // Get the sprite frame
+ int frameNumber = slot._frameNumber & 0x7fff;
+ bool flipped = (slot._frameNumber & 0x8000) != 0;
+ MSprite *sprite = spriteSet.getFrame(frameNumber - 1);
+
+ MSurface *spr = sprite;
+ if (flipped) {
+ // Create a flipped copy of the sprite temporarily
+ spr = sprite->flipHorizontal();
+ }
+
+ if ((slot._scale < 100) && (slot._scale != -1)) {
+ // Minimalised drawing
+ s->copyFrom(spr, slot._position, slot._depth, &scene._depthSurface,
+ slot._scale, sprite->getTransparencyIndex());
+ } else {
+ int xp, yp;
+
+ if (slot._scale == -1) {
+ xp = slot._position.x - scene._posAdjust.x;
+ yp = slot._position.y - scene._posAdjust.y;
+ } else {
+ xp = slot._position.x - (spr->w / 2) - scene._posAdjust.x;
+ yp = slot._position.y - spr->h - scene._posAdjust.y + 1;
+ }
+
+ if (slot._depth > 1) {
+ // Draw the frame with depth processing
+ s->copyFrom(spr, Common::Point(xp, yp), slot._depth, &scene._depthSurface,
+ 100, sprite->getTransparencyIndex());
+ } else {
+ // No depth, so simply draw the image
+ spr->copyTo(s, Common::Point(xp, yp), sprite->getTransparencyIndex());
+ }
+ }
+
+ // Free sprite if it was a flipped one
+ if (flipped)
+ delete spr;
+ }
+}
+
void SpriteSlots::cleanUp() {
for (int i = (int)size() - 1; i >= 0; --i) {
if ((*this)[i]._spriteType >= ST_NONE)
@@ -254,6 +341,4 @@ int SpriteSets::add(SpriteAsset *asset, int idx) {
return idx;
}
-/*------------------------------------------------------------------------*/
-
} // End of namespace MADS
diff --git a/engines/mads/sprites.h b/engines/mads/sprites.h
index b1208d0df5..f9ae46ad9b 100644
--- a/engines/mads/sprites.h
+++ b/engines/mads/sprites.h
@@ -114,6 +114,8 @@ public:
Common::Point _pos;
Common::Point _offset;
uint8 _encoding;
+
+ byte getTransparencyIndex() const;
};
class SpriteSlotSubset {
@@ -188,6 +190,11 @@ public:
*/
void drawBackground();
+ /**
+ * Draw any sprites into the foreground of the scene
+ */
+ void drawForeground(MSurface *s);
+
void cleanUp();
};