[Scummvm-git-logs] scummvm master -> c7714d3882343ef4322a93b8e5c7b8a05fd126d2

npjg nathanael.gentrydb8 at gmail.com
Wed Jun 17 13:09:08 UTC 2020


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
75210d8186 DIRECTOR: Render sprites from channel structs
c7714d3882 DIRECTOR: Work around flashing reverse sprites


Commit: 75210d8186063dd11e90001de8fc1047ee3cc8e9
    https://github.com/scummvm/scummvm/commit/75210d8186063dd11e90001de8fc1047ee3cc8e9
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-17T09:07:35-04:00

Commit Message:
DIRECTOR: Render sprites from channel structs

Among other rendering issues, this fixes the annoying jittery sprites issue when
a sprite is simultaneously animated and moveable.

Changed paths:
    engines/director/events.cpp
    engines/director/frame.cpp
    engines/director/ink.cpp
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/score-loading.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 128c86e66c..5f4db0bf61 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -82,11 +82,11 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 				sc->_lastRollTime =	 sc->_lastEventTime;
 
 				if (_draggingSprite) {
-					Sprite *draggedSprite = sc->_sprites[_draggingSpriteId];
+					Sprite *draggedSprite = sc->getSpriteById(_draggingSpriteId);
 					if (draggedSprite->_moveable) {
 						pos = g_system->getEventManager()->getMousePos();
-						Common::Point delta = pos - _draggingSpritePos;
-						draggedSprite->translate(delta);
+
+						sc->_channels[_draggingSpriteId]->addDelta(pos - _draggingSpritePos);
 						_draggingSpritePos = pos;
 					} else {
 						releaseDraggedSprite();
@@ -101,7 +101,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 				// But we still want to know if the mouse is down for press effects.
 				spriteId = sc->getSpriteIDFromPos(pos);
 				sc->_currentMouseDownSpriteId = spriteId;
-				if (sc->_sprites[spriteId]->_scriptId)
+				if (sc->getSpriteById(spriteId)->_scriptId)
 					sc->_currentClickOnSpriteId = spriteId;
 
 				sc->_lastEventTime = g_director->getMacTicks();
@@ -110,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 (sc->_sprites[spriteId]->_moveable)
+				if (sc->getSpriteById(spriteId)->_moveable)
 					g_director->setDraggedSprite(spriteId);
 
 				break;
@@ -120,7 +120,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 
 				spriteId = sc->getSpriteIDFromPos(pos);
 
-				if (!sc->_sprites[sc->_currentMouseDownSpriteId]->_currentBbox.contains(pos))
+				if (!sc->getChannelById(sc->_currentMouseDownSpriteId)->getBbox().contains(pos))
 					sc->_currentMouseDownSpriteId = 0;
 
 				if (!(g_director->_wm->_mode & Graphics::kWMModeButtonDialogStyle))
@@ -131,7 +131,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 				releaseDraggedSprite();
 
 				{
-					Cast *cast = g_director->getCastMember(sc->_sprites[spriteId]->_castId);
+					Cast *cast = g_director->getCastMember(sc->getSpriteById(spriteId)->_castId);
 					if (cast && cast->_type == kCastButton)
 						cast->_hilite = !cast->_hilite;
 				}
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index fd66254553..e33cf98602 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -288,8 +288,6 @@ void Frame::readChannels(Common::ReadStreamEndian *stream) {
 			sprite._startPoint.y = (int16)stream->readUint16();
 			sprite._startPoint.x = (int16)stream->readUint16();
 
-			sprite._currentPoint = sprite._startPoint;
-
 			sprite._height = (int16)stream->readUint16();
 			sprite._width = (int16)stream->readUint16();
 
diff --git a/engines/director/ink.cpp b/engines/director/ink.cpp
index 381944ec38..d7313b2c52 100644
--- a/engines/director/ink.cpp
+++ b/engines/director/ink.cpp
@@ -65,9 +65,9 @@ void Score::inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::
 }
 
 void Score::drawBackgndTransSprite(const Graphics::Surface &sprite, Common::Rect &drawRect, int spriteId) {
-	byte skipColor = _sprites[spriteId]->_backColor;
-	if (_sprites[spriteId]->_castType == kCastText && _sprites[spriteId]->_cast) {
-		skipColor = ((TextCast *)_sprites[spriteId]->_cast)->getBackColor();
+	byte skipColor = _channels[spriteId]->_sprite->_backColor;
+	if (_channels[spriteId]->_sprite->_castType == kCastText && _channels[spriteId]->_sprite->_cast) {
+		skipColor = ((TextCast *)_channels[spriteId]->_sprite->_cast)->getBackColor();
 	}
 
 	Common::Rect srcRect(sprite.w, sprite.h);
@@ -123,7 +123,7 @@ void Score::drawReverseSprite(const Graphics::Surface &sprite, Common::Rect &dra
 		byte srcColor = *src;
 
 		for (int j = 0; j < drawRect.width(); j++) {
-			if (!_sprites[spriteId]->_cast || _sprites[spriteId]->_cast->_type == kCastShape)
+			if (!_channels[spriteId]->_sprite->_cast || _channels[spriteId]->_sprite->_cast->_type == kCastShape)
 				srcColor = 0x0;
 			else
 				srcColor = *src;
@@ -132,7 +132,7 @@ void Score::drawReverseSprite(const Graphics::Surface &sprite, Common::Rect &dra
 				// TODO: This entire reverse colour attempt needs a lot more testing on
 				// a lot more colour depths.
 				if (srcColor != skipColor) {
-					if (!_sprites[targetSprite]->_cast || _sprites[targetSprite]->_cast->_type != kCastBitmap) {
+					if (!_channels[targetSprite]->_sprite->_cast || _channels[targetSprite]->_sprite->_cast->_type != kCastBitmap) {
 						if (*dst == 0 || *dst == 255) {
 							*dst = _vm->transformColor(*dst);
 						} else if (srcColor == 255 || srcColor == 0) {
@@ -142,7 +142,7 @@ void Score::drawReverseSprite(const Graphics::Surface &sprite, Common::Rect &dra
 						}
 					} else {
 						if (*dst == 0 && _vm->getVersion() == 3 &&
-							((BitmapCast*)_sprites[spriteId]->_cast)->_bitsPerPixel > 1) {
+							((BitmapCast*)_channels[spriteId]->_sprite->_cast)->_bitsPerPixel > 1) {
 							*dst = _vm->transformColor(*src - 40);
 						} else {
 							*dst ^= _vm->transformColor(srcColor);
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 9ade91d604..dfef2c5cdb 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1483,8 +1483,8 @@ void LB::b_editableText(int nargs) {
 	if (nargs == 2) {
 		Datum state = g_lingo->pop();
 		Datum sprite = g_lingo->pop();
-		if ((uint)sprite.asInt() < sc->_sprites.size()) {
-			sc->_sprites[sprite.asInt()]->_editable = state.asInt();
+		if ((uint)sprite.asInt() < sc->_channels.size()) {
+			sc->getSpriteById(sprite.asInt())->_editable = state.asInt();
 		} else {
 			warning("b_editableText: sprite index out of bounds");
 		}
@@ -1495,7 +1495,7 @@ void LB::b_editableText(int nargs) {
 			warning("b_editableText: channel Id is missing");
 			return;
 		}
-		sc->_sprites[g_lingo->_currentChannelId]->_editable = true;
+		sc->getSpriteById(g_lingo->_currentChannelId)->_editable = true;
 	} else {
 		warning("b_editableText: unexpectedly received %d arguments", nargs);
 		g_lingo->dropStack(nargs);
@@ -1724,8 +1724,8 @@ void LB::b_puppetSprite(int nargs) {
 	if (nargs == 2) {
 		Datum state = g_lingo->pop();
 		Datum sprite = g_lingo->pop();
-		if ((uint)sprite.asInt() < sc->_sprites.size()) {
-			sc->_sprites[sprite.asInt()]->_puppet = state.asInt();
+		if ((uint)sprite.asInt() < sc->_channels.size()) {
+			sc->getSpriteById(sprite.asInt())->_puppet = state.asInt();
 		} else {
 			warning("b_puppetSprite: sprite index out of bounds");
 		}
@@ -1736,7 +1736,7 @@ void LB::b_puppetSprite(int nargs) {
 			warning("b_puppetSprite: channel Id is missing");
 			return;
 		}
-		sc->_sprites[g_lingo->_currentChannelId]->_puppet = true;
+		sc->getSpriteById(g_lingo->_currentChannelId)->_puppet = true;
 	} else {
 		warning("b_puppetSprite: unexpectedly received %d arguments", nargs);
 		g_lingo->dropStack(nargs);
@@ -1773,7 +1773,7 @@ void LB::b_rollOver(int nargs) {
 		return;
 	}
 
-	if (arg >= (int32) score->_sprites.size()) {
+	if (arg >= (int32) score->_channels.size()) {
 		g_lingo->push(res);
 		return;
 	}
@@ -1827,33 +1827,32 @@ void LB::b_zoomBox(int nargs) {
 	Score *score = g_director->getCurrentScore();
 	uint16 curFrame = score->getCurrentFrame();
 
-	Common::Rect *startRect = score->getSpriteRect(startSprite);
-	if (!startRect) {
+	Common::Rect startRect = score->_channels[startSprite]->getBbox();
+	if (startRect.isEmpty()) {
 		warning("b_zoomBox: unknown start sprite #%d", startSprite);
 		return;
 	}
 
 	// Looks for endSprite in the current frame, otherwise
 	// Looks for endSprite in the next frame
-	Common::Rect *endRect = score->getSpriteRect(endSprite);
-	if (!endRect) {
+	Common::Rect endRect = score->_channels[endSprite]->getBbox();
+	if (endRect.isEmpty()) {
 		if ((uint)curFrame + 1 < score->_frames.size())
-			endRect = &score->_frames[curFrame + 1]->_sprites[endSprite]->_currentBbox;
+			endRect = score->_frames[curFrame + 1]->_sprites[endSprite]->getDims();
 	}
-	if (!endRect) {
+	if (endRect.isEmpty()) {
 		if ((uint)curFrame - 1 > 0)
-			endRect = &score->_frames[curFrame - 1]->_sprites[endSprite]->_currentBbox;
+			endRect = score->_frames[curFrame - 1]->_sprites[endSprite]->getDims();
 	}
 
-	if (!endRect) {
+	if (endRect.isEmpty()) {
 		warning("b_zoomBox: unknown end sprite #%d", endSprite);
 		return;
 	}
 
 	Graphics::ZoomBox *box = new Graphics::ZoomBox;
-	box->start = *startRect;
-	box->end = *endRect;
-	// box->last = Common::Rect(0, 0);
+	box->start = startRect;
+	box->end = endRect;
 	box->delay = delayTicks;
 	box->step = 0;
 	box->startTime = g_system->getMillis();
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 278b4478f9..ac2449c7d3 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -790,8 +790,8 @@ void LC::c_intersects() {
 	Datum d1 = g_lingo->pop();
 
 	Score *score = g_director->getCurrentScore();
-	Sprite *sprite1 = score->getSpriteById(d1.asInt());
-	Sprite *sprite2 = score->getSpriteById(d2.asInt());
+	Channel *sprite1 = score->getChannelById(d1.asInt());
+	Channel *sprite2 = score->getChannelById(d2.asInt());
 
 	if (!sprite1 || !sprite2) {
 		g_lingo->push(Datum(0));
@@ -806,8 +806,8 @@ void LC::c_within() {
 	Datum d1 = g_lingo->pop();
 
 	Score *score = g_director->getCurrentScore();
-	Sprite *sprite1 = score->getSpriteById(d1.asInt());
-	Sprite *sprite2 = score->getSpriteById(d2.asInt());
+	Channel *sprite1 = score->getChannelById(d1.asInt());
+	Channel *sprite2 = score->getChannelById(d2.asInt());
 
 	if (!sprite1 || !sprite2) {
 		g_lingo->push(Datum(0));
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 96892ec659..29f3544eaa 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -469,7 +469,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 			Score *sc = _vm->getCurrentScore();
 			uint16 spriteId = sc->getSpriteIDFromPos(pos);
 			d.type = INT;
-			d.u.i = sc->_sprites[spriteId]->_castId;
+			d.u.i = sc->getSpriteById(spriteId)->_castId;
 			if (d.u.i == 0)
 				d.u.i = -1;
 		}
@@ -688,8 +688,8 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		return d;
 	}
 
-	Sprite *sprite = score->getSpriteById(id);
-	SpriteChannel *channel = score->getSpriteChannelById(id);
+	Channel *channel = score->getChannelById(id);
+	Sprite *sprite = channel->_sprite;
 
 	if (!sprite)
 		return d;
@@ -704,7 +704,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_blend;
 		break;
 	case kTheBottom:
-		d.u.i = sprite->_currentBbox.bottom;
+		d.u.i = sprite->getDims().bottom + channel->_currentPoint.y;
 		break;
 	case kTheCastNum:
 		d.u.i = sprite->_castId;
@@ -728,16 +728,16 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_ink;
 		break;
 	case kTheLeft:
-		d.u.i = sprite->_currentBbox.left;
+		d.u.i = sprite->getDims().left + channel->_currentPoint.x;
 		break;
 	case kTheLineSize:
 		d.u.i = sprite->_thickness & 0x3;
 		break;
 	case kTheLocH:
-		d.u.i = sprite->_currentPoint.x;
+		d.u.i = channel->_currentPoint.x;
 		break;
 	case kTheLocV:
-		d.u.i = sprite->_currentPoint.y;
+		d.u.i = channel->_currentPoint.y;
 		break;
 	case kTheMoveableSprite:
 		d.u.i = sprite->_moveable;
@@ -755,7 +755,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_puppet;
 		break;
 	case kTheRight:
-		d.u.i = sprite->_currentBbox.right;
+		d.u.i = sprite->getDims().right + channel->_currentPoint.x;
 		break;
 	case kTheStartTime:
 		d.u.i = sprite->_startTime;
@@ -767,7 +767,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_stretch;
 		break;
 	case kTheTop:
-		d.u.i = sprite->_currentBbox.top;
+		d.u.i = sprite->getDims().top + channel->_currentPoint.y;
 		break;
 	case kTheTrails:
 		d.u.i = sprite->_trails;
@@ -809,8 +809,8 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		return;
 	}
 
-	Sprite *sprite = score->getSpriteById(id);
-	SpriteChannel *channel = score->getSpriteChannelById(id);
+	Channel *channel = score->getChannelById(id);
+	Sprite *sprite = channel->_sprite;
 
 	if (!sprite)
 		return;
@@ -849,16 +849,15 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		sprite->_thickness = d.asInt();
 		break;
 	case kTheLocH:
-		sprite->_currentPoint.x = d.asInt();
+		channel->addDelta(Common::Point(d.asInt() - channel->_currentPoint.x, 0));
 		break;
 	case kTheLocV:
-		sprite->_currentPoint.y = d.asInt();
+		channel->addDelta(Common::Point(0, d.asInt() - channel->_currentPoint.y));
 		break;
 	case kTheMoveableSprite:
 		sprite->_moveable = d.asInt();
-		if (!d.u.i) {
-			sprite->_currentPoint = sprite->_startPoint;
-		}
+		if (!d.u.i)
+			channel->resetPosition();
 		break;
 	case kTheMovieRate:
 		sprite->_movieRate = d.asInt();
@@ -872,7 +871,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 	case kThePuppet:
 		sprite->_puppet = d.asInt();
 		if (!d.asInt()) {
-			sprite->_currentPoint = sprite->_startPoint;
+			channel->resetPosition();
 
 			// TODO: Properly reset sprite properties after puppet disabled.
 			sprite->_moveable = false;
diff --git a/engines/director/score-loading.cpp b/engines/director/score-loading.cpp
index c367067a63..4151984369 100644
--- a/engines/director/score-loading.cpp
+++ b/engines/director/score-loading.cpp
@@ -259,10 +259,9 @@ bool Score::loadArchive(bool isSharedCast) {
 	}
 	copyCastStxts();
 
-	setSpriteCasts();
 	loadSpriteImages(isSharedCast);
 	loadSpriteSounds(isSharedCast);
-	setSpriteBboxes();
+	setSpriteCasts();
 
 	return true;
 }
@@ -514,10 +513,6 @@ void Score::loadFrames(Common::SeekableSubReadStreamEndian &stream) {
 		warning("STUB: Score::loadFrames. unk1: %x unk2: %x unk3: %x unk4: %x unk5: %x unk6: %x", unk1, unk2, unk3, unk4, unk5, unk6);
 	}
 
-	for (int i = 0; i < _numChannelsDisplayed + 1; i++) {
-		_spriteChannels.push_back(new SpriteChannel());
-	}
-
 	uint16 channelSize;
 	uint16 channelOffset;
 
@@ -691,20 +686,8 @@ void Score::setSpriteCasts() {
 	for (uint16 i = 0; i < _frames.size(); i++) {
 		for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
 			_frames[i]->_sprites[j]->setCast(_frames[i]->_sprites[j]->_castId);
-			debugC(1, kDebugImages, "Score::setSpriteCasts(): Frame: %d Channel: %d castId: %d type: %d", i, j, _frames[i]->_sprites[j]->_castId, _frames[i]->_sprites[j]->_spriteType);
-		}
-	}
-}
-
-void Score::setSpriteBboxes() {
-	// Initialise the sprite cache for all the initial bounding boxes
-	for (uint16 i = 0; i < _frames.size(); i++) {
-		for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
-			Sprite *sp = _frames[i]->_sprites[j];
-			sp->updateCast();
 
-			sp->_startBbox = sp->getBbox();
-			sp->_currentBbox = sp->_startBbox;
+			debugC(1, kDebugImages, "Score::setSpriteCasts(): Frame: %d Channel: %d castId: %d type: %d", i, j, _frames[i]->_sprites[j]->_castId, _frames[i]->_sprites[j]->_spriteType);
 		}
 	}
 }
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index d69a88c346..7100db4795 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -38,6 +38,43 @@
 
 namespace Director {
 
+Channel::Channel(Sprite *sp) {
+	_sprite = sp;
+	_currentPoint = sp->_startPoint;
+	_delta = Common::Point(0, 0);
+
+	_visible = true;
+
+	if (_sprite && _sprite->_castType != kCastTypeNull) {
+		_sprite->updateCast();
+		updateLocation();
+	}
+}
+
+Common::Rect Channel::getBbox() {
+	Common::Rect bbox = _sprite->getDims();
+	bbox.moveTo(_currentPoint);
+
+	return bbox;
+}
+
+void Channel::updateLocation() {
+	_currentPoint += _delta;
+	_delta = Common::Point(0, 0);
+
+	_sprite->translate(_currentPoint, true);
+}
+
+void Channel::addDelta(Common::Point pos) {
+	// This method is for easily implementing constraint of sprite
+
+	_delta += pos;
+}
+
+void Channel::resetPosition() {
+	_delta = _sprite->_startPoint;
+}
+
 Score::Score(DirectorEngine *vm) {
 	_vm = vm;
 	_surface = nullptr;
@@ -109,8 +146,8 @@ Score::~Score() {
 	for (uint i = 0; i < _frames.size(); i++)
 		delete _frames[i];
 
-	for (uint i = 0; i < _spriteChannels.size(); i++)
-		delete _spriteChannels[i];
+	for (uint i = 0; i < _channels.size(); i++)
+		delete _channels[i];
 
 	if (_loadedStxts)
 		for (Common::HashMap<int, const Stxt *>::iterator it = _loadedStxts->begin(); it != _loadedStxts->end(); ++it)
@@ -328,16 +365,18 @@ void Score::startLoop() {
 	_stopPlay = false;
 	_nextFrameTime = 0;
 
-	_sprites = _frames[_currentFrame]->_sprites;
-	_lingo->processEvent(kEventStartMovie);
-
-	renderFrame(_currentFrame, true);
-
 	if (_frames.size() <= 1) {	// We added one empty sprite
 		warning("Score::startLoop(): Movie has no frames");
 		_stopPlay = true;
 	}
 
+	// All frames in the same movie have the same number of channels
+	for (int i = _frames[1]->_sprites.size() - 1; i >= 0; i--) {
+		_channels.push_back(new Channel(_frames[1]->_sprites[i]));
+	}
+
+	_lingo->processEvent(kEventStartMovie);
+
 	while (!_stopPlay) {
 		if (_currentFrame >= _frames.size()) {
 			if (debugChannelSet(-1, kDebugNoLoop))
@@ -488,8 +527,9 @@ void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly)
 
 	Frame *currentFrame = _frames[frameId];
 
-	for (uint16 i = 0; i < _sprites.size(); i++) {
-		Sprite *currentSprite = _sprites[i];
+	for (uint16 i = 0; i < _channels.size(); i++) {
+		Channel *channel = _channels[i];
+		Sprite *currentSprite = channel->_sprite;
 		Sprite *nextSprite;
 
 		if (currentSprite->_puppet)
@@ -502,38 +542,53 @@ void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly)
 		// - The cast member ID of the sprite has changed (_dirty flag set)
 		// - The sprite slot from the current frame is different (cast member ID or bounding box) from the cached sprite slot
 		// (maybe we have to compare all the sprite attributes, not just these two?)
-		bool needsUpdate = currentSprite->isDirty() || currentSprite->_castId != nextSprite->_castId || currentSprite->_currentBbox != nextSprite->_currentBbox;
+		bool needsUpdate = currentSprite->isDirty() ||
+			currentSprite->_castId != nextSprite->_castId ||
+			channel->_delta != Common::Point(0, 0) ||
+			currentSprite->_startPoint != nextSprite->_startPoint ||
+			currentSprite->getDims() != nextSprite->getDims() ||
+			(channel->_currentPoint != nextSprite->_startPoint &&
+			 currentSprite != nextSprite);
+
 
 		if (needsUpdate || forceUpdate) {
 			if (!currentSprite->_trails) {
-				_maskSurface->fillRect(currentSprite->_currentBbox, 1);
-				_surface->fillRect(currentSprite->_currentBbox, _stageColor);
+				Common::Rect currentBbox = channel->getBbox();
+				_maskSurface->fillRect(currentBbox, 1);
+				_surface->fillRect(currentBbox, _stageColor);
 			}
-
-			currentSprite->_currentBbox = currentSprite->getBbox();
 		}
 
-		_maskSurface->fillRect(nextSprite->_currentBbox, 1);
-		_sprites[i] = nextSprite;
+		channel->_sprite = nextSprite;
+		channel->updateLocation();
 	}
 
-	for (uint id = 0; id < _sprites.size(); id++) {
-		Sprite *sprite = _sprites[id];
+	for (uint id = 0; id < _channels.size(); id++) {
+		Channel *channel = _channels[id];
+		Sprite *sprite = channel->_sprite;
 
 		if (!sprite || !sprite->_enabled || !sprite->_castType)
 			continue;
 
 		sprite->updateCast();
 
+		// Sprites marked moveable are constrained to the same bounding box until
+		// the moveable is disabled
+		if (!sprite->_moveable)
+			channel->_currentPoint = sprite->_startPoint;
+
+		Common::Rect currentBbox = channel->getBbox();
+		_maskSurface->fillRect(currentBbox, 1);
+
 		debugC(1, kDebugImages, "Score::renderSprite(): channel: %d,  castType: %d,  castId: %d", id, sprite->_castType, sprite->_castId);
 		if (sprite->_castType == kCastShape) {
 			renderShape(id);
 		} else {
-			Cast *cast = _sprites[id]->_cast;
+			Cast *cast = sprite->_cast;
 			if (cast && cast->_widget) {
 				cast->_widget->_priority = id;
 				cast->_widget->draw();
-				inkBasedBlit(cast->_widget->getMask(), cast->_widget->getSurface()->rawSurface(), _sprites[id]->_ink, _sprites[id]->_currentBbox, id);
+				inkBasedBlit(cast->_widget->getMask(), cast->_widget->getSurface()->rawSurface(), channel->_sprite->_ink, currentBbox, id);
 			} else {
 				warning("Score::renderSprite: No widget for channel ID %d", id);
 			}
@@ -562,7 +617,7 @@ void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly)
 }
 
 void Score::renderShape(uint16 spriteId) {
-	Sprite *sp = _sprites[spriteId];
+	Sprite *sp = _channels[spriteId]->_sprite;
 
 	InkType ink = sp->_ink;
 	byte spriteType = sp->_spriteType;
@@ -617,7 +672,7 @@ void Score::renderShape(uint16 spriteId) {
 	// for outlined shapes, line thickness of 1 means invisible.
 	lineSize -= 1;
 
-	Common::Rect shapeRect = sp->_currentBbox;
+	Common::Rect shapeRect = _channels[spriteId]->getBbox();
 
 	Graphics::ManagedSurface tmpSurface, maskSurface;
 	tmpSurface.create(shapeRect.width(), shapeRect.height(), Graphics::PixelFormat::createFormatCLUT8());
@@ -698,46 +753,37 @@ const Stxt *Score::getStxt(int castId) {
 }
 
 uint16 Score::getSpriteIDFromPos(Common::Point pos) {
-	for (int i = _sprites.size() - 1; i >= 0; i--)
-		if (_sprites[i]->_currentBbox.contains(pos))
+	for (int i = _channels.size() - 1; i >= 0; i--)
+		if (_channels[i]->getBbox().contains(pos))
 			return i;
 
 	return 0;
 }
 
 bool Score::checkSpriteIntersection(uint16 spriteId, Common::Point pos) {
-	if (_sprites[spriteId]->_currentBbox.contains(pos))
+	if (_channels[spriteId]->getBbox().contains(pos))
 		return true;
 
 	return false;
 }
 
-Common::Rect *Score::getSpriteRect(uint16 spriteId) {
-	if (!_sprites[spriteId]->_currentBbox.isEmpty())
-		return &_sprites[spriteId]->_currentBbox;
-
-	return nullptr;
-}
-
 Sprite *Score::getSpriteById(uint16 id) {
-	if (id >= _sprites.size()) {
-		warning("Score::getSpriteById(%d): out of bounds. frame: %d", id, _currentFrame);
-		return nullptr;
-	}
-	if (_sprites[id]) {
-		return _sprites[id];
+	Channel *channel = getChannelById(id);
+
+	if (channel) {
+		return channel->_sprite;
 	} else {
-		warning("Sprite on frame %d width id %d not found", _currentFrame, id);
+		warning("Score::getSpriteById: sprite on frame %d with id %d not found", _currentFrame, id);
 		return nullptr;
 	}
 }
 
-SpriteChannel *Score::getSpriteChannelById(uint16 id) {
-	if (id >= _spriteChannels.size()) {
+Channel *Score::getChannelById(uint16 id) {
+	if (id >= _channels.size()) {
 		warning("Score::getSpriteChannelById(%d): out of bounds", id);
 		return nullptr;
 	}
-	return _spriteChannels[id];
+	return _channels[id];
 }
 
 void Score::playSoundChannel(uint16 frameId) {
diff --git a/engines/director/score.h b/engines/director/score.h
index 1eb98aafaf..08fb1a5a68 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -48,8 +48,8 @@ class Frame;
 struct Label;
 class Lingo;
 struct Resource;
+class Channel;
 class Sprite;
-class SpriteChannel;
 class Stxt;
 class BitmapCast;
 class ScriptCast;
@@ -86,6 +86,20 @@ struct TransParams {
 	}
 };
 
+struct Channel {
+	Sprite *_sprite;
+
+	bool _visible;
+	Common::Point _currentPoint;
+	Common::Point _delta;
+
+	Channel(Sprite *sp);
+	Common::Rect getBbox();
+	void updateLocation();
+	void addDelta(Common::Point pos);
+	void resetPosition();
+};
+
 class Score {
 public:
 	Score(DirectorEngine *vm);
@@ -110,10 +124,9 @@ public:
 	void setCurrentFrame(uint16 frameId) { _nextFrame = frameId; }
 	uint16 getCurrentFrame() { return _currentFrame; }
 	Common::String getMacName() const { return _macName; }
+	Channel *getChannelById(uint16 id);
 	Sprite *getSpriteById(uint16 id);
-	SpriteChannel *getSpriteChannelById(uint16 id);
 	void setSpriteCasts();
-	void setSpriteBboxes();
 	void loadSpriteImages(bool isSharedCast);
 	void loadSpriteSounds(bool isSharedCast);
 	void copyCastStxts();
@@ -128,7 +141,6 @@ public:
 
 	uint16 getSpriteIDFromPos(Common::Point pos);
 	bool checkSpriteIntersection(uint16 spriteId, Common::Point pos);
-	Common::Rect *getSpriteRect(uint16 spriteId);
 
 	Cast *getCastMember(int castId);
 	const Stxt *getStxt(int castId);
@@ -171,9 +183,8 @@ private:
 	bool processImmediateFrameScript(Common::String s, int id);
 
 public:
+	Common::Array<Channel *> _channels;
 	Common::Array<Frame *> _frames;
-	Common::Array<Sprite *> _sprites;
-	Common::Array<SpriteChannel *> _spriteChannels;
 	Common::HashMap<uint16, CastInfo *> _castsInfo;
 	Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _castsNames;
 	Common::SortedArray<Label *> *_labels;
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 0d59887ae2..dcdcb6a951 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -30,13 +30,6 @@
 
 namespace Director {
 
-SpriteChannel::SpriteChannel() {
-	_visible = true;
-}
-
-SpriteChannel::~SpriteChannel() {
-}
-
 Sprite::Sprite() {
 	_scriptId = 0;
 	_scriptCastIndex = 0;
@@ -95,35 +88,23 @@ void Sprite::updateCast() {
 		_cast->createWidget();
 	}
 
-	int offsetx = 0, offsety = 0;
-	if (_cast->_type == kCastBitmap) {
-		BitmapCast *bc = (BitmapCast *)_cast;
-		offsety = bc->_initialRect.top - bc->_regY;
-		offsetx = bc->_initialRect.left - bc->_regX;
-	}
-
-	if (_cast && _cast->_widget)
-		_cast->_widget->_dims.moveTo(_currentPoint.x + offsetx, _currentPoint.y + offsety);
-
 	if (_cast->isEditable() != _editable && !_puppet)
 		_cast->setEditable(_editable);
 }
 
 void Sprite::translate(Common::Point delta, bool moveTo) {
-	_currentPoint += delta;
-
 	if (_cast && _cast->_widget) {
 		if (moveTo)
-			_cast->_widget->_dims.translate(delta.x, delta.y);
-		else
 			_cast->_widget->_dims.moveTo(delta.x, delta.y);
+		else
+			_cast->_widget->_dims.translate(delta.x, delta.y);
 	}
 
 	_dirty = true;
 }
 
 bool Sprite::isDirty() {
-	return _dirty || (_cast && _cast->isModified());
+	return _castType != kCastTypeNull && (_dirty || (_cast && _cast->isModified()));
 }
 
 void Sprite::setClean() {
@@ -246,11 +227,16 @@ void Sprite::setCast(uint16 castId) {
 		}
 	}
 
+	if (_castType == kCastBitmap && _cast) {
+		BitmapCast *bc = (BitmapCast *)_cast;
+
+		_startPoint += Common::Point(bc->_initialRect.left - bc->_regX, bc->_initialRect.top - bc->_regY);
+	}
 
 	_dirty = true;
 }
 
-Common::Rect Sprite::getBbox() {
+Common::Rect Sprite::getDims() {
 	Common::Rect result;
 	if (_castId == 0) {
 		return result;
@@ -258,18 +244,18 @@ Common::Rect Sprite::getBbox() {
 
 	if (_castType == kCastShape) {
 		// WORKAROUND: Shape widgets not fully implemented.
-		result = Common::Rect(_currentPoint.x, _currentPoint.y, _currentPoint.x + _width, _currentPoint.y + _height);
+		result = Common::Rect(_width, _height);
 	} else {
-		result = _cast && _cast->_widget ? _cast->_widget->getDimensions() : Common::Rect(0, 0, _width, _height);
-	}
-
-	result.moveTo(_currentPoint.x, _currentPoint.y);
-
-	if (_cast && _castType == kCastBitmap) {
-		BitmapCast *bc = (BitmapCast *)_cast;
-		int offsety = bc->_initialRect.top - bc->_regY;
-		int offsetx = bc->_initialRect.left - bc->_regX;
-		result.translate(offsetx, offsety);
+		if (_cast && _cast->_widget) {
+			result = Common::Rect(_cast->_widget->_dims.width(), _cast->_widget->_dims.height());
+
+			if (_castType == kCastBitmap) {
+				BitmapCast *bc = (BitmapCast *)_cast;
+				int offsety = bc->_initialRect.top - bc->_regY;
+				int offsetx = bc->_initialRect.left - bc->_regX;
+				result.translate(offsetx, offsety);
+			}
+		}
 	}
 
 	if (_puppet && _stretch) {
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 204a12ca25..f7f601941d 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -56,14 +56,6 @@ enum MainChannelsPosition {
 	kPalettePosition = 15
 };
 
-class SpriteChannel {
-public:
-	SpriteChannel();
-	~SpriteChannel();
-
-	bool _visible;
-};
-
 class Sprite {
 public:
 	Sprite();
@@ -78,7 +70,7 @@ public:
 
 	void setCast(uint16 castid);
 
-	Common::Rect getBbox();
+	Common::Rect getDims();
 
 	uint16 _scriptId;
 	uint16 _scriptCastIndex;
@@ -100,9 +92,6 @@ public:
 	byte _thickness;
 	bool _dirty;
 	Common::Point _startPoint;
-	Common::Point _currentPoint;
-	Common::Rect _startBbox;
-	Common::Rect _currentBbox;
 	int16 _width;
 	int16 _height;
 	// TODO: default constraint = 0, if turned on, sprite is constrainted to the bounding rect


Commit: c7714d3882343ef4322a93b8e5c7b8a05fd126d2
    https://github.com/scummvm/scummvm/commit/c7714d3882343ef4322a93b8e5c7b8a05fd126d2
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-17T09:07:35-04:00

Commit Message:
DIRECTOR: Work around flashing reverse sprites

Changed paths:
    engines/director/score.cpp


diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 7100db4795..8deac6ff55 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -550,6 +550,8 @@ void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly)
 			(channel->_currentPoint != nextSprite->_startPoint &&
 			 currentSprite != nextSprite);
 
+		// WORKAROUND, HACK: Redraw reverse ink sprites each time to prevent flickering
+		needsUpdate = needsUpdate || (currentSprite->_ink == kInkTypeReverse);
 
 		if (needsUpdate || forceUpdate) {
 			if (!currentSprite->_trails) {




More information about the Scummvm-git-logs mailing list