[Scummvm-git-logs] scummvm master -> 1149e0edd3867e8fb714899a2a542a7e4fb620b0
sev-
sev at scummvm.org
Sun May 17 21:21:38 UTC 2020
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
3fa90b4ade DIRECTOR: Move from drawRects to bboxes
9fc6197c32 DIRECTOR: Precompute cast types of sprite
5babbb30db DIRECTOR: Move to channel-based rendering
1149e0edd3 DIRECTOR: Disable ink inversion hack
Commit: 3fa90b4adec1b714b96d2b0fab73ecb2183fe2c5
https://github.com/scummvm/scummvm/commit/3fa90b4adec1b714b96d2b0fab73ecb2183fe2c5
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-05-17T23:21:33+02:00
Commit Message:
DIRECTOR: Move from drawRects to bboxes
Changed paths:
engines/director/events.cpp
engines/director/frame.cpp
engines/director/frame.h
engines/director/lingo/lingo-the.cpp
engines/director/score.cpp
engines/director/score.h
engines/director/sprite.cpp
engines/director/sprite.h
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 5793100c1e..05909b5656 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -88,6 +88,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
Common::Point delta = pos - _draggingSpritePos;
draggedSprite->_currentPoint.x += delta.x;
draggedSprite->_currentPoint.y += delta.y;
+ draggedSprite->_dirtyBbox.translate(delta.x, delta.y);
_draggingSpritePos = pos;
} else {
releaseDraggedSprite();
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index fd3a247705..2a741b9e5f 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -108,7 +108,6 @@ Frame::Frame(const Frame &frame) {
Frame::~Frame() {
delete _palette;
- _drawRects.clear();
for (uint16 i = 0; i < _sprites.size(); i++)
delete _sprites[i];
@@ -527,7 +526,6 @@ void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offse
}
void Frame::prepareFrame(Score *score, bool updateStageOnly) {
- _drawRects.clear();
renderSprites(*score->_surface, false);
renderSprites(*score->_trailSurface, true);
@@ -555,6 +553,62 @@ void Frame::playSoundChannel() {
debug(0, "STUB: playSoundChannel(), Sound1 %d Sound2 %d", _sound1, _sound2);
}
+CastType Frame::getCastType(uint16 spriteId) {
+ CastType castType = kCastTypeNull;
+ Sprite *sprite = _sprites[spriteId];
+
+ if (_vm->getVersion() < 4) {
+ debugC(1, kDebugImages, "Frame::getCastType(): Channel: %d type: %d", spriteId, sprite->_spriteType);
+ switch (sprite->_spriteType) {
+ case kBitmapSprite:
+ castType = kCastBitmap;
+ break;
+ case kRectangleSprite:
+ case kRoundedRectangleSprite:
+ case kOvalSprite:
+ case kLineTopBottomSprite:
+ case kLineBottomTopSprite:
+ case kOutlinedRectangleSprite:
+ case kOutlinedRoundedRectangleSprite:
+ case kOutlinedOvalSprite:
+ case kCastMemberSprite:
+ if (sprite->_cast != nullptr) {
+ switch (sprite->_cast->_type) {
+ case kCastButton:
+ castType = kCastButton;
+ break;
+ default:
+ castType = kCastShape;
+ break;
+ }
+ } else {
+ castType = kCastShape;
+ }
+ break;
+ case kTextSprite:
+ castType = kCastText;
+ break;
+ case kButtonSprite:
+ case kCheckboxSprite:
+ case kRadioButtonSprite:
+ castType = kCastButton;
+ break;
+ default:
+ warning("Frame::getCastType(): Unhandled sprite type %d", sprite->_spriteType);
+ break;
+ }
+ } else {
+ Cast *member = _vm->getCastMember(_sprites[spriteId]->_castId);
+ if (!member) {
+ debugC(1, kDebugImages, "Frame::renderSprites(): Cast id %d not found", _sprites[spriteId]->_castId);
+ } else {
+ castType = member->_type;
+ }
+ }
+
+ return castType;
+}
+
void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
for (uint16 i = 0; i <= _numChannels; i++) {
if (!_sprites[i]->_enabled)
@@ -563,60 +617,16 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail))
continue;
- CastType castType = kCastTypeNull;
- if (_vm->getVersion() < 4) {
- debugC(1, kDebugImages, "Frame::renderSprites(): Channel: %d type: %d", i, _sprites[i]->_spriteType);
- switch (_sprites[i]->_spriteType) {
- case kBitmapSprite:
- castType = kCastBitmap;
- break;
- case kRectangleSprite:
- case kRoundedRectangleSprite:
- case kOvalSprite:
- case kLineTopBottomSprite:
- case kLineBottomTopSprite:
- case kOutlinedRectangleSprite:
- case kOutlinedRoundedRectangleSprite:
- case kOutlinedOvalSprite:
- case kCastMemberSprite:
- if (_sprites[i]->_cast != nullptr) {
- switch (_sprites[i]->_cast->_type) {
- case kCastButton:
- castType = kCastButton;
- break;
- default:
- castType = kCastShape;
- break;
- }
- } else {
- castType = kCastShape;
- }
- break;
- case kTextSprite:
- castType = kCastText;
- break;
- case kButtonSprite:
- case kCheckboxSprite:
- case kRadioButtonSprite:
- castType = kCastButton;
- break;
- default:
- warning("Frame::renderSprites(): Unhandled sprite type %d", _sprites[i]->_spriteType);
- break;
- }
- } else {
- Cast *member = _vm->getCastMember(_sprites[i]->_castId);
- if (!member) {
- debugC(1, kDebugImages, "Frame::renderSprites(): Cast id %d not found", _sprites[i]->_castId);
- } else {
- castType = member->_type;
- }
- }
+ CastType castType = getCastType(i);
+ if (castType == kCastTypeNull)
+ continue;
// this needs precedence to be hit first... D3 does something really tricky with cast IDs for shapes.
// I don't like this implementation 100% as the 'cast' above might not actually hit a member and be null?
debugC(1, kDebugImages, "Frame::renderSprites(): Channel: %d castType: %d", i, castType);
+ _sprites[i]->_currentBbox = _sprites[i]->_dirtyBbox;
+
if (castType == kCastShape) {
renderShape(surface, i);
} else if (castType == kCastText || castType == kCastRTE) {
@@ -638,13 +648,6 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
}
}
-void Frame::addDrawRect(uint16 spriteId, Common::Rect &rect) {
- FrameEntity *fi = new FrameEntity();
- fi->spriteId = spriteId;
- fi->rect = rect;
- _drawRects.push_back(fi);
-}
-
void Frame::renderShape(Graphics::ManagedSurface &surface, uint16 spriteId) {
Sprite *sp = _sprites[spriteId];
@@ -700,10 +703,7 @@ void Frame::renderShape(Graphics::ManagedSurface &surface, uint16 spriteId) {
// for outlined shapes, line thickness of 1 means invisible.
lineSize -= 1;
- Common::Rect shapeRect = Common::Rect(sp->_currentPoint.x,
- sp->_currentPoint.y,
- sp->_currentPoint.x + sp->_width,
- sp->_currentPoint.y + sp->_height);
+ Common::Rect shapeRect = sp->_currentBbox;
Graphics::ManagedSurface tmpSurface, maskSurface;
tmpSurface.create(shapeRect.width(), shapeRect.height(), Graphics::PixelFormat::createFormatCLUT8());
@@ -762,7 +762,6 @@ void Frame::renderShape(Graphics::ManagedSurface &surface, uint16 spriteId) {
break;
}
- addDrawRect(spriteId, shapeRect);
inkBasedBlit(surface, &maskSurface, tmpSurface, ink, shapeRect, spriteId);
}
@@ -798,28 +797,16 @@ void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
}
}
- uint32 rectLeft = button->_initialRect.left;
- uint32 rectTop = button->_initialRect.top;
-
- int x = _sprites[spriteId]->_currentPoint.x;
- int y = _sprites[spriteId]->_currentPoint.y;
-
- if (_vm->getVersion() > 3) {
- x += rectLeft;
- y += rectTop;
- }
-
- int height = button->_initialRect.height();
- int width = button->_initialRect.width() + 3;
-
bool invert = spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId;
// TODO: review all cases to confirm if we should use text height.
// height = textRect.height();
- Common::Rect _rect;
+ Common::Rect _rect = _sprites[spriteId]->_currentBbox;
+ int16 x = _rect.left;
+ int16 y = _rect.top;
- Common::Rect textRect(0, 0, width, height);
+ Common::Rect textRect(0, 0, _rect.width(), _rect.height());
// WORKAROUND, HACK
// Because we're not drawing text with transparency
@@ -828,27 +815,20 @@ void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
if (!invert)
renderText(surface, spriteId, &textRect);
- Graphics::MacPlotData plotStroke(&surface, nullptr, &_vm->getPatterns(), 1, -_rect.left, -_rect.top, 1, 0);
+ Graphics::MacPlotData plotStroke(&surface, nullptr, &_vm->getPatterns(), 1, 0, 0, 1, 0);
switch (buttonType) {
case kCheckboxSprite:
- // Magic numbers: checkbox square need to move left about 5px from text and 12px side size (D4)
- _rect = Common::Rect(x, y + 2, x + 12, y + 14);
surface.frameRect(_rect, 0);
- addDrawRect(spriteId, _rect);
break;
case kButtonSprite: {
- _rect = Common::Rect(x, y, x + width, y + height + 3);
Graphics::MacPlotData pd(&surface, nullptr, &_vm->getMacWindowManager()->getPatterns(), Graphics::MacGUIConstants::kPatternSolid, 0, 0, 1, invert ? Graphics::kColorBlack : Graphics::kColorWhite);
Graphics::drawRoundRect(_rect, 4, 0, invert, Graphics::macDrawPixel, &pd);
- addDrawRect(spriteId, _rect);
}
break;
case kRadioButtonSprite:
- _rect = Common::Rect(x, y + 2, x + 12, y + 14);
Graphics::drawEllipse(x, y + 2, x + 11, y + 13, 0, false, Graphics::macDrawPixel, &plotStroke);
- addDrawRect(spriteId, _rect);
break;
default:
warning("renderButton: Unknown buttonType");
@@ -869,20 +849,11 @@ void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteId, Commo
Score *score = _vm->getCurrentScore();
Sprite *sprite = _sprites[spriteId];
- int x = sprite->_currentPoint.x; // +rectLeft;
- int y = sprite->_currentPoint.y; // +rectTop;
- int height = textCast->_initialRect.height(); //_sprites[spriteId]->_height;
- int width;
-
- if (_vm->getVersion() >= 4) {
- if (textRect == NULL) {
- width = textCast->_initialRect.right;
- } else {
- width = textRect->width();
- }
- } else {
- width = textCast->_initialRect.width(); //_sprites[spriteId]->_width;
- }
+ Common::Rect bbox = sprite->_currentBbox;
+ int width = bbox.width();
+ int height = bbox.height();
+ int x = bbox.left;
+ int y = bbox.top;
if (_vm->getCurrentScore()->_fontMap.contains(textCast->_fontId)) {
// We need to make sure that the Shared Cast fonts have been loaded in?
@@ -1055,18 +1026,8 @@ void Frame::renderBitmap(Graphics::ManagedSurface &surface, uint16 spriteId) {
ink = sprite->_ink;
BitmapCast *bc = (BitmapCast *)sprite->_cast;
+ Common::Rect drawRect = sprite->_currentBbox;
- int32 regX = bc->_regX;
- int32 regY = bc->_regY;
- int32 rectLeft = bc->_initialRect.left;
- int32 rectTop = bc->_initialRect.top;
-
- int x = sprite->_currentPoint.x - regX + rectLeft;
- int y = sprite->_currentPoint.y - regY + rectTop;
- int height = sprite->_height;
- int width = _vm->getVersion() > 4 ? bc->_initialRect.width() : sprite->_width;
- Common::Rect drawRect(x, y, x + width, y + height);
- addDrawRect(spriteId, drawRect);
inkBasedBlit(surface, nullptr, *(bc->_surface), ink, drawRect, spriteId);
}
@@ -1260,29 +1221,22 @@ void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Su
}
uint16 Frame::getSpriteIDFromPos(Common::Point pos) {
- // Find first from front to back
- for (int dr = _drawRects.size() - 1; dr >= 0; dr--)
- if (_drawRects[dr]->rect.contains(pos))
- return _drawRects[dr]->spriteId;
+ for (int i = _sprites.size() - 1; i >= 0; i--)
+ if (_sprites[i]->_currentBbox.contains(pos))
+ return i;
return 0;
}
bool Frame::checkSpriteIntersection(uint16 spriteId, Common::Point pos) {
- // Find first from front to back
- for (int dr = _drawRects.size() - 1; dr >= 0; dr--)
- if (_drawRects[dr]->spriteId == spriteId && _drawRects[dr]->rect.contains(pos))
- return true;
+ if (_sprites[spriteId]->_currentBbox.contains(pos))
+ return true;
return false;
}
Common::Rect *Frame::getSpriteRect(uint16 spriteId) {
- for (int dr = _drawRects.size() - 1; dr >= 0; dr--)
- if (_drawRects[dr]->spriteId == spriteId)
- return &_drawRects[dr]->rect;
-
- return nullptr;
+ return &_sprites[spriteId]->_currentBbox;
}
} // End of namespace Director
diff --git a/engines/director/frame.h b/engines/director/frame.h
index 6891f11290..96a4525292 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -76,6 +76,7 @@ public:
uint16 getSpriteIDFromPos(Common::Point pos);
bool checkSpriteIntersection(uint16 spriteId, Common::Point pos);
Common::Rect *getSpriteRect(uint16 spriteId);
+ CastType getCastType(uint16 spriteId);
void executeImmediateScripts();
@@ -97,7 +98,6 @@ private:
void drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect);
void drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect, uint16 spriteId);
void inkBasedBlit(Graphics::ManagedSurface &targetSurface, const Graphics::ManagedSurface *maskSurface, const Graphics::Surface &spriteSurface, InkType ink, Common::Rect drawRect, uint spriteId);
- void addDrawRect(uint16 entityId, Common::Rect &rect);
public:
int _numChannels;
@@ -124,7 +124,6 @@ public:
uint8 _skipFrameFlag;
uint8 _blend;
Common::Array<Sprite *> _sprites;
- Common::Array<FrameEntity *> _drawRects;
DirectorEngine *_vm;
};
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 5f9144eebc..5459c5f44d 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -573,7 +573,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
d.u.i = sprite->_blend;
break;
case kTheBottom:
- d.u.i = sprite->_bottom;
+ d.u.i = sprite->_currentBbox.bottom;
break;
case kTheCastNum:
d.u.i = sprite->_castId;
@@ -594,7 +594,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
d.u.i = sprite->_ink;
break;
case kTheLeft:
- d.u.i = sprite->_left;
+ d.u.i = sprite->_currentBbox.left;
break;
case kTheLineSize:
d.u.i = sprite->_thickness & 0x3;
@@ -621,7 +621,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
d.u.i = sprite->_puppet;
break;
case kTheRight:
- d.u.i = sprite->_right;
+ d.u.i = sprite->_currentBbox.right;
break;
case kTheStartTime:
d.u.i = sprite->_startTime;
@@ -633,7 +633,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
d.u.i = sprite->_stretch;
break;
case kTheTop:
- d.u.i = sprite->_top;
+ d.u.i = sprite->_currentBbox.top;
break;
case kTheTrails:
d.u.i = sprite->_trails;
@@ -687,9 +687,6 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
case kTheBlend:
sprite->_blend = d.asInt();
break;
- case kTheBottom:
- sprite->_bottom = d.asInt();
- break;
case kTheCastNum:
if (_vm->getCastMember(d.asInt())) {
sprite->_cast = _vm->getCastMember(d.asInt());
@@ -711,9 +708,6 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
case kTheInk:
sprite->_ink = static_cast<InkType>(d.asInt());
break;
- case kTheLeft:
- sprite->_left = d.asInt();
- break;
case kTheLineSize:
sprite->_thickness = d.asInt();
break;
@@ -725,8 +719,10 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
break;
case kTheMoveableSprite:
sprite->_moveable = d.asInt();
- if (!d.u.i)
+ if (!d.u.i) {
sprite->_currentPoint = sprite->_startPoint;
+ sprite->_dirtyBbox = sprite->_startBbox;
+ }
break;
case kTheMovieRate:
sprite->_movieRate = d.asInt();
@@ -740,9 +736,6 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
case kThePuppet:
sprite->_puppet = d.asInt();
break;
- case kTheRight:
- sprite->_right = d.asInt();
- break;
case kTheStartTime:
sprite->_startTime = d.asInt();
break;
@@ -752,9 +745,6 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
case kTheStretch:
sprite->_stretch = d.asInt();
break;
- case kTheTop:
- sprite->_top = d.asInt();
- break;
case kTheTrails:
sprite->_trails = d.asInt();
break;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 587bc6400b..ef0ce793a5 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -278,8 +278,8 @@ void Score::loadArchive() {
debug("STUB: Unhandled 'SCVW' resource");
}
-
setSpriteCasts();
+ setSpriteBboxes();
loadSpriteImages(false);
loadSpriteSounds(false);
@@ -772,6 +772,128 @@ void Score::setSpriteCasts() {
}
}
+void Score::setSpriteBboxes() {
+ for (uint16 i = 0; i < _frames.size(); i++) {
+ for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
+ Sprite *sp = _frames[i]->_sprites[j];
+
+ if (sp->_castId == 0)
+ continue;
+
+ CastType castType = _frames[i]->getCastType(j);
+
+ switch (castType) {
+ case kCastShape:
+ sp->_startBbox = Common::Rect(sp->_currentPoint.x,
+ sp->_currentPoint.y,
+ sp->_currentPoint.x + sp->_width,
+ sp->_currentPoint.y + sp->_height);
+ break;
+ case kCastRTE:
+ case kCastText: {
+ TextCast *textCast = (TextCast*)sp->_cast;
+ int x = sp->_currentPoint.x; // +rectLeft;
+ int y = sp->_currentPoint.y; // +rectTop;
+ int height = textCast->_initialRect.height(); //_sprites[spriteId]->_height;
+ int width;
+ Common::Rect *textRect = NULL;
+
+ if (_vm->getVersion() >= 4) {
+ // where does textRect come from?
+ if (textRect == NULL) {
+ width = textCast->_initialRect.right;
+ } else {
+ width = textRect->width();
+ }
+ } else {
+ width = textCast->_initialRect.width(); //_sprites[spriteId]->_width;
+ }
+
+ sp->_startBbox = Common::Rect(x, y, x + width, y + height);
+ break;
+ }
+ case kCastButton: {
+ uint16 castId = sp->_castId;
+
+ // This may not be a button cast. It could be a textcast with the
+ // channel forcing it to be a checkbox or radio button!
+ ButtonCast *button = (ButtonCast *)_vm->getCurrentScore()->_loadedCast->getVal(castId);
+
+ // Sometimes, at least in the D3 Workshop Examples, these buttons are
+ // just TextCast. If they are, then we just want to use the spriteType
+ // as the button type. If they are full-bown Cast members, then use the
+ // actual cast member type.
+ int buttonType = sp->_spriteType;
+ if (buttonType == kCastMemberSprite) {
+ switch (button->_buttonType) {
+ case kTypeCheckBox:
+ buttonType = kCheckboxSprite;
+ break;
+ case kTypeButton:
+ buttonType = kButtonSprite;
+ break;
+ case kTypeRadio:
+ buttonType = kRadioButtonSprite;
+ break;
+ }
+ }
+
+ uint32 rectLeft = button->_initialRect.left;
+ uint32 rectTop = button->_initialRect.top;
+
+ int x = sp->_currentPoint.x;
+ int y = sp->_currentPoint.y;
+
+ if (_vm->getVersion() > 3) {
+ x += rectLeft;
+ y += rectTop;
+ }
+
+ int height = button->_initialRect.height();
+ int width = button->_initialRect.width() + 3;
+
+ switch (buttonType) {
+ case kCheckboxSprite:
+ // Magic numbers: checkbox square need to move left about 5px from
+ // text and 12px side size (D4)
+ sp->_startBbox = Common::Rect(x, y + 2, x + 12, y + 14);
+ break;
+ case kButtonSprite:
+ sp->_startBbox = Common::Rect(x, y, x + width, y + height + 3);
+ break;
+ case kRadioButtonSprite:
+ sp->_startBbox = Common::Rect(x, y + 2, x + 12, y + 14);
+ break;
+ default:
+ warning("Score::setSpriteBboxes: Unknown buttonType");
+ }
+ break;
+ }
+ case kCastBitmap: {
+ BitmapCast *bc = (BitmapCast *)sp->_cast;
+
+ int32 regX = bc->_regX;
+ int32 regY = bc->_regY;
+ int32 rectLeft = bc->_initialRect.left;
+ int32 rectTop = bc->_initialRect.top;
+
+ int x = sp->_currentPoint.x - regX + rectLeft;
+ int y = sp->_currentPoint.y - regY + rectTop;
+ int height = sp->_height;
+ int width = _vm->getVersion() > 4 ? bc->_initialRect.width() : sp->_width;
+
+ sp->_startBbox = Common::Rect(x, y, x + width, y + height);
+ break;
+ }
+ default:
+ warning("Score::setSpriteBboxes(): Unhandled cast type: %d", castType);
+ }
+ sp->_currentBbox = sp->_startBbox;
+ sp->_dirtyBbox = sp->_startBbox;
+ }
+ }
+}
+
void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id, Resource *res) {
// IDs are stored as relative to the start of the cast array.
id += _castArrayStart;
diff --git a/engines/director/score.h b/engines/director/score.h
index 5b6044d674..4648ff0604 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -89,6 +89,7 @@ public:
Common::String getMacName() const { return _macName; }
Sprite *getSpriteById(uint16 id);
void setSpriteCasts();
+ void setSpriteBboxes();
void loadSpriteImages(bool isSharedCast);
void loadSpriteSounds(bool isSharedCast);
void copyCastStxts();
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 0e9408db09..e7b12bc862 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -53,10 +53,6 @@ Sprite::Sprite() {
_backColor = 255;
_foreColor = 0;
- _left = 0;
- _right = 0;
- _top = 0;
- _bottom = 0;
_blend = 0;
_visible = false;
_movieRate = 0;
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 7009c63978..796ac84b8e 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -84,6 +84,9 @@ public:
byte _thickness;
Common::Point _startPoint;
Common::Point _currentPoint;
+ Common::Rect _startBbox;
+ Common::Rect _currentBbox;
+ Common::Rect _dirtyBbox;
uint16 _width;
uint16 _height;
// TODO: default constraint = 0, if turned on, sprite is constrainted to the bounding rect
@@ -95,10 +98,6 @@ public:
byte _backColor;
byte _foreColor;
- uint16 _left;
- uint16 _right;
- uint16 _top;
- uint16 _bottom;
byte _blend;
bool _visible;
// Using in digital movie sprites
Commit: 9fc6197c32688443921c70e1d3b54fe9092ce952
https://github.com/scummvm/scummvm/commit/9fc6197c32688443921c70e1d3b54fe9092ce952
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-05-17T23:21:33+02:00
Commit Message:
DIRECTOR: Precompute cast types of sprite
Changed paths:
engines/director/frame.cpp
engines/director/frame.h
engines/director/score.cpp
engines/director/sprite.h
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 2a741b9e5f..f506fd00e9 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -553,62 +553,6 @@ void Frame::playSoundChannel() {
debug(0, "STUB: playSoundChannel(), Sound1 %d Sound2 %d", _sound1, _sound2);
}
-CastType Frame::getCastType(uint16 spriteId) {
- CastType castType = kCastTypeNull;
- Sprite *sprite = _sprites[spriteId];
-
- if (_vm->getVersion() < 4) {
- debugC(1, kDebugImages, "Frame::getCastType(): Channel: %d type: %d", spriteId, sprite->_spriteType);
- switch (sprite->_spriteType) {
- case kBitmapSprite:
- castType = kCastBitmap;
- break;
- case kRectangleSprite:
- case kRoundedRectangleSprite:
- case kOvalSprite:
- case kLineTopBottomSprite:
- case kLineBottomTopSprite:
- case kOutlinedRectangleSprite:
- case kOutlinedRoundedRectangleSprite:
- case kOutlinedOvalSprite:
- case kCastMemberSprite:
- if (sprite->_cast != nullptr) {
- switch (sprite->_cast->_type) {
- case kCastButton:
- castType = kCastButton;
- break;
- default:
- castType = kCastShape;
- break;
- }
- } else {
- castType = kCastShape;
- }
- break;
- case kTextSprite:
- castType = kCastText;
- break;
- case kButtonSprite:
- case kCheckboxSprite:
- case kRadioButtonSprite:
- castType = kCastButton;
- break;
- default:
- warning("Frame::getCastType(): Unhandled sprite type %d", sprite->_spriteType);
- break;
- }
- } else {
- Cast *member = _vm->getCastMember(_sprites[spriteId]->_castId);
- if (!member) {
- debugC(1, kDebugImages, "Frame::renderSprites(): Cast id %d not found", _sprites[spriteId]->_castId);
- } else {
- castType = member->_type;
- }
- }
-
- return castType;
-}
-
void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
for (uint16 i = 0; i <= _numChannels; i++) {
if (!_sprites[i]->_enabled)
@@ -617,7 +561,7 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail))
continue;
- CastType castType = getCastType(i);
+ CastType castType = _sprites[i]->_castType;
if (castType == kCastTypeNull)
continue;
diff --git a/engines/director/frame.h b/engines/director/frame.h
index 96a4525292..5ab89bd330 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -76,7 +76,6 @@ public:
uint16 getSpriteIDFromPos(Common::Point pos);
bool checkSpriteIntersection(uint16 spriteId, Common::Point pos);
Common::Rect *getSpriteRect(uint16 spriteId);
- CastType getCastType(uint16 spriteId);
void executeImmediateScripts();
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index ef0ce793a5..b04454bc20 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -767,6 +767,59 @@ void Score::setSpriteCasts() {
Cast *member = _vm->getCastMember(castId);
if (member) {
_frames[i]->_sprites[j]->_cast = member;
+
+ CastType castType = kCastTypeNull;
+ Sprite *sprite = _frames[i]->_sprites[j];
+
+ if (_vm->getVersion() < 4) {
+ debugC(1, kDebugImages, "Score::setSpriteCasts(): Frame: %d Channel: %d type: %d", i, j, sprite->_spriteType);
+ switch (sprite->_spriteType) {
+ case kBitmapSprite:
+ castType = kCastBitmap;
+ break;
+ case kRectangleSprite:
+ case kRoundedRectangleSprite:
+ case kOvalSprite:
+ case kLineTopBottomSprite:
+ case kLineBottomTopSprite:
+ case kOutlinedRectangleSprite:
+ case kOutlinedRoundedRectangleSprite:
+ case kOutlinedOvalSprite:
+ case kCastMemberSprite:
+ if (sprite->_cast != nullptr) {
+ switch (sprite->_cast->_type) {
+ case kCastButton:
+ castType = kCastButton;
+ break;
+ default:
+ castType = kCastShape;
+ break;
+ }
+ } else {
+ castType = kCastShape;
+ }
+ break;
+ case kTextSprite:
+ castType = kCastText;
+ break;
+ case kButtonSprite:
+ case kCheckboxSprite:
+ case kRadioButtonSprite:
+ castType = kCastButton;
+ break;
+ default:
+ warning("Score::setSpriteCasts(): Unhandled sprite type %d", sprite->_spriteType);
+ break;
+ }
+ } else {
+ member = _vm->getCastMember(sprite->_castId);
+ if (!member) {
+ debugC(1, kDebugImages, "Score::setSpriteCasts(): Cast id %d not found", sprite->_castId);
+ } else {
+ castType = member->_type;
+ }
+ }
+ sprite->_castType = castType;
}
}
}
@@ -780,7 +833,7 @@ void Score::setSpriteBboxes() {
if (sp->_castId == 0)
continue;
- CastType castType = _frames[i]->getCastType(j);
+ CastType castType = sp->_castType;
switch (castType) {
case kCastShape:
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 796ac84b8e..844d175fa6 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -75,6 +75,7 @@ public:
uint16 _castId;
uint16 _castIndex;
SpriteType _spriteType;
+ CastType _castType;
byte _inkData;
InkType _ink;
uint16 _trails;
Commit: 5babbb30db4f71ca31b92d26fc935ab508a25c8d
https://github.com/scummvm/scummvm/commit/5babbb30db4f71ca31b92d26fc935ab508a25c8d
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-05-17T23:21:33+02:00
Commit Message:
DIRECTOR: Move to channel-based rendering
Changed paths:
engines/director/events.cpp
engines/director/frame.cpp
engines/director/frame.h
engines/director/lingo/lingo-builtins.cpp
engines/director/lingo/lingo-the.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 05909b5656..6af7ef8ed4 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -62,7 +62,6 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
warning("processEvents: request to access frame %d of %d", sc->getCurrentFrame(), sc->_frames.size() - 1);
return;
}
- Frame *currentFrame = sc->_frames[sc->getCurrentFrame()];
uint16 spriteId = 0;
Common::Point pos;
@@ -82,7 +81,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
sc->_lastRollTime = sc->_lastEventTime;
if (_draggingSprite) {
- Sprite *draggedSprite = currentFrame->_sprites[_draggingSpriteId];
+ Sprite *draggedSprite = sc->_sprites[_draggingSpriteId];
if (draggedSprite->_moveable) {
pos = g_system->getEventManager()->getMousePos();
Common::Point delta = pos - _draggingSpritePos;
@@ -101,7 +100,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
// D3 doesn't have both mouse up and down.
// But we still want to know if the mouse is down for press effects.
- spriteId = currentFrame->getSpriteIDFromPos(pos);
+ spriteId = sc->getSpriteIDFromPos(pos);
sc->_currentMouseDownSpriteId = spriteId;
sc->_mouseIsDown = true;
@@ -111,7 +110,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
debugC(3, kDebugEvents, "event: Button Down @(%d, %d), sprite id: %d", pos.x, pos.y, spriteId);
_lingo->registerEvent(kEventMouseDown);
- if (currentFrame->_sprites[spriteId]->_moveable)
+ if (sc->_sprites[spriteId]->_moveable)
g_director->setDraggedSprite(spriteId);
break;
@@ -119,7 +118,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
case Common::EVENT_LBUTTONUP:
pos = g_system->getEventManager()->getMousePos();
- spriteId = currentFrame->getSpriteIDFromPos(pos);
+ spriteId = sc->getSpriteIDFromPos(pos);
debugC(3, kDebugEvents, "event: Button Up @(%d, %d), sprite id: %d", pos.x, pos.y, spriteId);
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index f506fd00e9..782a39f64b 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -23,13 +23,9 @@
#include "common/system.h"
#include "common/substream.h"
-#include "graphics/macgui/macfontmanager.h"
-#include "graphics/macgui/macwindowmanager.h"
-#include "graphics/macgui/maceditabletext.h"
#include "graphics/primitives.h"
#include "director/director.h"
-#include "director/cachedmactext.h"
#include "director/cast.h"
#include "director/frame.h"
#include "director/score.h"
@@ -525,662 +521,4 @@ void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offse
}
-void Frame::prepareFrame(Score *score, bool updateStageOnly) {
- renderSprites(*score->_surface, false);
- renderSprites(*score->_trailSurface, true);
-
- if (!updateStageOnly) {
- score->renderZoomBox();
-
- _vm->_wm->draw();
-
- if (_transType != 0)
- // TODO Handle changing area case
- playTransition(score);
-
- if (_sound1 != 0 || _sound2 != 0) {
- playSoundChannel();
- }
-
- if (_vm->getCurrentScore()->haveZoomBox())
- score->_backSurface->copyFrom(*score->_surface);
- }
-
- g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, score->_surface->getBounds().width(), score->_surface->getBounds().height());
-}
-
-void Frame::playSoundChannel() {
- debug(0, "STUB: playSoundChannel(), Sound1 %d Sound2 %d", _sound1, _sound2);
-}
-
-void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
- for (uint16 i = 0; i <= _numChannels; i++) {
- if (!_sprites[i]->_enabled)
- continue;
-
- if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail))
- continue;
-
- CastType castType = _sprites[i]->_castType;
- if (castType == kCastTypeNull)
- continue;
-
- // this needs precedence to be hit first... D3 does something really tricky with cast IDs for shapes.
- // I don't like this implementation 100% as the 'cast' above might not actually hit a member and be null?
- debugC(1, kDebugImages, "Frame::renderSprites(): Channel: %d castType: %d", i, castType);
-
- _sprites[i]->_currentBbox = _sprites[i]->_dirtyBbox;
-
- if (castType == kCastShape) {
- renderShape(surface, i);
- } else if (castType == kCastText || castType == kCastRTE) {
- renderText(surface, i, NULL);
- } else if (castType == kCastButton) {
- renderButton(surface, i);
- } else {
- if (!_sprites[i]->_cast || _sprites[i]->_cast->_type != kCastBitmap) {
- warning("Frame::renderSprites(): No cast ID for sprite %d", i);
- continue;
- }
- if (_sprites[i]->_cast->_surface == nullptr) {
- warning("Frame::renderSprites(): No cast surface for sprite %d", i);
- continue;
- }
-
- renderBitmap(surface, i);
- }
- }
-}
-
-void Frame::renderShape(Graphics::ManagedSurface &surface, uint16 spriteId) {
- Sprite *sp = _sprites[spriteId];
-
- InkType ink = sp->_ink;
- byte spriteType = sp->_spriteType;
- byte foreColor = sp->_foreColor;
- byte backColor = sp->_backColor;
- int lineSize = sp->_thickness & 0x3;
-
- if (_vm->getVersion() >= 3 && spriteType == kCastMemberSprite) {
- if (!sp->_cast) {
- warning("Frame::renderShape(): kCastMemberSprite has no cast defined");
- return;
- }
- switch (sp->_cast->_type) {
- case kCastShape:
- {
- ShapeCast *sc = (ShapeCast *)sp->_cast;
- switch (sc->_shapeType) {
- case kShapeRectangle:
- spriteType = sc->_fillType ? kRectangleSprite : kOutlinedRectangleSprite;
- break;
- case kShapeRoundRect:
- spriteType = sc->_fillType ? kRoundedRectangleSprite : kOutlinedRoundedRectangleSprite;
- break;
- case kShapeOval:
- spriteType = sc->_fillType ? kOvalSprite : kOutlinedOvalSprite;
- break;
- case kShapeLine:
- spriteType = sc->_lineDirection == 6 ? kLineBottomTopSprite : kLineTopBottomSprite;
- break;
- default:
- break;
- }
- if (_vm->getVersion() > 3) {
- foreColor = sc->_fgCol;
- backColor = sc->_bgCol;
- lineSize = sc->_lineThickness;
- ink = sc->_ink;
- }
- // shapes should be rendered with transparency by default
- if (ink == kInkTypeCopy) {
- ink = kInkTypeTransparent;
- }
- }
- break;
- default:
- warning("Frame::renderShape(): Unhandled cast type: %d", sp->_cast->_type);
- break;
- }
- }
-
- // for outlined shapes, line thickness of 1 means invisible.
- lineSize -= 1;
-
- Common::Rect shapeRect = sp->_currentBbox;
-
- Graphics::ManagedSurface tmpSurface, maskSurface;
- tmpSurface.create(shapeRect.width(), shapeRect.height(), Graphics::PixelFormat::createFormatCLUT8());
- tmpSurface.clear(backColor);
-
- maskSurface.create(shapeRect.width(), shapeRect.height(), Graphics::PixelFormat::createFormatCLUT8());
- maskSurface.clear(0);
-
- // Draw fill
- Common::Rect fillRect((int)shapeRect.width(), (int)shapeRect.height());
- Graphics::MacPlotData plotFill(&tmpSurface, &maskSurface, &_vm->getPatterns(), sp->getPattern(), -shapeRect.left, -shapeRect.top, 1, backColor);
- switch (spriteType) {
- case kRectangleSprite:
- Graphics::drawFilledRect(fillRect, foreColor, Graphics::macDrawPixel, &plotFill);
- break;
- case kRoundedRectangleSprite:
- Graphics::drawRoundRect(fillRect, 12, foreColor, true, Graphics::macDrawPixel, &plotFill);
- break;
- case kOvalSprite:
- Graphics::drawEllipse(fillRect.left, fillRect.top, fillRect.right, fillRect.bottom, foreColor, true, Graphics::macDrawPixel, &plotFill);
- break;
- case kCastMemberSprite: // Face kit D3
- Graphics::drawFilledRect(fillRect, foreColor, Graphics::macDrawPixel, &plotFill);
- break;
- default:
- break;
- }
-
- // Draw stroke
- Common::Rect strokeRect(MAX((int)shapeRect.width() - lineSize, 0), MAX((int)shapeRect.height() - lineSize, 0));
- Graphics::MacPlotData plotStroke(&tmpSurface, &maskSurface, &_vm->getPatterns(), 1, -shapeRect.left, -shapeRect.top, lineSize, backColor);
- switch (spriteType) {
- case kLineTopBottomSprite:
- Graphics::drawLine(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, foreColor, Graphics::macDrawPixel, &plotStroke);
- break;
- case kLineBottomTopSprite:
- Graphics::drawLine(strokeRect.left, strokeRect.bottom, strokeRect.right, strokeRect.top, foreColor, Graphics::macDrawPixel, &plotStroke);
- break;
- case kRectangleSprite:
- // fall through
- case kOutlinedRectangleSprite: // this is actually a mouse-over shape? I don't think it's a real button.
- Graphics::drawRect(strokeRect, foreColor, Graphics::macDrawPixel, &plotStroke);
- //tmpSurface.fillRect(Common::Rect(shapeRect.width(), shapeRect.height()), (_vm->getCurrentScore()->_currentMouseDownSpriteId == spriteId ? 0 : 0xff));
- break;
- case kRoundedRectangleSprite:
- // fall through
- case kOutlinedRoundedRectangleSprite:
- Graphics::drawRoundRect(strokeRect, 12, foreColor, false, Graphics::macDrawPixel, &plotStroke);
- break;
- case kOvalSprite:
- // fall through
- case kOutlinedOvalSprite:
- Graphics::drawEllipse(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, foreColor, false, Graphics::macDrawPixel, &plotStroke);
- break;
- default:
- break;
- }
-
- inkBasedBlit(surface, &maskSurface, tmpSurface, ink, shapeRect, spriteId);
-}
-
-void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
- uint16 castId = _sprites[spriteId]->_castId;
-
- // This may not be a button cast. It could be a textcast with the channel forcing it
- // to be a checkbox or radio button!
- Cast *member = _vm->getCastMember(castId);
- if (!member) {
- warning("renderButton: unknown cast id %d", castId);
- } else if (member->_type != kCastButton) {
- warning("renderButton: cast id %d not of type kCastButton", castId);
- return;
- }
- ButtonCast *button = (ButtonCast *)member;
-
- // Sometimes, at least in the D3 Workshop Examples, these buttons are just TextCast.
- // If they are, then we just want to use the spriteType as the button type.
- // If they are full-bown Cast members, then use the actual cast member type.
- int buttonType = _sprites[spriteId]->_spriteType;
- if (buttonType == kCastMemberSprite) {
- switch (button->_buttonType) {
- case kTypeCheckBox:
- buttonType = kCheckboxSprite;
- break;
- case kTypeButton:
- buttonType = kButtonSprite;
- break;
- case kTypeRadio:
- buttonType = kRadioButtonSprite;
- break;
- }
- }
-
- bool invert = spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId;
-
- // TODO: review all cases to confirm if we should use text height.
- // height = textRect.height();
-
- Common::Rect _rect = _sprites[spriteId]->_currentBbox;
- int16 x = _rect.left;
- int16 y = _rect.top;
-
- Common::Rect textRect(0, 0, _rect.width(), _rect.height());
-
- // WORKAROUND, HACK
- // Because we're not drawing text with transparency
- // We swap drawing depending on whether the button is
- // inverted or not, to prevent destroying the border
- if (!invert)
- renderText(surface, spriteId, &textRect);
-
- Graphics::MacPlotData plotStroke(&surface, nullptr, &_vm->getPatterns(), 1, 0, 0, 1, 0);
-
- switch (buttonType) {
- case kCheckboxSprite:
- surface.frameRect(_rect, 0);
- break;
- case kButtonSprite: {
- Graphics::MacPlotData pd(&surface, nullptr, &_vm->getMacWindowManager()->getPatterns(), Graphics::MacGUIConstants::kPatternSolid, 0, 0, 1, invert ? Graphics::kColorBlack : Graphics::kColorWhite);
-
- Graphics::drawRoundRect(_rect, 4, 0, invert, Graphics::macDrawPixel, &pd);
- }
- break;
- case kRadioButtonSprite:
- Graphics::drawEllipse(x, y + 2, x + 11, y + 13, 0, false, Graphics::macDrawPixel, &plotStroke);
- break;
- default:
- warning("renderButton: Unknown buttonType");
- break;
- }
-
- if (invert)
- renderText(surface, spriteId, &textRect);
-}
-
-void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteId, Common::Rect *textRect) {
- TextCast *textCast = (TextCast*)_sprites[spriteId]->_cast;
- if (textCast == nullptr) {
- warning("Frame::renderText(): TextCast #%d is a nullptr", spriteId);
- return;
- }
-
- Score *score = _vm->getCurrentScore();
- Sprite *sprite = _sprites[spriteId];
-
- Common::Rect bbox = sprite->_currentBbox;
- int width = bbox.width();
- int height = bbox.height();
- int x = bbox.left;
- int y = bbox.top;
-
- if (_vm->getCurrentScore()->_fontMap.contains(textCast->_fontId)) {
- // We need to make sure that the Shared Cast fonts have been loaded in?
- // might need a mapping table here of our own.
- // textCast->fontId = _vm->_wm->_fontMan->getFontIdByName(_vm->getCurrentScore()->_fontMap[textCast->fontId]);
- }
-
- if (width == 0 || height == 0) {
- warning("Frame::renderText(): Requested to draw on an empty surface: %d x %d", width, height);
- return;
- }
-
- if (sprite->_editable) {
- if (!textCast->_widget) {
- warning("Creating MacEditableText with '%s'", toPrintable(textCast->_ftext).c_str());
- textCast->_widget = new Graphics::MacEditableText(score->_window, x, y, width, height, g_director->_wm, textCast->_ftext, new Graphics::MacFont(), 0, 255, width);
- warning("Finished creating MacEditableText");
- }
-
- textCast->_widget->draw();
-
- InkType ink = sprite->_ink;
-
- if (spriteId == score->_currentMouseDownSpriteId)
- ink = kInkTypeReverse;
-
- inkBasedBlit(surface, nullptr, textCast->_widget->getSurface()->rawSurface(), ink, Common::Rect(x, y, x + width, y + height), spriteId);
-
- return;
- }
-
- debugC(3, kDebugText, "renderText: sprite: %d x: %d y: %d w: %d h: %d fontId: '%d' text: '%s'", spriteId, x, y, width, height, textCast->_fontId, Common::toPrintable(textCast->_ftext).c_str());
-
- uint16 boxShadow = (uint16)textCast->_boxShadow;
- uint16 borderSize = (uint16)textCast->_borderSize;
- if (textRect != NULL)
- borderSize = 0;
- uint16 padding = (uint16)textCast->_gutterSize;
- uint16 textShadow = (uint16)textCast->_textShadow;
-
- //uint32 rectLeft = textCast->initialRect.left;
- //uint32 rectTop = textCast->initialRect.top;
-
- textCast->_cachedMacText->clip(width);
- const Graphics::ManagedSurface *textSurface = textCast->_cachedMacText->getSurface();
-
- if (!textSurface)
- return;
-
- height = textSurface->h;
- if (textRect != NULL) {
- // TODO: this offset could be due to incorrect fonts loaded!
- textRect->bottom = height + textCast->_cachedMacText->getLineCount();
- }
-
- uint16 textX = 0, textY = 0;
-
- if (textRect == NULL) {
- if (borderSize > 0) {
- if (_vm->getVersion() <= 3) {
- height += (borderSize * 2);
- textX += (borderSize + 2);
- } else {
- height += borderSize;
- textX += (borderSize + 1);
- }
- textY += borderSize;
- } else {
- x += 1;
- }
-
- if (padding > 0) {
- width += padding * 2;
- height += padding;
- textY += padding / 2;
- }
-
- if (textCast->_textAlign == kTextAlignRight)
- textX -= 1;
-
- if (textShadow > 0)
- textX--;
- } else {
- x++;
- if (width % 2 != 0)
- x++;
-
- if (sprite->_spriteType != kCastMemberSprite) {
- y += 2;
- switch (sprite->_spriteType) {
- case kCheckboxSprite:
- textX += 16;
- break;
- case kRadioButtonSprite:
- textX += 17;
- break;
- default:
- break;
- }
- } else {
- ButtonType buttonType = ((ButtonCast*)textCast)->_buttonType;
- switch (buttonType) {
- case kTypeCheckBox:
- width += 4;
- textX += 16;
- break;
- case kTypeRadio:
- width += 4;
- textX += 17;
- break;
- case kTypeButton:
- width += 4;
- y += 2;
- break;
- default:
- warning("Frame::renderText(): Expected button but got unexpected button type: %d", buttonType);
- y += 2;
- break;
- }
- }
- }
-
- switch (textCast->_textAlign) {
- case kTextAlignLeft:
- default:
- break;
- case kTextAlignCenter:
- textX = (width / 2) - (textSurface->w / 2) + (padding / 2) + borderSize;
- break;
- case kTextAlignRight:
- textX = width - (textSurface->w + 1) + (borderSize * 2) - (textShadow * 2) - (padding);
- break;
- }
-
- Graphics::ManagedSurface textWithFeatures(width + (borderSize * 2) + boxShadow + textShadow, height + borderSize + boxShadow + textShadow);
- textWithFeatures.fillRect(Common::Rect(textWithFeatures.w, textWithFeatures.h), score->getStageColor());
-
- if (textRect == NULL && boxShadow > 0) {
- textWithFeatures.fillRect(Common::Rect(boxShadow, boxShadow, textWithFeatures.w + boxShadow, textWithFeatures.h), 0);
- }
-
- if (textRect == NULL && borderSize != kSizeNone) {
- for (int bb = 0; bb < borderSize; bb++) {
- Common::Rect borderRect(bb, bb, textWithFeatures.w - bb - boxShadow - textShadow, textWithFeatures.h - bb - boxShadow - textShadow);
- textWithFeatures.fillRect(borderRect, 0xff);
- textWithFeatures.frameRect(borderRect, 0);
- }
- }
-
- if (textShadow > 0)
- textWithFeatures.transBlitFrom(textSurface->rawSurface(), Common::Point(textX + textShadow, textY + textShadow), 0xff);
-
- textWithFeatures.transBlitFrom(textSurface->rawSurface(), Common::Point(textX, textY), 0xff);
-
- InkType ink = sprite->_ink;
-
- if (spriteId == score->_currentMouseDownSpriteId)
- ink = kInkTypeReverse;
-
- inkBasedBlit(surface, nullptr, textWithFeatures, ink, Common::Rect(x, y, x + width, y + height), spriteId);
-}
-
-void Frame::renderBitmap(Graphics::ManagedSurface &surface, uint16 spriteId) {
- InkType ink;
- Sprite *sprite = _sprites[spriteId];
-
- if (spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId)
- ink = kInkTypeReverse;
- else
- ink = sprite->_ink;
-
- BitmapCast *bc = (BitmapCast *)sprite->_cast;
- Common::Rect drawRect = sprite->_currentBbox;
-
- inkBasedBlit(surface, nullptr, *(bc->_surface), ink, drawRect, spriteId);
-}
-
-void Frame::inkBasedBlit(Graphics::ManagedSurface &targetSurface, const Graphics::ManagedSurface *maskSurface, const Graphics::Surface &spriteSurface, InkType ink, Common::Rect drawRect, uint spriteId) {
- // drawRect could be bigger than the spriteSurface. Clip it
- Common::Rect t(spriteSurface.w, spriteSurface.h);
- t.moveTo(drawRect.left, drawRect.top);
- drawRect.clip(t);
-
- switch (ink) {
- case kInkTypeCopy:
- if (maskSurface)
- targetSurface.transBlitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top), *maskSurface);
- else
- targetSurface.blitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top));
- break;
- case kInkTypeTransparent:
- // FIXME: is it always white (last entry in pallette)?
- targetSurface.transBlitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top), _vm->getPaletteColorCount() - 1);
- break;
- case kInkTypeBackgndTrans:
- drawBackgndTransSprite(targetSurface, spriteSurface, drawRect, spriteId);
- break;
- case kInkTypeMatte:
- drawMatteSprite(targetSurface, spriteSurface, drawRect);
- break;
- case kInkTypeGhost:
- drawGhostSprite(targetSurface, spriteSurface, drawRect);
- break;
- case kInkTypeReverse:
- drawReverseSprite(targetSurface, spriteSurface, drawRect, spriteId);
- break;
- default:
- warning("Frame::inkBasedBlit(): Unhandled ink type %d", ink);
- targetSurface.blitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top));
- break;
- }
-}
-
-void Frame::drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect, int spriteId) {
- byte skipColor = _sprites[spriteId]->_backColor;
- Common::Rect srcRect(sprite.w, sprite.h);
-
- if (!target.clip(srcRect, drawRect))
- return; // Out of screen
-
- for (int ii = 0; ii < srcRect.height(); ii++) {
- const byte *src = (const byte *)sprite.getBasePtr(srcRect.left, srcRect.top + ii);
- byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii);
-
- for (int j = 0; j < srcRect.width(); j++) {
- if (*src != skipColor)
- *dst = *src;
-
- src++;
- dst++;
- }
- }
-}
-
-void Frame::drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) {
- Common::Rect srcRect(sprite.w, sprite.h);
-
- if (!target.clip(srcRect, drawRect))
- return; // Out of screen
-
- uint8 skipColor = _vm->getPaletteColorCount() - 1;
- for (int ii = 0; ii < srcRect.height(); ii++) {
- const byte *src = (const byte *)sprite.getBasePtr(srcRect.left, srcRect.top + ii);
- byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii);
-
- for (int j = 0; j < srcRect.width(); j++) {
- if ((getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii)) != 0) && (*src != skipColor))
- *dst = (_vm->getPaletteColorCount() - 1) - *src; // Oposite color
-
- src++;
- dst++;
- }
- }
-}
-
-void Frame::drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect, uint16 spriteId) {
- Common::Rect srcRect(sprite.w, sprite.h);
-
- if (!target.clip(srcRect, drawRect))
- return; // Out of screen
-
- uint8 skipColor = _vm->getPaletteColorCount() - 1;
- for (int ii = 0; ii < srcRect.height(); ii++) {
- const byte *src = (const byte *)sprite.getBasePtr(srcRect.left, srcRect.top + ii);
- byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii);
- byte srcColor = *src;
-
- for (int j = 0; j < srcRect.width(); j++) {
- if (_sprites[spriteId]->_cast->_type == kCastShape)
- srcColor = 0x0;
- else
- srcColor = *src;
- uint16 targetSprite = getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii));
- if ((targetSprite != 0)) {
- // TODO: This entire reverse colour attempt needs a lot more testing on
- // a lot more colour depths.
- if (srcColor != skipColor) {
- if (_sprites[targetSprite]->_cast->_type != kCastBitmap) {
- if (*dst == 0 || *dst == 255) {
- *dst = _vm->transformColor(*dst);
- } else if (srcColor == 255 || srcColor == 0) {
- *dst = _vm->transformColor(*dst - 40);
- } else {
- *dst = _vm->transformColor(*src - 40);
- }
- } else {
- if (*dst == 0 && _vm->getVersion() == 3 &&
- ((BitmapCast*)_sprites[spriteId]->_cast)->_bitsPerPixel > 1) {
- *dst = _vm->transformColor(*src - 40);
- } else {
- *dst ^= _vm->transformColor(srcColor);
- }
- }
- }
- } else if (srcColor != skipColor) {
- *dst = _vm->transformColor(srcColor);
- }
- src++;
- dst++;
- }
- }
-}
-
-void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) {
- // Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent
- Graphics::Surface tmp;
- tmp.copyFrom(sprite);
- Common::Rect srcRect(sprite.w, sprite.h);
-
- if (!target.clip(srcRect, drawRect))
- 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 (_vm->getPalette()[color * 3 + 0] == 0xff &&
- _vm->getPalette()[color * 3 + 1] == 0xff &&
- _vm->getPalette()[color * 3 + 2] == 0xff) {
- whiteColor = color;
- break;
- }
- }
- }
-
- if (whiteColor == -1) {
- debugC(1, kDebugImages, "Frame::drawMatteSprite(): No white color for Matte image");
-
- for (int yy = 0; yy < srcRect.height(); yy++) {
- const byte *src = (const byte *)tmp.getBasePtr(srcRect.left, srcRect.top + yy);
- byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy);
-
- for (int xx = 0; xx < drawRect.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 < srcRect.height(); yy++) {
- const byte *src = (const byte *)tmp.getBasePtr(srcRect.left, srcRect.top + yy);
- const byte *mask = (const byte *)ff.getMask()->getBasePtr(srcRect.left, srcRect.top + yy);
- byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy);
-
- for (int xx = 0; xx < srcRect.width(); xx++, src++, dst++, mask++)
- if (*mask == 0)
- *dst = *src;
- }
- }
-
- tmp.free();
-}
-
-uint16 Frame::getSpriteIDFromPos(Common::Point pos) {
- for (int i = _sprites.size() - 1; i >= 0; i--)
- if (_sprites[i]->_currentBbox.contains(pos))
- return i;
-
- return 0;
-}
-
-bool Frame::checkSpriteIntersection(uint16 spriteId, Common::Point pos) {
- if (_sprites[spriteId]->_currentBbox.contains(pos))
- return true;
-
- return false;
-}
-
-Common::Rect *Frame::getSpriteRect(uint16 spriteId) {
- return &_sprites[spriteId]->_currentBbox;
-}
-
} // End of namespace Director
diff --git a/engines/director/frame.h b/engines/director/frame.h
index 5ab89bd330..684488841d 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -72,31 +72,19 @@ public:
~Frame();
void readChannels(Common::ReadStreamEndian *stream);
void readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size);
- void prepareFrame(Score *score, bool updateStageOnly = false);
- uint16 getSpriteIDFromPos(Common::Point pos);
- bool checkSpriteIntersection(uint16 spriteId, Common::Point pos);
- Common::Rect *getSpriteRect(uint16 spriteId);
void executeImmediateScripts();
-private:
void playTransition(Score *score);
- void playSoundChannel();
- void renderSprites(Graphics::ManagedSurface &surface, bool renderTrail);
- void renderText(Graphics::ManagedSurface &surface, uint16 spriteId, Common::Rect *textSize);
- void renderShape(Graphics::ManagedSurface &surface, uint16 spriteId);
- void renderButton(Graphics::ManagedSurface &surface, uint16 spriteId);
- void renderBitmap(Graphics::ManagedSurface &surface, uint16 spriteId);
+
+private:
+
void readPaletteInfo(Common::SeekableSubReadStreamEndian &stream);
void readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size);
void readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size);
Image::ImageDecoder *getImageFrom(uint16 spriteId);
Common::String readTextStream(Common::SeekableSubReadStreamEndian *textStream, TextCast *textCast);
- void drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect, int spriteId);
- void drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect);
- void drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect);
- void drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect, uint16 spriteId);
- void inkBasedBlit(Graphics::ManagedSurface &targetSurface, const Graphics::ManagedSurface *maskSurface, const Graphics::Surface &spriteSurface, InkType ink, Common::Rect drawRect, uint spriteId);
+
public:
int _numChannels;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index f0ef57eaa0..17877d00fb 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1715,21 +1715,21 @@ void LB::b_rollOver(int nargs) {
Datum res(0);
int arg = d.asInt();
- if (!g_director->getCurrentScore()) {
+ Score *score = g_director->getCurrentScore();
+
+ if (!score) {
warning("b_rollOver: Reference to an empty score");
return;
}
- Frame *frame = g_director->getCurrentScore()->_frames[g_director->getCurrentScore()->getCurrentFrame()];
-
- if (arg >= (int32) frame->_sprites.size()) {
+ if (arg >= (int32) score->_sprites.size()) {
g_lingo->push(res);
return;
}
Common::Point pos = g_system->getEventManager()->getMousePos();
- if (frame->checkSpriteIntersection(arg, pos))
+ if (score->checkSpriteIntersection(arg, pos))
res.u.i = 1; // TRUE
g_lingo->push(res);
@@ -1775,9 +1775,8 @@ void LB::b_zoomBox(int nargs) {
Score *score = g_director->getCurrentScore();
uint16 curFrame = score->getCurrentFrame();
- Frame *frame = score->_frames[curFrame];
- Common::Rect *startRect = frame->getSpriteRect(startSprite);
+ Common::Rect *startRect = score->getSpriteRect(startSprite);
if (!startRect) {
warning("b_zoomBox: unknown start sprite #%d", startSprite);
return;
@@ -1785,10 +1784,10 @@ void LB::b_zoomBox(int nargs) {
// Looks for endSprite in the current frame, otherwise
// Looks for endSprite in the next frame
- Common::Rect *endRect = frame->getSpriteRect(endSprite);
+ Common::Rect *endRect = score->getSpriteRect(endSprite);
if (!endRect) {
if ((uint)curFrame + 1 < score->_frames.size())
- score->_frames[curFrame + 1]->getSpriteRect(endSprite);
+ endRect = &score->_frames[curFrame + 1]->_sprites[endSprite]->_currentBbox;
}
if (!endRect) {
@@ -1818,11 +1817,7 @@ void LB::b_updateStage(int nargs) {
return;
}
- uint16 curFrame = score->getCurrentFrame();
- Frame *frame = score->_frames[curFrame];
-
- frame->prepareFrame(score, true);
- g_director->processEvents(true);
+ score->renderFrame( score->getCurrentFrame(), false, true);
}
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 5459c5f44d..0383d7057d 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -427,10 +427,9 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
{
Common::Point pos = g_system->getEventManager()->getMousePos();
Score *sc = _vm->getCurrentScore();
- Frame *currentFrame = sc->_frames[sc->getCurrentFrame()];
- uint16 spriteId = currentFrame->getSpriteIDFromPos(pos);
+ uint16 spriteId = sc->getSpriteIDFromPos(pos);
d.type = INT;
- d.u.i = currentFrame->_sprites[spriteId]->_castId;
+ d.u.i = sc->_sprites[spriteId]->_castId;
if (d.u.i == 0)
d.u.i = -1;
}
@@ -735,6 +734,10 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
break;
case kThePuppet:
sprite->_puppet = d.asInt();
+ if (!d.u.i) {
+ sprite->_currentPoint = sprite->_startPoint;
+ sprite->_dirtyBbox = sprite->_startBbox;
+ }
break;
case kTheStartTime:
sprite->_startTime = d.asInt();
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index b04454bc20..70258152df 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -31,6 +31,8 @@
#include "graphics/primitives.h"
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/macgui/maceditabletext.h"
+#include "director/cachedmactext.h"
#include "image/bmp.h"
#include "director/director.h"
@@ -69,7 +71,7 @@ const char *scriptType2str(ScriptType scr) {
Score::Score(DirectorEngine *vm) {
_vm = vm;
_surface = nullptr;
- _trailSurface = nullptr;
+ _maskSurface = nullptr;
_backSurface = nullptr;
_backSurface2 = nullptr;
_lingo = _vm->getLingo();
@@ -454,8 +456,8 @@ void Score::loadSpriteSounds(bool isSharedCast) {
Score::~Score() {
- if (_trailSurface && _trailSurface->w)
- _trailSurface->free();
+ if (_maskSurface && _maskSurface->w)
+ _maskSurface->free();
if (_backSurface && _backSurface->w)
_backSurface->free();
@@ -465,7 +467,7 @@ Score::~Score() {
delete _backSurface;
delete _backSurface2;
- delete _trailSurface;
+ delete _maskSurface;
if (_window)
_vm->_wm->removeWindow(_window);
@@ -1706,14 +1708,16 @@ void Score::startLoop() {
_window->resize(_movieRect.width(), _movieRect.height());
_surface = _window->getWindowSurface();
- _trailSurface = new Graphics::ManagedSurface;
+ _maskSurface = new Graphics::ManagedSurface;
_backSurface = new Graphics::ManagedSurface;
_backSurface2 = new Graphics::ManagedSurface;
- _trailSurface->create(_movieRect.width(), _movieRect.height());
+ _maskSurface->create(_movieRect.width(), _movieRect.height());
_backSurface->create(_movieRect.width(), _movieRect.height());
_backSurface2->create(_movieRect.width(), _movieRect.height());
+ _sprites.resize(_frames[0]->_sprites.size());
+
if (_vm->_backSurface.w > 0) {
// Persist screen between the movies
// TODO: this is a workaround until the rendering pipeline is reworked
@@ -1728,7 +1732,7 @@ void Score::startLoop() {
_vm->_wm->setScreen(_surface);
- _trailSurface->clear(_stageColor);
+ _surface->clear(_stageColor);
_currentFrame = 0;
_stopPlay = false;
@@ -1736,7 +1740,8 @@ void Score::startLoop() {
_lingo->processEvent(kEventStartMovie);
- _frames[_currentFrame]->prepareFrame(this);
+ _sprites = _frames[_currentFrame]->_sprites;
+ renderFrame(_currentFrame, true);
while (!_stopPlay) {
if (_currentFrame >= _frames.size()) {
@@ -1818,8 +1823,8 @@ void Score::update() {
_vm->_newMovieStarted = false;
- _surface->clear(_stageColor);
- _surface->copyFrom(*_trailSurface);
+ // _surface->clear(_stageColor);
+ // _surface->copyFrom(*_trailSurface);
_lingo->executeImmediateScripts(_frames[_currentFrame]);
@@ -1830,7 +1835,7 @@ void Score::update() {
// TODO: Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
}
- _frames[_currentFrame]->prepareFrame(this);
+ renderFrame(_currentFrame);
// Stage is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
// Enter and exit from previous frame (Director 4)
@@ -1880,19 +1885,724 @@ void Score::update() {
_framesRan++;
}
+void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly) {
+ _maskSurface->clear(0);
+
+ Frame *currentFrame = _frames[frameId];
+
+ for (uint16 i = 0; i < _sprites.size(); i++) {
+ Sprite *currentSprite = _sprites[i];
+ Sprite *nextSprite;
+
+ if (currentSprite->_puppet)
+ nextSprite = currentSprite;
+ else
+ nextSprite = currentFrame->_sprites[i];
+
+ bool needsUpdate = (currentSprite->_currentBbox != nextSprite->_currentBbox || currentSprite->_currentBbox != currentSprite->_dirtyBbox);
+
+ if (needsUpdate || forceUpdate)
+ unrenderSprite(i);
+
+ _sprites[i] = nextSprite;
+ }
+
+ for (uint i = 0; i < _sprites.size(); i++)
+ renderSprite(i);
+
+ if (!updateStageOnly) {
+ renderZoomBox();
+
+ _vm->_wm->draw();
+
+ if (currentFrame->_transType != 0)
+ // TODO Handle changing area case
+ currentFrame->playTransition(this);
+
+ if (currentFrame->_sound1 != 0 || currentFrame->_sound2 != 0) {
+ playSoundChannel(frameId);
+ }
+
+ if (_vm->getCurrentScore()->haveZoomBox())
+ _backSurface->copyFrom(*_surface);
+ }
+
+ g_system->copyRectToScreen(_surface->getPixels(), _surface->pitch, 0, 0, _surface->getBounds().width(), _surface->getBounds().height());
+}
+
+void Score::unrenderSprite(uint16 spriteId) {
+ Sprite *currentSprite = _sprites[spriteId];
+
+ if (!currentSprite->_trails) {
+ _maskSurface->fillRect(currentSprite->_currentBbox, 1);
+ _surface->fillRect(currentSprite->_currentBbox, _stageColor);
+ }
+
+ currentSprite->_currentBbox = currentSprite->_dirtyBbox;
+}
+
+void Score::renderSprite(uint16 id) {
+ Sprite *sprite = _sprites[id];
+
+ if (!sprite)
+ return;
+
+ CastType castType = sprite->_castType;
+
+ _maskSurface->fillRect(sprite->_currentBbox, 1);
+
+ if (castType == kCastTypeNull)
+ return;
+
+ debugC(1, kDebugImages, "Score::renderFrame(): channel: %d, castType: %d", id, castType);
+ // this needs precedence to be hit first... D3 does something really tricky
+ // with cast IDs for shapes. I don't like this implementation 100% as the
+ // 'cast' above might not actually hit a member and be null?
+ if (castType == kCastShape) {
+ renderShape(id);
+ } else if (castType == kCastText || castType == kCastRTE) {
+ renderText(id, NULL);
+ } else if (castType == kCastButton) {
+ renderButton(id);
+ } else {
+ if (!sprite->_cast || sprite->_cast->_type != kCastBitmap) {
+ warning("Score::renderFrame(): No cast ID for sprite %d", id);
+ return;
+ }
+ if (sprite->_cast->_surface == nullptr) {
+ warning("Score::renderFrame(): No cast surface for sprite %d", id);
+ return;
+ }
+
+ renderBitmap(id);
+ }
+}
+
+void Score::renderShape(uint16 spriteId) {
+ Sprite *sp = _sprites[spriteId];
+
+ InkType ink = sp->_ink;
+ byte spriteType = sp->_spriteType;
+ byte foreColor = sp->_foreColor;
+ byte backColor = sp->_backColor;
+ int lineSize = sp->_thickness & 0x3;
+
+ if (_vm->getVersion() >= 3 && spriteType == kCastMemberSprite) {
+ if (!sp->_cast) {
+ warning("Frame::renderShape(): kCastMemberSprite has no cast defined");
+ return;
+ }
+ switch (sp->_cast->_type) {
+ case kCastShape:
+ {
+ ShapeCast *sc = (ShapeCast *)sp->_cast;
+ switch (sc->_shapeType) {
+ case kShapeRectangle:
+ spriteType = sc->_fillType ? kRectangleSprite : kOutlinedRectangleSprite;
+ break;
+ case kShapeRoundRect:
+ spriteType = sc->_fillType ? kRoundedRectangleSprite : kOutlinedRoundedRectangleSprite;
+ break;
+ case kShapeOval:
+ spriteType = sc->_fillType ? kOvalSprite : kOutlinedOvalSprite;
+ break;
+ case kShapeLine:
+ spriteType = sc->_lineDirection == 6 ? kLineBottomTopSprite : kLineTopBottomSprite;
+ break;
+ default:
+ break;
+ }
+ if (_vm->getVersion() > 3) {
+ foreColor = sc->_fgCol;
+ backColor = sc->_bgCol;
+ lineSize = sc->_lineThickness;
+ ink = sc->_ink;
+ }
+ // shapes should be rendered with transparency by default
+ if (ink == kInkTypeCopy) {
+ ink = kInkTypeTransparent;
+ }
+ }
+ break;
+ default:
+ warning("Frame::renderShape(): Unhandled cast type: %d", sp->_cast->_type);
+ break;
+ }
+ }
+
+ // for outlined shapes, line thickness of 1 means invisible.
+ lineSize -= 1;
+
+ Common::Rect shapeRect = sp->_currentBbox;
+
+ Graphics::ManagedSurface tmpSurface, maskSurface;
+ tmpSurface.create(shapeRect.width(), shapeRect.height(), Graphics::PixelFormat::createFormatCLUT8());
+ tmpSurface.clear(backColor);
+
+ maskSurface.create(shapeRect.width(), shapeRect.height(), Graphics::PixelFormat::createFormatCLUT8());
+ maskSurface.clear(0);
+
+ // Draw fill
+ Common::Rect fillRect((int)shapeRect.width(), (int)shapeRect.height());
+ Graphics::MacPlotData plotFill(&tmpSurface, &maskSurface, &_vm->getPatterns(), sp->getPattern(), -shapeRect.left, -shapeRect.top, 1, backColor);
+ switch (spriteType) {
+ case kRectangleSprite:
+ Graphics::drawFilledRect(fillRect, foreColor, Graphics::macDrawPixel, &plotFill);
+ break;
+ case kRoundedRectangleSprite:
+ Graphics::drawRoundRect(fillRect, 12, foreColor, true, Graphics::macDrawPixel, &plotFill);
+ break;
+ case kOvalSprite:
+ Graphics::drawEllipse(fillRect.left, fillRect.top, fillRect.right, fillRect.bottom, foreColor, true, Graphics::macDrawPixel, &plotFill);
+ break;
+ case kCastMemberSprite: // Face kit D3
+ Graphics::drawFilledRect(fillRect, foreColor, Graphics::macDrawPixel, &plotFill);
+ break;
+ default:
+ break;
+ }
+
+ // Draw stroke
+ Common::Rect strokeRect(MAX((int)shapeRect.width() - lineSize, 0), MAX((int)shapeRect.height() - lineSize, 0));
+ Graphics::MacPlotData plotStroke(&tmpSurface, &maskSurface, &_vm->getPatterns(), 1, -shapeRect.left, -shapeRect.top, lineSize, backColor);
+ switch (spriteType) {
+ case kLineTopBottomSprite:
+ Graphics::drawLine(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, foreColor, Graphics::macDrawPixel, &plotStroke);
+ break;
+ case kLineBottomTopSprite:
+ Graphics::drawLine(strokeRect.left, strokeRect.bottom, strokeRect.right, strokeRect.top, foreColor, Graphics::macDrawPixel, &plotStroke);
+ break;
+ case kRectangleSprite:
+ // fall through
+ case kOutlinedRectangleSprite: // this is actually a mouse-over shape? I don't think it's a real button.
+ Graphics::drawRect(strokeRect, foreColor, Graphics::macDrawPixel, &plotStroke);
+ //tmpSurface.fillRect(Common::Rect(shapeRect.width(), shapeRect.height()), (_vm->getCurrentScore()->_currentMouseDownSpriteId == spriteId ? 0 : 0xff));
+ break;
+ case kRoundedRectangleSprite:
+ // fall through
+ case kOutlinedRoundedRectangleSprite:
+ Graphics::drawRoundRect(strokeRect, 12, foreColor, false, Graphics::macDrawPixel, &plotStroke);
+ break;
+ case kOvalSprite:
+ // fall through
+ case kOutlinedOvalSprite:
+ Graphics::drawEllipse(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, foreColor, false, Graphics::macDrawPixel, &plotStroke);
+ break;
+ default:
+ break;
+ }
+
+ inkBasedBlit(&maskSurface, tmpSurface, ink, shapeRect, spriteId);
+}
+
+
+void Score::renderButton(uint16 spriteId) {
+ uint16 castId = _sprites[spriteId]->_castId;
+
+ // This may not be a button cast. It could be a textcast with the channel forcing it
+ // to be a checkbox or radio button!
+ Cast *member = _vm->getCastMember(castId);
+ if (!member) {
+ warning("renderButton: unknown cast id %d", castId);
+ } else if (member->_type != kCastButton) {
+ warning("renderButton: cast id %d not of type kCastButton", castId);
+ return;
+ }
+ ButtonCast *button = (ButtonCast *)member;
+
+ // Sometimes, at least in the D3 Workshop Examples, these buttons are just TextCast.
+ // If they are, then we just want to use the spriteType as the button type.
+ // If they are full-bown Cast members, then use the actual cast member type.
+ int buttonType = _sprites[spriteId]->_spriteType;
+ if (buttonType == kCastMemberSprite) {
+ switch (button->_buttonType) {
+ case kTypeCheckBox:
+ buttonType = kCheckboxSprite;
+ break;
+ case kTypeButton:
+ buttonType = kButtonSprite;
+ break;
+ case kTypeRadio:
+ buttonType = kRadioButtonSprite;
+ break;
+ }
+ }
+
+ bool invert = spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId;
+
+ // TODO: review all cases to confirm if we should use text height.
+ // height = textRect.height();
+
+ Common::Rect _rect = _sprites[spriteId]->_currentBbox;
+ int16 x = _rect.left;
+ int16 y = _rect.top;
+
+ Common::Rect textRect(0, 0, _rect.width(), _rect.height());
+
+ // WORKAROUND, HACK
+ // Because we're not drawing text with transparency
+ // We swap drawing depending on whether the button is
+ // inverted or not, to prevent destroying the border
+ if (!invert)
+ renderText(spriteId, &textRect);
+
+ Graphics::MacPlotData plotStroke(_surface, nullptr, &_vm->getPatterns(), 1, 0, 0, 1, 0);
+
+ switch (buttonType) {
+ case kCheckboxSprite:
+ _surface->frameRect(_rect, 0);
+ break;
+ case kButtonSprite: {
+ Graphics::MacPlotData pd(_surface, nullptr, &_vm->getMacWindowManager()->getPatterns(), Graphics::MacGUIConstants::kPatternSolid, 0, 0, 1, invert ? Graphics::kColorBlack : Graphics::kColorWhite);
+
+ Graphics::drawRoundRect(_rect, 4, 0, invert, Graphics::macDrawPixel, &pd);
+ }
+ break;
+ case kRadioButtonSprite:
+ Graphics::drawEllipse(x, y + 2, x + 11, y + 13, 0, false, Graphics::macDrawPixel, &plotStroke);
+ break;
+ default:
+ warning("renderButton: Unknown buttonType");
+ break;
+ }
+
+ if (invert)
+ renderText(spriteId, &textRect);
+}
+
+void Score::renderText(uint16 spriteId, Common::Rect *textRect) {
+ TextCast *textCast = (TextCast*)_sprites[spriteId]->_cast;
+ if (textCast == nullptr) {
+ warning("Frame::renderText(): TextCast #%d is a nullptr", spriteId);
+ return;
+ }
+
+ Score *score = _vm->getCurrentScore();
+ Sprite *sprite = _sprites[spriteId];
+
+ Common::Rect bbox = sprite->_currentBbox;
+ int width = bbox.width();
+ int height = bbox.height();
+ int x = bbox.left;
+ int y = bbox.top;
+
+ if (_vm->getCurrentScore()->_fontMap.contains(textCast->_fontId)) {
+ // We need to make sure that the Shared Cast fonts have been loaded in?
+ // might need a mapping table here of our own.
+ // textCast->fontId = _vm->_wm->_fontMan->getFontIdByName(_vm->getCurrentScore()->_fontMap[textCast->fontId]);
+ }
+
+ if (width == 0 || height == 0) {
+ warning("Frame::renderText(): Requested to draw on an empty surface: %d x %d", width, height);
+ return;
+ }
+
+ if (sprite->_editable) {
+ if (!textCast->_widget) {
+ warning("Creating MacEditableText with '%s'", toPrintable(textCast->_ftext).c_str());
+ textCast->_widget = new Graphics::MacEditableText(score->_window, x, y, width, height, g_director->_wm, textCast->_ftext, new Graphics::MacFont(), 0, 255, width);
+ warning("Finished creating MacEditableText");
+ }
+
+ textCast->_widget->draw();
+
+ InkType ink = sprite->_ink;
+
+ if (spriteId == score->_currentMouseDownSpriteId)
+ ink = kInkTypeReverse;
+
+ inkBasedBlit(nullptr, textCast->_widget->getSurface()->rawSurface(), ink, Common::Rect(x, y, x + width, y + height), spriteId);
+
+ return;
+ }
+
+ debugC(3, kDebugText, "renderText: sprite: %d x: %d y: %d w: %d h: %d fontId: '%d' text: '%s'", spriteId, x, y, width, height, textCast->_fontId, Common::toPrintable(textCast->_ftext).c_str());
+
+ uint16 boxShadow = (uint16)textCast->_boxShadow;
+ uint16 borderSize = (uint16)textCast->_borderSize;
+ if (textRect != NULL)
+ borderSize = 0;
+ uint16 padding = (uint16)textCast->_gutterSize;
+ uint16 textShadow = (uint16)textCast->_textShadow;
+
+ //uint32 rectLeft = textCast->initialRect.left;
+ //uint32 rectTop = textCast->initialRect.top;
+
+ textCast->_cachedMacText->clip(width);
+ const Graphics::ManagedSurface *textSurface = textCast->_cachedMacText->getSurface();
+
+ if (!textSurface)
+ return;
+
+ height = textSurface->h;
+ if (textRect != NULL) {
+ // TODO: this offset could be due to incorrect fonts loaded!
+ textRect->bottom = height + textCast->_cachedMacText->getLineCount();
+ }
+
+ uint16 textX = 0, textY = 0;
+
+ if (textRect == NULL) {
+ if (borderSize > 0) {
+ if (_vm->getVersion() <= 3) {
+ height += (borderSize * 2);
+ textX += (borderSize + 2);
+ } else {
+ height += borderSize;
+ textX += (borderSize + 1);
+ }
+ textY += borderSize;
+ } else {
+ x += 1;
+ }
+
+ if (padding > 0) {
+ width += padding * 2;
+ height += padding;
+ textY += padding / 2;
+ }
+
+ if (textCast->_textAlign == kTextAlignRight)
+ textX -= 1;
+
+ if (textShadow > 0)
+ textX--;
+ } else {
+ x++;
+ if (width % 2 != 0)
+ x++;
+
+ if (sprite->_spriteType != kCastMemberSprite) {
+ y += 2;
+ switch (sprite->_spriteType) {
+ case kCheckboxSprite:
+ textX += 16;
+ break;
+ case kRadioButtonSprite:
+ textX += 17;
+ break;
+ default:
+ break;
+ }
+ } else {
+ ButtonType buttonType = ((ButtonCast*)textCast)->_buttonType;
+ switch (buttonType) {
+ case kTypeCheckBox:
+ width += 4;
+ textX += 16;
+ break;
+ case kTypeRadio:
+ width += 4;
+ textX += 17;
+ break;
+ case kTypeButton:
+ width += 4;
+ y += 2;
+ break;
+ default:
+ warning("Frame::renderText(): Expected button but got unexpected button type: %d", buttonType);
+ y += 2;
+ break;
+ }
+ }
+ }
+
+ switch (textCast->_textAlign) {
+ case kTextAlignLeft:
+ default:
+ break;
+ case kTextAlignCenter:
+ textX = (width / 2) - (textSurface->w / 2) + (padding / 2) + borderSize;
+ break;
+ case kTextAlignRight:
+ textX = width - (textSurface->w + 1) + (borderSize * 2) - (textShadow * 2) - (padding);
+ break;
+ }
+
+ Graphics::ManagedSurface textWithFeatures(width + (borderSize * 2) + boxShadow + textShadow, height + borderSize + boxShadow + textShadow);
+ textWithFeatures.fillRect(Common::Rect(textWithFeatures.w, textWithFeatures.h), score->getStageColor());
+
+ if (textRect == NULL && boxShadow > 0) {
+ textWithFeatures.fillRect(Common::Rect(boxShadow, boxShadow, textWithFeatures.w + boxShadow, textWithFeatures.h), 0);
+ }
+
+ if (textRect == NULL && borderSize != kSizeNone) {
+ for (int bb = 0; bb < borderSize; bb++) {
+ Common::Rect borderRect(bb, bb, textWithFeatures.w - bb - boxShadow - textShadow, textWithFeatures.h - bb - boxShadow - textShadow);
+ textWithFeatures.fillRect(borderRect, 0xff);
+ textWithFeatures.frameRect(borderRect, 0);
+ }
+ }
+
+ if (textShadow > 0)
+ textWithFeatures.transBlitFrom(textSurface->rawSurface(), Common::Point(textX + textShadow, textY + textShadow), 0xff);
+
+ textWithFeatures.transBlitFrom(textSurface->rawSurface(), Common::Point(textX, textY), 0xff);
+
+ InkType ink = sprite->_ink;
+
+ if (spriteId == score->_currentMouseDownSpriteId)
+ ink = kInkTypeReverse;
+
+ inkBasedBlit(nullptr, textWithFeatures, ink, Common::Rect(x, y, x + width, y + height), spriteId);
+}
+
+void Score::renderBitmap(uint16 spriteId) {
+ InkType ink;
+ Sprite *sprite = _sprites[spriteId];
+
+ if (spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId)
+ ink = kInkTypeReverse;
+ else
+ ink = sprite->_ink;
+
+ BitmapCast *bc = (BitmapCast *)sprite->_cast;
+ Common::Rect drawRect = sprite->_currentBbox;
+
+ inkBasedBlit(nullptr, *(bc->_surface), ink, drawRect, spriteId);
+}
+
+void Score::inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::Surface &spriteSurface, InkType ink, Common::Rect drawRect, uint spriteId) {
+ // drawRect could be bigger than the spriteSurface. Clip it
+ Common::Rect t(spriteSurface.w, spriteSurface.h);
+ t.moveTo(drawRect.left, drawRect.top);
+ bool nullMask = false;
+
+ // combine the given mask with the maskSurface
+ if (!maskSurface) {
+ nullMask = true;
+ maskSurface = new Graphics::ManagedSurface;
+ maskSurface->create(spriteSurface.w, spriteSurface.h, Graphics::PixelFormat::createFormatCLUT8());
+ maskSurface->clear(0);
+ }
+
+ maskSurface->blitFrom(*_maskSurface, drawRect, Common::Point(0, 0));
+
+ drawRect.clip(t);
+
+ switch (ink) {
+ case kInkTypeCopy:
+ if (maskSurface)
+ _surface->transBlitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top), *maskSurface);
+ else
+ _surface->blitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top));
+ break;
+ case kInkTypeTransparent:
+ // FIXME: is it always white (last entry in pallette)?
+ _surface->transBlitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top), _vm->getPaletteColorCount() - 1);
+ break;
+ case kInkTypeBackgndTrans:
+ drawBackgndTransSprite(spriteSurface, drawRect, spriteId);
+ break;
+ case kInkTypeMatte:
+ drawMatteSprite(spriteSurface, drawRect);
+ break;
+ case kInkTypeGhost:
+ drawGhostSprite(spriteSurface, drawRect);
+ break;
+ case kInkTypeReverse:
+ drawReverseSprite(spriteSurface, drawRect, spriteId);
+ break;
+ default:
+ warning("Frame::inkBasedBlit(): Unhandled ink type %d", ink);
+ _surface->blitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top));
+ break;
+ }
+
+ if (nullMask)
+ delete maskSurface;
+}
+
+void Score::drawBackgndTransSprite(const Graphics::Surface &sprite, Common::Rect &drawRect, int spriteId) {
+ byte skipColor = _sprites[spriteId]->_backColor;
+ Common::Rect srcRect(sprite.w, sprite.h);
+
+ if (!_surface->clip(srcRect, drawRect))
+ return; // Out of screen
+
+ for (int ii = 0; ii < srcRect.height(); ii++) {
+ const byte *src = (const byte *)sprite.getBasePtr(srcRect.left, srcRect.top + ii);
+ byte *dst = (byte *)_surface->getBasePtr(drawRect.left, drawRect.top + ii);
+
+ for (int j = 0; j < srcRect.width(); j++) {
+ if (*src != skipColor)
+ *dst = *src;
+
+ src++;
+ dst++;
+ }
+ }
+}
+
+void Score::drawGhostSprite(const Graphics::Surface &sprite, Common::Rect &drawRect) {
+ Common::Rect srcRect(sprite.w, sprite.h);
+
+ if (!_surface->clip(srcRect, drawRect))
+ return; // Out of screen
+
+ uint8 skipColor = _vm->getPaletteColorCount() - 1;
+ for (int ii = 0; ii < srcRect.height(); ii++) {
+ const byte *src = (const byte *)sprite.getBasePtr(srcRect.left, srcRect.top + ii);
+ byte *dst = (byte *)_surface->getBasePtr(drawRect.left, drawRect.top + ii);
+
+ for (int j = 0; j < srcRect.width(); j++) {
+ if ((getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii)) != 0) && (*src != skipColor))
+ *dst = (_vm->getPaletteColorCount() - 1) - *src; // Oposite color
+
+ src++;
+ dst++;
+ }
+ }
+}
+
+void Score::drawReverseSprite(const Graphics::Surface &sprite, Common::Rect &drawRect, uint16 spriteId) {
+ Common::Rect srcRect(sprite.w, sprite.h);
+
+ if (!_surface->clip(srcRect, drawRect))
+ return; // Out of screen
+
+ uint8 skipColor = _vm->getPaletteColorCount() - 1;
+ for (int ii = 0; ii < srcRect.height(); ii++) {
+ const byte *src = (const byte *)sprite.getBasePtr(srcRect.left, srcRect.top + ii);
+ byte *dst = (byte *)_surface->getBasePtr(drawRect.left, drawRect.top + ii);
+ byte srcColor = *src;
+
+ for (int j = 0; j < srcRect.width(); j++) {
+ if (_sprites[spriteId]->_cast->_type == kCastShape)
+ srcColor = 0x0;
+ else
+ srcColor = *src;
+ uint16 targetSprite = getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii));
+ if ((targetSprite != 0)) {
+ // TODO: This entire reverse colour attempt needs a lot more testing on
+ // a lot more colour depths.
+ if (srcColor != skipColor) {
+ if (_sprites[targetSprite]->_cast->_type != kCastBitmap) {
+ if (*dst == 0 || *dst == 255) {
+ *dst = _vm->transformColor(*dst);
+ } else if (srcColor == 255 || srcColor == 0) {
+ *dst = _vm->transformColor(*dst - 40);
+ } else {
+ *dst = _vm->transformColor(*src - 40);
+ }
+ } else {
+ if (*dst == 0 && _vm->getVersion() == 3 &&
+ ((BitmapCast*)_sprites[spriteId]->_cast)->_bitsPerPixel > 1) {
+ *dst = _vm->transformColor(*src - 40);
+ } else {
+ *dst ^= _vm->transformColor(srcColor);
+ }
+ }
+ }
+ } else if (srcColor != skipColor) {
+ *dst = _vm->transformColor(srcColor);
+ }
+ src++;
+ dst++;
+ }
+ }
+}
+
+void Score::drawMatteSprite(const Graphics::Surface &sprite, Common::Rect &drawRect) {
+ // Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent
+ Graphics::Surface tmp;
+ tmp.copyFrom(sprite);
+ Common::Rect srcRect(sprite.w, sprite.h);
+
+ if (!_surface->clip(srcRect, drawRect))
+ 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 (_vm->getPalette()[color * 3 + 0] == 0xff &&
+ _vm->getPalette()[color * 3 + 1] == 0xff &&
+ _vm->getPalette()[color * 3 + 2] == 0xff) {
+ whiteColor = color;
+ break;
+ }
+ }
+ }
+
+ if (whiteColor == -1) {
+ debugC(1, kDebugImages, "Frame::drawMatteSprite(): No white color for Matte image");
+
+ for (int yy = 0; yy < srcRect.height(); yy++) {
+ const byte *src = (const byte *)tmp.getBasePtr(srcRect.left, srcRect.top + yy);
+ byte *dst = (byte *)_surface->getBasePtr(drawRect.left, drawRect.top + yy);
+
+ for (int xx = 0; xx < drawRect.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 < srcRect.height(); yy++) {
+ const byte *src = (const byte *)tmp.getBasePtr(srcRect.left, srcRect.top + yy);
+ const byte *mask = (const byte *)ff.getMask()->getBasePtr(srcRect.left, srcRect.top + yy);
+ byte *dst = (byte *)_surface->getBasePtr(drawRect.left, drawRect.top + yy);
+
+ for (int xx = 0; xx < srcRect.width(); xx++, src++, dst++, mask++)
+ if (*mask == 0)
+ *dst = *src;
+ }
+ }
+
+ tmp.free();
+}
+
+uint16 Score::getSpriteIDFromPos(Common::Point pos) {
+ for (int i = _sprites.size() - 1; i >= 0; i--)
+ if (_sprites[i]->_currentBbox.contains(pos))
+ return i;
+
+ return 0;
+}
+
+bool Score::checkSpriteIntersection(uint16 spriteId, Common::Point pos) {
+ if (_sprites[spriteId]->_currentBbox.contains(pos))
+ return true;
+
+ return false;
+}
+
+Common::Rect *Score::getSpriteRect(uint16 spriteId) {
+ return &_sprites[spriteId]->_currentBbox;
+}
+
Sprite *Score::getSpriteById(uint16 id) {
- if (_currentFrame >= _frames.size() || id >= _frames[_currentFrame]->_sprites.size()) {
+ if (id >= _sprites.size()) {
warning("Score::getSpriteById(%d): out of bounds. frame: %d", id, _currentFrame);
return nullptr;
}
- if (_frames[_currentFrame]->_sprites[id]) {
- return _frames[_currentFrame]->_sprites[id];
+ if (_sprites[id]) {
+ return _sprites[id];
} else {
warning("Sprite on frame %d width id %d not found", _currentFrame, id);
return nullptr;
}
}
+void Score::playSoundChannel(uint16 frameId) {
+ Frame *frame = _frames[frameId];
+ debug(0, "STUB: playSoundChannel(), Sound1 %d Sound2 %d", frame->_sound1, frame->_sound2);
+}
+
void Score::addZoomBox(ZoomBox *box) {
_zoomBoxes.push_back(box);
}
diff --git a/engines/director/score.h b/engines/director/score.h
index 4648ff0604..7547630016 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -102,6 +102,10 @@ public:
int getCurrentLabelNumber();
int getNextLabelNumber(int referenceFrame);
+ uint16 getSpriteIDFromPos(Common::Point pos);
+ bool checkSpriteIntersection(uint16 spriteId, Common::Point pos);
+ Common::Rect *getSpriteRect(uint16 spriteId);
+
void addZoomBox(ZoomBox *box);
void renderZoomBox(bool redraw = false);
bool haveZoomBox() { return !_zoomBoxes.empty(); }
@@ -109,9 +113,25 @@ public:
int32 getStageColor() { return _stageColor; }
Cast *getCastMember(int castId);
+ void renderFrame(uint16 frameId, bool forceUpdate = false, bool updateStageOnly = false);
+ void renderSprite(uint16 id);
+ void unrenderSprite(uint16 spriteId);
private:
void update();
+ void renderText(uint16 spriteId, Common::Rect *textSize);
+ void renderShape(uint16 spriteId);
+ void renderButton(uint16 spriteId);
+ void renderBitmap(uint16 spriteId);
+
+ void inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::Surface &spriteSurface, InkType ink, Common::Rect drawRect, uint spriteId);
+ void drawBackgndTransSprite(const Graphics::Surface &sprite, Common::Rect &drawRect, int spriteId);
+ void drawMatteSprite(const Graphics::Surface &sprite, Common::Rect &drawRect);
+ void drawGhostSprite(const Graphics::Surface &sprite, Common::Rect &drawRect);
+ void drawReverseSprite(const Graphics::Surface &sprite, Common::Rect &drawRect, uint16 spriteId);
+
+ void playSoundChannel(uint16 frameId);
+
void readVersion(uint32 rid);
void loadPalette(Common::SeekableSubReadStreamEndian &stream);
void loadFrames(Common::SeekableSubReadStreamEndian &stream);
@@ -128,6 +148,7 @@ private:
public:
Common::Array<Frame *> _frames;
+ Common::Array<Sprite *> _sprites;
Common::HashMap<uint16, CastInfo *> _castsInfo;
Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _castsNames;
Common::SortedArray<Label *> *_labels;
@@ -136,7 +157,7 @@ public:
Common::HashMap<uint16, Common::String> _fontMap;
Common::Array<uint16> _castScriptIds;
Graphics::ManagedSurface *_surface;
- Graphics::ManagedSurface *_trailSurface;
+ Graphics::ManagedSurface *_maskSurface;
Graphics::ManagedSurface *_backSurface;
Graphics::ManagedSurface *_backSurface2;
Graphics::Font *_font;
Commit: 1149e0edd3867e8fb714899a2a542a7e4fb620b0
https://github.com/scummvm/scummvm/commit/1149e0edd3867e8fb714899a2a542a7e4fb620b0
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-05-17T23:21:33+02:00
Commit Message:
DIRECTOR: Disable ink inversion hack
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 70258152df..34b81dda8d 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -2208,8 +2208,8 @@ void Score::renderText(uint16 spriteId, Common::Rect *textRect) {
InkType ink = sprite->_ink;
- if (spriteId == score->_currentMouseDownSpriteId)
- ink = kInkTypeReverse;
+ // if (spriteId == score->_currentMouseDownSpriteId)
+ // ink = kInkTypeReverse;
inkBasedBlit(nullptr, textCast->_widget->getSurface()->rawSurface(), ink, Common::Rect(x, y, x + width, y + height), spriteId);
@@ -2341,8 +2341,8 @@ void Score::renderText(uint16 spriteId, Common::Rect *textRect) {
InkType ink = sprite->_ink;
- if (spriteId == score->_currentMouseDownSpriteId)
- ink = kInkTypeReverse;
+ // if (spriteId == score->_currentMouseDownSpriteId)
+ // ink = kInkTypeReverse;
inkBasedBlit(nullptr, textWithFeatures, ink, Common::Rect(x, y, x + width, y + height), spriteId);
}
@@ -2351,9 +2351,9 @@ void Score::renderBitmap(uint16 spriteId) {
InkType ink;
Sprite *sprite = _sprites[spriteId];
- if (spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId)
- ink = kInkTypeReverse;
- else
+ // if (spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId)
+ // ink = kInkTypeReverse;
+ // else
ink = sprite->_ink;
BitmapCast *bc = (BitmapCast *)sprite->_cast;
More information about the Scummvm-git-logs
mailing list