[Scummvm-git-logs] scummvm master -> a8b779ee0e67c96c4efc951cf34accadc794e583
npjg
nathanael.gentrydb8 at gmail.com
Fri Jul 3 17:19:30 UTC 2020
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
a8b779ee0e DIRECTOR: Lazily load ink masks
Commit: a8b779ee0e67c96c4efc951cf34accadc794e583
https://github.com/scummvm/scummvm/commit/a8b779ee0e67c96c4efc951cf34accadc794e583
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-07-03T13:19:06-04:00
Commit Message:
DIRECTOR: Lazily load ink masks
This is for mask and matte inks. Now, rather than a bitmap sprite requiring a
flood fill every time (for mask ink) the matte is created and cached when matte
ink is first requested on that cast. Mask ink does not require a new surface to
be created, but it uses the same new channel interface.
Changed paths:
engines/director/castmember.cpp
engines/director/castmember.h
engines/director/graphics.cpp
engines/director/score.cpp
engines/director/score.h
engines/director/stage.cpp
diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 45bd4831fb..ad48a36c80 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -45,6 +45,7 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Common::ReadStream
: CastMember(cast, castId) {
_type = kCastBitmap;
_img = nullptr;
+ _matte = nullptr;
_bytes = 0;
_pitch = 0;
_flags = 0;
@@ -121,6 +122,9 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Common::ReadStream
BitmapCastMember::~BitmapCastMember() {
if (_img)
delete _img;
+
+ if (_matte)
+ delete _matte;
}
void BitmapCastMember::createWidget() {
@@ -135,6 +139,61 @@ void BitmapCastMember::createWidget() {
_widget->getSurface()->blitFrom(*_img->getSurface());
}
+void BitmapCastMember::createMatte() {
+ // Like background trans, but all white pixels NOT ENCLOSED by coloured pixels
+ // are transparent
+ Graphics::Surface tmp;
+ tmp.create(_initialRect.width(), _initialRect.height(), Graphics::PixelFormat::createFormatCLUT8());
+ tmp.copyFrom(*_img->getSurface());
+
+ // Searching white color in the corners
+ int whiteColor = -1;
+
+ for (int y = 0; y < tmp.h; y++) {
+ for (int x = 0; x < tmp.w; x++) {
+ byte color = *(byte *)tmp.getBasePtr(x, y);
+
+ if (g_director->getPalette()[color * 3 + 0] == 0xff &&
+ g_director->getPalette()[color * 3 + 1] == 0xff &&
+ g_director->getPalette()[color * 3 + 2] == 0xff) {
+ whiteColor = color;
+ break;
+ }
+ }
+ }
+
+ if (whiteColor == -1) {
+ debugC(1, kDebugImages, "BitmapCastMember::createMatte(): No white color for matte image");
+ } else {
+ delete _matte;
+
+ _matte = new Graphics::FloodFill(&tmp, whiteColor, 0, true);
+
+ for (int yy = 0; yy < tmp.h; yy++) {
+ _matte->addSeed(0, yy);
+ _matte->addSeed(tmp.w - 1, yy);
+ }
+
+ for (int xx = 0; xx < tmp.w; xx++) {
+ _matte->addSeed(xx, 0);
+ _matte->addSeed(xx, tmp.h - 1);
+ }
+
+ _matte->fillMask();
+ }
+
+ tmp.free();
+}
+
+Graphics::Surface *BitmapCastMember::getMatte() {
+ // Lazy loading of mattes
+ if (!_matte) {
+ createMatte();
+ }
+
+ return _matte ? _matte->getMask() : nullptr;
+}
+
DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId, Common::ReadStreamEndian &stream, uint16 version)
: CastMember(cast, castId) {
_type = kCastDigitalVideo;
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index 88b9c04d3a..59b8fa015e 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -29,6 +29,7 @@
namespace Graphics {
struct Surface;
+struct FloodFill;
class MacText;
class MacWindowManager;
class MacButton;
@@ -86,9 +87,13 @@ public:
BitmapCastMember(Cast *cast, uint16 castId, Common::ReadStreamEndian &stream, uint32 castTag, uint16 version);
~BitmapCastMember();
virtual void createWidget() override;
+
+ void createMatte();
+ Graphics::Surface *getMatte();
// virtual void setColors(int *fgcolor, int *bgcolor) override;
Image::ImageDecoder *_img;
+ Graphics::FloodFill *_matte;
uint16 _pitch;
uint16 _regX;
diff --git a/engines/director/graphics.cpp b/engines/director/graphics.cpp
index 14313e8ef4..d924af6f79 100644
--- a/engines/director/graphics.cpp
+++ b/engines/director/graphics.cpp
@@ -836,10 +836,11 @@ void inkDrawPixel(int x, int y, int color, void *data) {
if (*src == p->backColor)
break;
// fall through
+ case kInkTypeMatte:
+ case kInkTypeMask:
+ // Only unmasked pixels make it here, so copy them straight
case kInkTypeCopy:
*dst = *src;
- case kInkTypeMask:
- // TODO: Migrate from Stage to here
break;
case kInkTypeTransparent:
// FIXME: Is colour to ignore always white (last entry in pallette)?
@@ -870,9 +871,6 @@ void inkDrawPixel(int x, int y, int color, void *data) {
if (*src != p->numColors - 1)
*dst = *dst | *src;
break;
- case kInkTypeMatte:
- // TODO: Migrate from Stage to here.
- break;
// Arithmetic ink types
case kInkTypeBlend:
if (*src != p->numColors - 1)
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 4e831542d0..846f774db2 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -68,6 +68,37 @@ Graphics::ManagedSurface *Channel::getSurface() {
}
}
+const Graphics::Surface *Channel::getMask() {
+ switch (_sprite->_ink) {
+ case kInkTypeMatte:
+ // Mattes are only supported in bitmaps for now. Shapes don't need mattes,
+ // as they already have all non-enclosed white pixels transparent.
+ // Matte on text has a trivial enough effect to not worry about implementing.
+ if (_sprite->_cast && _sprite->_cast->_type == kCastBitmap) {
+ return ((BitmapCastMember *)_sprite->_cast)->getMatte();
+ } else {
+ return nullptr;
+ }
+
+ case kInkTypeMask: {
+ CastMember *member = g_director->getCurrentMovie()->getCastMember(_sprite->_castId + 1);
+
+ if (_sprite->_cast && member->_initialRect == _sprite->_cast->_initialRect) {
+ return &member->_widget->getSurface()->rawSurface();
+ } else {
+ warning("Channel::getMask(): Requested cast mask, but no matching mask was found");
+ return nullptr;
+ }
+
+ // Silence warning
+ break;
+ }
+
+ default:
+ return nullptr;
+ }
+}
+
bool Channel::isDirty(Sprite *nextSprite) {
// When a sprite is puppeted setTheSprite ensures that the dirty flag here is
// set. Otherwise, we need to rerender when the position, bounding box, or
diff --git a/engines/director/score.h b/engines/director/score.h
index 7493e80a8e..804a2a8187 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -26,6 +26,7 @@
//#include "graphics/macgui/macwindowmanager.h"
namespace Graphics {
+ struct Surface;
class ManagedSurface;
class Font;
class MacWindow;
@@ -112,10 +113,12 @@ struct Channel {
Channel(Sprite *sp);
bool isDirty(Sprite *nextSprite = nullptr);
+
Common::Rect getBbox();
Common::Point getPosition();
MacShape *getShape();
Graphics::ManagedSurface *getSurface();
+ const Graphics::Surface *getMask();
void setClean(Sprite *nextSprite, int spriteId);
void addDelta(Common::Point pos);
diff --git a/engines/director/stage.cpp b/engines/director/stage.cpp
index 76a0c05a2c..44d1fc024f 100644
--- a/engines/director/stage.cpp
+++ b/engines/director/stage.cpp
@@ -185,86 +185,20 @@ void Stage::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Manag
return;
}
- // Otherwise, we are drawing a cast type that does have a built-in surface, so
- // blit from that.
- // TODO: Work this ink type into inkDrawPixel.
- if (sprite->_ink == kInkTypeMatte) {
- drawMatteSprite(channel, srcRect, destRect, blitTo);
- return;
- }
+ // First, get any masks that might be needed.
+ const Graphics::Surface *mask = channel->getMask();
pd.srcPoint.y = MAX(abs(srcRect.top - destRect.top), 0);
for (int i = 0; i < destRect.height(); i++, pd.srcPoint.y++) {
pd.srcPoint.x = MAX(abs(srcRect.left - destRect.left), 0);
+ const byte *msk = mask ? (const byte *)mask->getBasePtr(pd.srcPoint.x, pd.srcPoint.y) : nullptr;
for (int j = 0; j < destRect.width(); j++, pd.srcPoint.x++)
- inkDrawPixel(destRect.left + j, destRect.top + i, 0, &pd);
+ if (!mask || (msk && (sprite->_ink == kInkTypeMatte ? !(*msk++) : *msk++)))
+ inkDrawPixel(destRect.left + j, destRect.top + i, 0, &pd);
}
}
-void Stage::drawMatteSprite(Channel *channel, Common::Rect &srcRect, Common::Rect &destRect, Graphics::ManagedSurface *blitTo) {
- // Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent
- Graphics::Surface tmp;
- tmp.create(destRect.width(), destRect.height(), Graphics::PixelFormat::createFormatCLUT8());
- tmp.copyFrom(channel->getSurface()->rawSurface());
-
- if (!blitTo->clip(srcRect, destRect))
- return; // Out of screen
-
- // Searching white color in the corners
- int whiteColor = -1;
-
- for (int y = 0; y < tmp.h; y++) {
- for (int x = 0; x < tmp.w; x++) {
- byte color = *(byte *)tmp.getBasePtr(x, y);
-
- if (g_director->getPalette()[color * 3 + 0] == 0xff &&
- g_director->getPalette()[color * 3 + 1] == 0xff &&
- g_director->getPalette()[color * 3 + 2] == 0xff) {
- whiteColor = color;
- break;
- }
- }
- }
-
- if (whiteColor == -1) {
- debugC(1, kDebugImages, "Score::drawMatteSprite(): No white color for Matte image");
-
- for (int yy = 0; yy < destRect.height(); yy++) {
- const byte *src = (const byte *)channel->getSurface()->getBasePtr(MAX(abs(srcRect.left - destRect.left), 0), MAX(abs(srcRect.top - destRect.top + yy), 0));
- byte *dst = (byte *)blitTo->getBasePtr(destRect.left, destRect.top + yy);
-
- for (int xx = 0; xx < destRect.width(); xx++, src++, dst++)
- *dst = *src;
- }
- } else {
- Graphics::FloodFill ff(&tmp, whiteColor, 0, true);
-
- for (int yy = 0; yy < tmp.h; yy++) {
- ff.addSeed(0, yy);
- ff.addSeed(tmp.w - 1, yy);
- }
-
- for (int xx = 0; xx < tmp.w; xx++) {
- ff.addSeed(xx, 0);
- ff.addSeed(xx, tmp.h - 1);
- }
- ff.fillMask();
-
- for (int yy = 0; yy < destRect.height(); yy++) {
- const byte *mask = (const byte *)ff.getMask()->getBasePtr(MAX(abs(srcRect.left - destRect.left), 0), MAX(abs(srcRect.top - destRect.top - yy), 0));
- const byte *src = (const byte *)channel->getSurface()->getBasePtr(MAX(abs(srcRect.left - destRect.left), 0), MAX(abs(srcRect.top - destRect.top - yy), 0));
- byte *dst = (byte *)blitTo->getBasePtr(destRect.left, destRect.top + yy);
-
- for (int xx = 0; xx < destRect.width(); xx++, src++, dst++, mask++)
- if (*mask == 0)
- *dst = *src;
- }
- }
-
- tmp.free();
-}
-
Common::Point Stage::getMousePos() {
return g_system->getEventManager()->getMousePos() - Common::Point(_dims.left, _dims.top);
}
More information about the Scummvm-git-logs
mailing list