[Scummvm-git-logs] scummvm master -> b0f735987622de32ee3bb471a5e0895541d05927
sev-
noreply at scummvm.org
Thu Apr 9 10:55:54 UTC 2026
This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
1c250c7879 DIRECTOR: Initial code for replacing FilmLoop parsing with Score
dc59f8d49d DIRECTOR: Force sprite preload for FilmLoop castmembers
59eba8a56e DIRECTOR: Remove custom loaders for Filmloop castmembers
bdfe5780a5 DIRECTOR: Completely disable Lingo in filmloops
e720eaf755 DIRECTOR: Let Filmloop castmember Score keep its own state
828966aeb7 DIRECTOR: Streamlined filmloop sprites passing
13836af96c DIRECTOR: Filmloop: Fix filmloop scaling bug
b0f7359876 DIRECTOR: Fix crash when setting picture of unloaded bitmap cast member
Commit: 1c250c7879e8e00748758dedab56a56ecc7432b3
https://github.com/scummvm/scummvm/commit/1c250c7879e8e00748758dedab56a56ecc7432b3
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-09T12:51:27+02:00
Commit Message:
DIRECTOR: Initial code for replacing FilmLoop parsing with Score
Changed paths:
engines/director/castmember/filmloop.cpp
engines/director/castmember/filmloop.h
engines/director/score.cpp
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index d0a540b8cea..fd170f64d23 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -31,6 +31,7 @@
#include "director/channel.h"
#include "director/frame.h"
#include "director/movie.h"
+#include "director/score.h"
#include "director/sprite.h"
#include "director/window.h"
#include "director/castmember/bitmap.h"
@@ -85,7 +86,7 @@ FilmLoopCastMember::FilmLoopCastMember(Cast *cast, uint16 castId, FilmLoopCastMe
_enableSound = source._enableSound;
_crop = source._crop;
_center = source._center;
- _frames = source._frames;
+ _score = source._score;
_subchannels = source._subchannels;
_looping = source._looping;
}
@@ -95,7 +96,7 @@ FilmLoopCastMember::~FilmLoopCastMember() {
}
bool FilmLoopCastMember::isModified() {
- if (_frames.size())
+ if (_score->_scoreCache.size())
return true;
if (_initialRect.width() && _initialRect.height())
@@ -109,19 +110,17 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
_subchannels.clear();
- if (frame >= _frames.size()) {
- warning("FilmLoopCastMember::getSubChannels(): Film loop frame %d requested, only %d available", frame, _frames.size());
+ if (frame >= _score->_scoreCache.size()) {
+ warning("FilmLoopCastMember::getSubChannels(): Film loop frame %d requested, only %d available", frame, _score->_scoreCache.size());
return &_subchannels;
}
// get the list of sprite IDs for this frame
Common::Array<int> spriteIds;
- for (auto &iter : _frames[frame].sprites) {
- // channels 0 and 1 are used for audio
- if (iter._key >= 2)
- spriteIds.push_back(iter._key);
+ for (uint i = 0; i < _score->_scoreCache[frame]->_sprites.size(); ++i) {
+ if (_score->_scoreCache[frame]->_sprites[i] && !_score->_scoreCache[frame]->_sprites[i]->_castId.isNull())
+ spriteIds.push_back(i);
}
- Common::sort(spriteIds.begin(), spriteIds.end());
debugC(5, kDebugImages, "FilmLoopCastMember::getSubChannels(): castId: %d, frame: %d, count: %d, initRect: %d,%d %dx%d, bbox: %d,%d %dx%d",
_castId, frame, spriteIds.size(),
@@ -134,33 +133,33 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
// copy the sprites in order to the list
for (auto &iter : spriteIds) {
- Sprite src = _frames[frame].sprites[iter];
- if (!src._cast)
+ Sprite *src = _score->_scoreCache[frame]->_sprites[iter];
+ if (src->_castId.isNull())
continue;
// translate sprite relative to the global bounding box
- int16 relX = (src._startPoint.x - _initialRect.left) * widgetRect.width() / _initialRect.width();
- int16 relY = (src._startPoint.y - _initialRect.top) * widgetRect.height() / _initialRect.height();
+ int16 relX = (src->_startPoint.x - _initialRect.left) * widgetRect.width() / _initialRect.width();
+ int16 relY = (src->_startPoint.y - _initialRect.top) * widgetRect.height() / _initialRect.height();
int16 absX = relX + bbox.left;
int16 absY = relY + bbox.top;
- int16 width = src._width * widgetRect.width() / _initialRect.width();
- int16 height = src._height * widgetRect.height() / _initialRect.height();
+ int16 width = src->_width * widgetRect.width() / _initialRect.width();
+ int16 height = src->_height * widgetRect.height() / _initialRect.height();
debugC(5, kDebugImages, "FilmLoopCastMember::getSubChannels(): sprite: %d - cast: %s, orig: %d,%d %dx%d, trans: %d,%d %dx%d",
- iter, src._castId.asString().c_str(),
- src._startPoint.x, src._startPoint.y, src._width, src._height,
+ iter, src->_castId.asString().c_str(),
+ src->_startPoint.x, src->_startPoint.y, src->_width, src->_height,
absX, absY, width, height);
// Re-inject the translated position into the Sprite.
// This saves the hassle of having to force the Channel to be in puppet mode.
- src._width = width;
- src._height = height;
- src._startPoint = Common::Point(absX, absY);
- src._stretch = true;
+ src->_width = width;
+ src->_height = height;
+ src->_startPoint = Common::Point(absX, absY);
+ src->_stretch = true;
// Film loop frames are constructed as a series of Channels, much like how a normal frame
// is rendered by the Score. We don't include a pointer to the current Score here,
// that's only for querying the constraint channel which is not used.
- Channel chan(nullptr, &src);
+ Channel chan(nullptr, src);
_subchannels.push_back(chan);
}
// Initialise the widgets on all of the subchannels.
@@ -175,29 +174,24 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
}
CastMemberID FilmLoopCastMember::getSubChannelSound1(uint frame) {
- if (frame >= _frames.size()) {
- warning("FilmLoopCastMember::getSubChannelSound1(): Film loop frame %d requested, only %d available", frame, _frames.size());
+ if (frame >= _score->_scoreCache.size()) {
+ warning("FilmLoopCastMember::getSubChannelSound1(): Film loop frame %d requested, only %d available", frame, _score->_scoreCache.size());
return CastMemberID();
}
- if (_frames[frame].sprites.contains(0)) {
- return _frames[frame].sprites[0]._castId;
- }
- return CastMemberID();
+ return _score->_scoreCache[frame]->_mainChannels.sound1;
}
CastMemberID FilmLoopCastMember::getSubChannelSound2(uint frame) {
- if (frame >= _frames.size()) {
- warning("FilmLoopCastMember::getSubChannelSound2(): Film loop frame %d requested, only %d available", frame, _frames.size());
+ if (frame >= _score->_scoreCache.size()) {
+ warning("FilmLoopCastMember::getSubChannelSound2(): Film loop frame %d requested, only %d available", frame, _score->_scoreCache.size());
return CastMemberID();
}
- if (_frames[frame].sprites.contains(1)) {
- return _frames[frame].sprites[1]._castId;
- }
- return CastMemberID();
+ return _score->_scoreCache[frame]->_mainChannels.sound2;
}
+#if 0
void FilmLoopCastMember::loadFilmLoopDataD2(Common::SeekableReadStreamEndian &stream) {
_initialRect = Common::Rect();
_frames.clear();
@@ -667,7 +661,7 @@ void FilmLoopCastMember::loadFilmLoopDataD6(Common::SeekableReadStreamEndian &st
debugC(5, kDebugLoading, "loadFilmLoopDataD6: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
}
-
+#endif
Common::String FilmLoopCastMember::formatInfo() {
return Common::String::format(
@@ -676,7 +670,7 @@ Common::String FilmLoopCastMember::formatInfo() {
_initialRect.left, _initialRect.top,
_boundingRect.width(), _boundingRect.height(),
_boundingRect.left, _boundingRect.top,
- _frames.size(), _subchannels.size(), _enableSound, _looping,
+ _score->_scoreCache.size(), _subchannels.size(), _enableSound, _looping,
_crop, _center
);
}
@@ -685,48 +679,39 @@ void FilmLoopCastMember::load() {
if (_loaded)
return;
+ Common::SeekableReadStreamEndian *loop = nullptr;
+ uint16 filmLoopId = 0;
+ uint32 tag = 0;
+
if (_cast->_version < kFileVer400) {
// Director 3 and below should have a SCVW resource
- uint16 filmLoopId = _castId + _cast->_castIDoffset;
- uint32 tag = MKTAG('S', 'C', 'V', 'W');
- Common::SeekableReadStreamEndian *loop = _cast->getResource(tag, filmLoopId);
- if (loop) {
- debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
- loadFilmLoopDataD2(*loop);
- delete loop;
- } else {
- warning("FilmLoopCastMember::load(): Film loop not found");
- }
+ filmLoopId = _castId + _cast->_castIDoffset;
+ tag = MKTAG('S', 'C', 'V', 'W');
+ loop = _cast->getResource(tag, filmLoopId);
} else if (_cast->_version >= kFileVer400 && _cast->_version < kFileVer700) {
- Common::SeekableReadStreamEndian *loop = nullptr;
- uint16 filmLoopId = 0;
- uint32 tag = 0;
for (auto &it : _children) {
if (it.tag == MKTAG('S', 'C', 'V', 'W')) {
filmLoopId = it.index;
tag = it.tag;
loop = _cast->getResource(tag, filmLoopId);
break;
+ } else {
+ debugC(5, kDebugLoading, "FilmLoopCastMember::load(): Ignoring child with tag '%s' id: %d", tag2str(it.tag), it.index);
}
}
-
- if (loop) {
- debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
- if (_cast->_version < kFileVer500) {
- loadFilmLoopDataD4(*loop);
- } else if (_cast->_version < kFileVer600) {
- loadFilmLoopDataD5(*loop);
- } else if (_cast->_version < kFileVer700) {
- loadFilmLoopDataD6(*loop);
- }
- delete loop;
- } else {
- warning("FilmLoopCastMember::load(): No SCVW resource found in %d children", _children.size());
- }
} else {
warning("STUB: FilmLoopCastMember::load(): Film loops not yet supported for version v%d (%d)", humanVersion(_cast->_version), _cast->_version);
}
+ if (loop) {
+ debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
+ _score = new Score(g_director->getCurrentMovie());
+ _score->loadFrames(*loop, _cast->_version);
+ delete loop;
+ } else {
+ warning("FilmLoopCastMember::load(): Film loop not found");
+ }
+
_loaded = true;
}
@@ -821,11 +806,10 @@ void FilmLoopCastMember::writeSCVWResource(Common::SeekableWriteStream *writeStr
// order of message (this order tells us the channel we're reading) ->
// 1-20 bytes of Sprite data
- for (FilmLoopFrame frame : _frames) {
- writeStream->writeUint16BE(frame.sprites.size() * (channelSize + 4) + 2); // Frame Size
+ for (Frame *frame : _score->_scoreCache) {
+ writeStream->writeUint16BE(frame->_sprites.size() * (channelSize + 4) + 2); // Frame Size
- for (auto it : frame.sprites) {
- int channel = it._key;
+ for (uint channel = 0; channel < frame->_sprites.size(); ++channel) {
// TODO: For now writing the order considering that each sprite will have 20 bytes of data
// In the future, for optimization, we can actually calculate the data of each sprite
// And write the order accordingly
@@ -836,12 +820,12 @@ void FilmLoopCastMember::writeSCVWResource(Common::SeekableWriteStream *writeStr
writeStream->writeUint16BE(channelSize); // message width
writeStream->writeUint16BE(channel * channelSize);
- Sprite sprite = it._value;
+ Sprite *sprite = frame->_sprites[channel];
if (_cast->_version >= kFileVer400 && _cast->_version < kFileVer500) {
- writeSpriteDataD4(writeStream, sprite);
+ writeSpriteDataD4(writeStream, *sprite);
} else if (_cast->_version >= kFileVer500 && _cast->_version < kFileVer600) {
- writeSpriteDataD5(writeStream, sprite);
+ writeSpriteDataD5(writeStream, *sprite);
}
}
@@ -875,15 +859,14 @@ uint32 FilmLoopCastMember::getSCVWResourceSize() {
}
uint32 framesSize = 0;
- for (FilmLoopFrame frame : _frames) {
+ for (Frame *frame : _score->_scoreCache) {
// Frame size
framesSize += 2;
- for (auto it : frame.sprites) {
- // message width: 2 bytes
- // order: 2 bytes
- // Sprite data: 20 bytes
- framesSize += 2 + 2 + channelSize;
- }
+
+ // message width: 2 bytes
+ // order: 2 bytes
+ // Sprite data: 20 bytes
+ framesSize += (2 + 2 + channelSize) * frame->_sprites.size();
}
// Size: 4 bytes
diff --git a/engines/director/castmember/filmloop.h b/engines/director/castmember/filmloop.h
index 5cd04417f32..80006e5ef65 100644
--- a/engines/director/castmember/filmloop.h
+++ b/engines/director/castmember/filmloop.h
@@ -72,8 +72,9 @@ public:
bool _crop;
bool _center;
- Common::Array<FilmLoopFrame> _frames;
Common::Array<Channel> _subchannels;
+
+ Score *_score;
};
} // End of namespace Director
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 386eddc8bff..a50cd3d634f 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -908,12 +908,12 @@ void Score::incrementFilmLoops() {
for (auto &it : _channels) {
if (it->_sprite->_cast && (it->_sprite->_cast->_type == kCastFilmLoop || it->_sprite->_cast->_type == kCastMovie)) {
FilmLoopCastMember *fl = ((FilmLoopCastMember *)it->_sprite->_cast);
- if (!fl->_frames.empty()) {
+ if (!fl->_score->_scoreCache.empty()) {
// increment the film loop counter
if (fl->_looping) {
it->_filmLoopFrame += 1;
- it->_filmLoopFrame %= fl->_frames.size();
- } else if (it->_filmLoopFrame < (fl->_frames.size() - 1)) {
+ it->_filmLoopFrame %= fl->_score->_scoreCache.size();
+ } else if (it->_filmLoopFrame < (fl->_score->_scoreCache.size() - 1)) {
it->_filmLoopFrame += 1;
}
} else {
Commit: dc59f8d49dc6acc2c0db94c3e955c6d46c453f78
https://github.com/scummvm/scummvm/commit/dc59f8d49dc6acc2c0db94c3e955c6d46c453f78
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Force sprite preload for FilmLoop castmembers
Changed paths:
engines/director/castmember/filmloop.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index fd170f64d23..ca365c3bf61 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -704,9 +704,9 @@ void FilmLoopCastMember::load() {
}
if (loop) {
- debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
+ debugC(2, kDebugLoading, "****** FilmLoopCastMember::load(): Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
_score = new Score(g_director->getCurrentMovie());
- _score->loadFrames(*loop, _cast->_version);
+ _score->loadFrames(*loop, _cast->_version, true);
delete loop;
} else {
warning("FilmLoopCastMember::load(): Film loop not found");
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index a50cd3d634f..e2a31dd17ae 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1832,7 +1832,7 @@ void Score::playQueuedSound() {
sound->playFPlaySound();
}
-void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version) {
+void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version, bool loadSprites) {
debugC(1, kDebugLoading, "****** Loading frames VWSC");
// Setup our streams for frames processing
@@ -1955,7 +1955,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Calculate number of frames and their positions
// numOfFrames in the header is often incorrect
- for (_numFrames = 1; loadFrame(_numFrames, false); _numFrames++) {
+ for (_numFrames = 1; loadFrame(_numFrames, loadSprites); _numFrames++) {
_scoreCache.push_back(new Frame(*_currentFrame));
for (int i = 0; i < (int)_currentFrame->_sprites.size(); i++) {
diff --git a/engines/director/score.h b/engines/director/score.h
index bec69ff42a8..33329321bd9 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -70,7 +70,7 @@ public:
Movie *getMovie() const { return _movie; }
- void loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version);
+ void loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version, bool loadSprites = false);
bool loadFrame(int frame, bool loadCast);
bool readOneFrame();
void updateFrame(Frame *frame);
Commit: 59eba8a56e5b65f48f902a02bc63e556d67a2ef2
https://github.com/scummvm/scummvm/commit/59eba8a56e5b65f48f902a02bc63e556d67a2ef2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Remove custom loaders for Filmloop castmembers
Changed paths:
engines/director/castmember/filmloop.cpp
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index ca365c3bf61..f069ea0ce0e 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -191,478 +191,6 @@ CastMemberID FilmLoopCastMember::getSubChannelSound2(uint frame) {
return _score->_scoreCache[frame]->_mainChannels.sound2;
}
-#if 0
-void FilmLoopCastMember::loadFilmLoopDataD2(Common::SeekableReadStreamEndian &stream) {
- _initialRect = Common::Rect();
- _frames.clear();
-
- uint32 size = stream.readUint32BE();
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD2: SCVW body:");
- uint32 pos = stream.pos();
- stream.seek(0);
- stream.hexdump(size);
- stream.seek(pos);
- }
- uint16 channelSize = kSprChannelSizeD2;
- FilmLoopFrame newFrame;
-
- while (stream.pos() < size) {
- uint16 frameSize = stream.readUint16BE();
- if (frameSize == 0) {
- continue;
- }
- frameSize -= 2;
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD2: Frame entry:");
- stream.hexdump(frameSize);
- }
-
- while (frameSize > 0) {
- int msgWidth = stream.readByte() * 2;
- int order = stream.readByte() * 2;
- frameSize -= 2;
-
- int channel = order / channelSize;
- int channelOffset = order % channelSize;
- int offset = order;
-
- debugC(8, kDebugLoading, "loadFilmLoopDataD2: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
- if (debugChannelSet(8, kDebugLoading)) {
- stream.hexdump(msgWidth);
- }
-
- uint16 segSize = msgWidth;
- uint16 nextStart = (channel + 1) * kSprChannelSizeD2;
-
- while (segSize > 0) {
- Sprite sprite(nullptr);
- sprite._movie = g_director->getCurrentMovie();
- if (newFrame.sprites.contains(channel)) {
- sprite = newFrame.sprites.getVal(channel);
- }
-
- sprite._spriteType = kCastMemberSprite;
- sprite._stretch = true;
-
- uint16 needSize = MIN((uint16)(nextStart - offset), segSize);
- int startPosition = stream.pos() - channelOffset;
- int finishPosition = stream.pos() + needSize;
- readSpriteDataD2(stream, sprite, startPosition, finishPosition);
- newFrame.sprites.setVal(channel, sprite);
- segSize -= needSize;
- offset += needSize;
- channel += 1;
- channelOffset = 0;
- nextStart += kSprChannelSizeD2;
- }
-
- frameSize -= msgWidth;
- }
-
- for (auto &s : newFrame.sprites) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD2: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
-
- s._value.setCast(s._value._castId);
- Common::Point topLeft = s._value._startPoint;
- if (s._value._cast) {
- topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
- }
- Common::Rect spriteBbox(
- topLeft.x,
- topLeft.y,
- topLeft.x + s._value._width,
- topLeft.y + s._value._height
- );
- if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
- if ((_initialRect.width() == 0) && (_initialRect.height() == 0)) {
- _initialRect = spriteBbox;
- } else {
- _initialRect.extend(spriteBbox);
- }
- }
- debugC(8, kDebugLoading, "loadFilmLoopDataD2: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-
- }
-
- _frames.push_back(newFrame);
-
- }
- debugC(5, kDebugLoading, "loadFilmLoopDataD2: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-}
-
-void FilmLoopCastMember::loadFilmLoopDataD4(Common::SeekableReadStreamEndian &stream) {
- _initialRect = Common::Rect();
- _frames.clear();
-
- uint32 size = stream.readUint32BE();
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: SCVW body of size: %d", size);
- uint32 pos = stream.pos();
- stream.seek(0);
- stream.hexdump(size);
- stream.seek(pos);
- }
- uint32 framesOffset = stream.readUint32BE();
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: SCVW header of size: %d", framesOffset - 8);
- stream.hexdump(framesOffset - 8);
- }
- stream.skip(6);
- uint16 channelSize = kSprChannelSizeD4;
- stream.readUint16BE(); // should be kSprChannelSizeD4 = 20!
- stream.skip(framesOffset - 16);
-
- FilmLoopFrame newFrame;
-
- while (stream.pos() < size) {
- uint16 frameSize = stream.readUint16BE();
- if (frameSize == 0) {
- continue;
- }
- frameSize -= 2;
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: Frame entry: %d", frameSize);
- stream.hexdump(frameSize);
- }
-
- while (frameSize > 0) {
- uint16 msgWidth = stream.readUint16BE();
- uint16 order = stream.readUint16BE();
- frameSize -= 4;
-
- int channel = order / channelSize;
- int channelOffset = order % channelSize;
- int offset = order;
-
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: Message: msgWidth %d, order: %d, channel %d, channelOffset %d", msgWidth, order, channel, channelOffset);
- if (debugChannelSet(8, kDebugLoading)) {
- stream.hexdump(msgWidth);
- }
-
- uint16 segSize = msgWidth;
- uint16 nextStart = (channel + 1) * kSprChannelSizeD4;
-
- while (segSize > 0) {
- Sprite sprite(nullptr);
- sprite._movie = g_director->getCurrentMovie();
- if (newFrame.sprites.contains(channel)) {
- sprite = newFrame.sprites.getVal(channel);
- }
-
- sprite._stretch = true;
-
- uint16 needSize = MIN((uint16)(nextStart - offset), segSize);
- int startPosition = stream.pos() - channelOffset;
- int finishPosition = stream.pos() + needSize;
- readSpriteDataD4(stream, sprite, startPosition, finishPosition);
- newFrame.sprites.setVal(channel, sprite);
- segSize -= needSize;
- offset += needSize;
- channel += 1;
- channelOffset = 0;
- nextStart += kSprChannelSizeD4;
- }
-
- frameSize -= msgWidth;
- }
-
- for (auto &s : newFrame.sprites) {
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
-
- if (s._key == -1) {
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: Skipping channel -1");
- if (s._value._startPoint.x != 0 || s._value._startPoint.y != 0 || s._value._width != 0 ||
- (s._value._height != -256 && s._value._height != 0))
- warning("BUILDBOT: loadFilmLoopDataD4: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
- continue;
- }
-
- s._value.setCast(s._value._castId);
- Common::Point topLeft = s._value._startPoint;
- if (s._value._cast) {
- topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
- }
- Common::Rect spriteBbox(
- topLeft.x,
- topLeft.y,
- topLeft.x + s._value._width,
- topLeft.y + s._value._height
- );
- if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
- if ((_initialRect.width() == 0) && (_initialRect.height() == 0)) {
- _initialRect = spriteBbox;
- } else {
- _initialRect.extend(spriteBbox);
- }
- }
- debugC(8, kDebugLoading, "loadFilmLoopDataD4: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-
- }
-
- _frames.push_back(newFrame);
-
- }
- debugC(5, kDebugLoading, "loadFilmLoopDataD4: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-
-}
-
-void FilmLoopCastMember::loadFilmLoopDataD5(Common::SeekableReadStreamEndian &stream) {
- _initialRect = Common::Rect();
- _frames.clear();
-
- uint32 size = stream.readUint32BE();
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD5: SCVW body:");
- uint32 pos = stream.pos();
- stream.seek(0);
- stream.hexdump(size);
- stream.seek(pos);
- }
- uint32 framesOffset = stream.readUint32BE();
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD5: SCVW header:");
- stream.hexdump(framesOffset - 8);
- }
- stream.skip(6);
- uint16 channelSize = kSprChannelSizeD5;
- stream.readUint16BE(); // should be kSprChannelSizeD5 = 24!
- stream.skip(framesOffset - 16);
-
- FilmLoopFrame newFrame;
-
- while (stream.pos() < size) {
- uint16 frameSize = stream.readUint16BE();
- if (frameSize == 0) {
- continue;
- }
- frameSize -= 2;
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD5: Frame entry:");
- stream.hexdump(frameSize);
- }
-
- while (frameSize > 0) {
- uint16 msgWidth = stream.readUint16BE();
- uint16 order = stream.readUint16BE();
- frameSize -= 4;
-
- int channel = order / channelSize;
- int channelOffset = order % channelSize;
- int offset = order;
-
- debugC(8, kDebugLoading, "loadFilmLoopDataD5: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
- if (debugChannelSet(8, kDebugLoading)) {
- stream.hexdump(msgWidth);
- }
-
- uint16 segSize = msgWidth;
- uint16 nextStart = (channel + 1) * kSprChannelSizeD5;
-
- while (segSize > 0) {
- Sprite sprite(nullptr);
- sprite._movie = g_director->getCurrentMovie();
- if (newFrame.sprites.contains(channel)) {
- sprite = newFrame.sprites.getVal(channel);
- }
-
- sprite._stretch = true;
-
- uint16 needSize = MIN((uint16)(nextStart - offset), segSize);
- int startPosition = stream.pos() - channelOffset;
- int finishPosition = stream.pos() + needSize;
- readSpriteDataD5(stream, sprite, startPosition, finishPosition);
- // Swap castLib ID value of -1 for the film loop's castLib ID
- if (sprite._castId.castLib == -1)
- sprite._castId.castLib = _cast->_castLibID;
- if (sprite._scriptId.castLib == -1)
- sprite._scriptId.castLib = _cast->_castLibID;
- newFrame.sprites.setVal(channel, sprite);
- segSize -= needSize;
- offset += needSize;
- channel += 1;
- channelOffset = 0;
- nextStart += kSprChannelSizeD5;
- }
-
- frameSize -= msgWidth;
- }
-
- for (auto &s : newFrame.sprites) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD5: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
-
- if (s._key == -1) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD5: Skipping channel -1");
- if (s._value._startPoint.x != 0 || s._value._startPoint.y != 0 || s._value._width != 0 ||
- (s._value._height != -256 && s._value._height != 0))
- warning("BUILDBOT: loadFilmLoopDataD5: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
- continue;
- }
-
- s._value.setCast(s._value._castId);
- Common::Point topLeft = s._value._startPoint;
- if (s._value._cast) {
- topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
- }
- Common::Rect spriteBbox(
- topLeft.x,
- topLeft.y,
- topLeft.x + s._value._width,
- topLeft.y + s._value._height
- );
- if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
- if ((_initialRect.width() == 0) && (_initialRect.height() == 0)) {
- _initialRect = spriteBbox;
- } else {
- _initialRect.extend(spriteBbox);
- }
- }
- debugC(8, kDebugLoading, "loadFilmLoopDataD5: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-
- }
-
- _frames.push_back(newFrame);
-
- }
- debugC(5, kDebugLoading, "loadFilmLoopDataD5: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-}
-
-void FilmLoopCastMember::loadFilmLoopDataD6(Common::SeekableReadStreamEndian &stream) {
- _initialRect = Common::Rect();
- _frames.clear();
-
- uint32 size = stream.readUint32BE();
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD6: SCVW body:");
- uint32 pos = stream.pos();
- stream.seek(0);
- stream.hexdump(size);
- stream.seek(pos);
- }
- uint32 framesOffset = stream.readUint32BE();
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD6: SCVW header:");
- stream.hexdump(framesOffset - 8);
- }
- stream.skip(6);
- uint16 channelSize = kSprChannelSizeD6;
- stream.readUint16BE(); // should be kSprChannelSizeD6 = 24!
- stream.skip(framesOffset - 16);
-
- FilmLoopFrame newFrame;
-
- while (stream.pos() < size) {
- uint16 frameSize = stream.readUint16BE();
- if (frameSize == 0) {
- continue;
- }
- frameSize -= 2;
- if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD6: Frame entry:");
- stream.hexdump(frameSize);
- }
-
- while (frameSize > 0) {
- uint16 msgWidth = stream.readUint16BE();
- uint16 order = stream.readUint16BE();
- frameSize -= 4;
-
- int channel = order / channelSize;
- int channelOffset = order % channelSize;
- int offset = order;
-
- debugC(8, kDebugLoading, "loadFilmLoopDataD6: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
- if (debugChannelSet(8, kDebugLoading)) {
- stream.hexdump(msgWidth);
- }
-
- uint16 segSize = msgWidth;
- uint16 nextStart = (channel + 1) * kSprChannelSizeD4;
-
- while (segSize > 0) {
- Sprite sprite(nullptr);
- sprite._movie = g_director->getCurrentMovie();
- if (newFrame.sprites.contains(channel)) {
- sprite = newFrame.sprites.getVal(channel);
- }
-
- sprite._stretch = true;
-
- uint16 needSize = MIN((uint16)(nextStart - offset), segSize);
- int startPosition = stream.pos() - channelOffset;
- int finishPosition = stream.pos() + needSize;
- readSpriteDataD6(stream, sprite, startPosition, finishPosition);
- // Swap castLib ID value of -1 for the film loop's castLib ID
- if (sprite._castId.castLib == -1)
- sprite._castId.castLib = _cast->_castLibID;
- if (sprite._scriptId.castLib == -1)
- sprite._scriptId.castLib = _cast->_castLibID;
- newFrame.sprites.setVal(channel, sprite);
- segSize -= needSize;
- offset += needSize;
- channel += 1;
- channelOffset = 0;
- nextStart += kSprChannelSizeD6;
- }
-
- frameSize -= msgWidth;
- }
-
- for (auto &s : newFrame.sprites) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD6: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
-
- if (s._key == -1) {
- debugC(5, kDebugLoading, "loadFilmLoopDataD6: Skipping channel -1");
- if (s._value._startPoint.x != 0 || s._value._startPoint.y != 0 || s._value._width != 0 ||
- (s._value._height != -256 && s._value._height != 0))
- warning("BUILDBOT: loadFilmLoopDataD6: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
- s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
- s._value._width, s._value._height);
- continue;
- }
-
- s._value.setCast(s._value._castId);
- Common::Point topLeft = s._value._startPoint;
- if (s._value._cast) {
- topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
- }
- Common::Rect spriteBbox(
- topLeft.x,
- topLeft.y,
- topLeft.x + s._value._width,
- topLeft.y + s._value._height
- );
- if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
- if ((_initialRect.width() == 0) && (_initialRect.height() == 0)) {
- _initialRect = spriteBbox;
- } else {
- _initialRect.extend(spriteBbox);
- }
- }
- debugC(8, kDebugLoading, "loadFilmLoopDataD6: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-
- }
-
- _frames.push_back(newFrame);
-
- }
- debugC(5, kDebugLoading, "loadFilmLoopDataD6: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
-}
-
-#endif
-
Common::String FilmLoopCastMember::formatInfo() {
return Common::String::format(
"initialRect: %dx%d@%d,%d, boundingRect: %dx%d@%d,%d, frameCount: %d, subchannelCount: %d, enableSound: %d, looping: %d, crop: %d, center: %d",
Commit: bdfe5780a5f699f984c1c7952be3a9f5cb4568b4
https://github.com/scummvm/scummvm/commit/bdfe5780a5f699f984c1c7952be3a9f5cb4568b4
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Completely disable Lingo in filmloops
Changed paths:
engines/director/castmember/filmloop.cpp
engines/director/movie.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index f069ea0ce0e..962b0e2a007 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -233,7 +233,7 @@ void FilmLoopCastMember::load() {
if (loop) {
debugC(2, kDebugLoading, "****** FilmLoopCastMember::load(): Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
- _score = new Score(g_director->getCurrentMovie());
+ _score = new Score(g_director->getCurrentMovie(), false);
_score->loadFrames(*loop, _cast->_version, true);
delete loop;
} else {
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index b840a3a4770..8f0f978527b 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -82,7 +82,7 @@ Movie::Movie(Window *window) {
_cast = new Cast(this, DEFAULT_CAST_LIB);
_casts.setVal(_cast->_castLibID, _cast);
_sharedCast = nullptr;
- _score = new Score(this);
+ _score = new Score(this, true);
_selEnd = -1;
_selStart = -1;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index e2a31dd17ae..0b81080537a 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -55,11 +55,12 @@ namespace Director {
#include "director/palette-fade.h"
-Score::Score(Movie *movie) {
+Score::Score(Movie *movie, bool haveInteractivity) {
_movie = movie;
_window = movie->getWindow();
_vm = _movie->getVM();
_lingo = _vm->getLingo();
+ _haveInteractivity = haveInteractivity;
_soundManager = _window->getSoundManager();
@@ -329,6 +330,9 @@ void Score::startPlay() {
return;
}
+ if (_haveInteractivity && _version >= kFileVer300)
+ _movie->processEvent(kEventStartMovie);
+
// load first frame (either 1 or _nextFrame)
updateCurrentFrame();
@@ -351,23 +355,25 @@ void Score::step() {
if (_playState == kPlayStopped)
return;
- if (!_movie->_inputEventQueue.empty() && !_window->frozenLingoStateCount()) {
- _lingo->processEvents(_movie->_inputEventQueue, true);
- }
- if (_version >= kFileVer300 && !_window->_newMovieStarted && _playState != kPlayStopped) {
- _movie->processEvent(kEventIdle);
+ if (_haveInteractivity) {
+ if (!_movie->_inputEventQueue.empty() && !_window->frozenLingoStateCount()) {
+ _lingo->processEvents(_movie->_inputEventQueue, true);
+ }
+ if (_version >= kFileVer300 && !_window->_newMovieStarted && _playState != kPlayStopped) {
+ _movie->processEvent(kEventIdle);
- if (_version >= kFileVer600) {
- if (_movie->_currentHoveredSpriteId) {
- _movie->processEvent(kEventMouseWithin, _movie->_currentHoveredSpriteId);
- }
+ if (_version >= kFileVer600) {
+ if (_movie->_currentHoveredSpriteId) {
+ _movie->processEvent(kEventMouseWithin, _movie->_currentHoveredSpriteId);
+ }
- _soundManager->processCuePoints();
- } else if (_version >= kFileVer500) {
- // In D5, these events are only generated if a mouse button is pressed
- bool isButtonDown = !Director::DT::isMouseInputIgnored() && (g_system->getEventManager()->getButtonState() != 0);
- if (_movie->_currentHoveredSpriteId && isButtonDown) {
- _movie->processEvent(kEventMouseWithin, _movie->_currentHoveredSpriteId);
+ _soundManager->processCuePoints();
+ } else if (_version >= kFileVer500) {
+ // In D5, these events are only generated if a mouse button is pressed
+ bool isButtonDown = !Director::DT::isMouseInputIgnored() && (g_system->getEventManager()->getButtonState() != 0);
+ if (_movie->_currentHoveredSpriteId && isButtonDown) {
+ _movie->processEvent(kEventMouseWithin, _movie->_currentHoveredSpriteId);
+ }
}
}
}
@@ -393,9 +399,13 @@ void Score::stopPlay() {
if (_stopPlayCalled)
return;
_stopPlayCalled = true;
- if (_version >= kFileVer300)
- _movie->processEvent(kEventStopMovie);
- _lingo->executePerFrameHook(-1, 0);
+
+ if (_haveInteractivity) {
+ if (_version >= kFileVer300)
+ _movie->processEvent(kEventStopMovie);
+
+ _lingo->executePerFrameHook(-1, 0);
+ }
}
void Score::setDelay(uint32 ticks) {
@@ -661,7 +671,7 @@ void Score::update() {
// When Lingo::func_goto* is called, _nextFrame is set
// and _skipFrameAdvance is set to true.
// exitFrame is not called in this case.
- if (!_window->_skipFrameAdvance && !_exitFrameCalled) {
+ if (_haveInteractivity && !_window->_skipFrameAdvance && !_exitFrameCalled) {
// Exit the current frame. This can include scopeless ScoreScripts.
_movie->processEvent(kEventExitFrame);
_exitFrameCalled = true;
@@ -708,64 +718,68 @@ void Score::update() {
debugC(1, kDebugEvents, "##############################");
g_debugger->frameHook();
- // movie could have been stopped by a window switch or a debug flag
- if (_playState == kPlayStopped) {
- processFrozenScripts();
- return;
- }
+ uint32 count = 0;
+
+ if (_haveInteractivity) {
+ // movie could have been stopped by a window switch or a debug flag
+ if (_playState == kPlayStopped) {
+ processFrozenScripts();
+ return;
+ }
- uint32 count = _window->frozenLingoStateCount();
+ count = _window->frozenLingoStateCount();
- // Director 4 and below will allow infinite recursion via the perFrameHook.
- if (_version < kFileVer500) {
- // new frame, first call the perFrameHook (if one exists)
- if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
- // Call the perFrameHook as soon as a frame switch is done.
- // If there is a transition, the perFrameHook is called
- // after each transition subframe instead of here.
- if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
- _lingo->executePerFrameHook(_curFrameNumber, 0);
+ // Director 4 and below will allow infinite recursion via the perFrameHook.
+ if (_version < kFileVer500) {
+ // new frame, first call the perFrameHook (if one exists)
+ if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+ // Call the perFrameHook as soon as a frame switch is done.
+ // If there is a transition, the perFrameHook is called
+ // after each transition subframe instead of here.
+ if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
+ _lingo->executePerFrameHook(_curFrameNumber, 0);
+ }
}
+ if (_window->frozenLingoStateCount() > count)
+ return;
}
- if (_window->frozenLingoStateCount() > count)
- return;
- }
- // Check to see if we've hit the recursion limit
- if (_version >= kFileVer400 && _window->frozenLingoRecursionCount() >= 2) {
- debugC(1, kDebugEvents, "Score::update(): hitting D4 recursion depth limit, defrosting");
- processFrozenScripts(true);
- return;
- } else if (_window->frozenLingoStateCount() >= 64) {
- warning("Score::update(): Stopping runaway script recursion. By this point D3 will have run out of stack space");
- processFrozenScripts();
- return;
- }
+ // Check to see if we've hit the recursion limit
+ if (_version >= kFileVer400 && _window->frozenLingoRecursionCount() >= 2) {
+ debugC(1, kDebugEvents, "Score::update(): hitting D4 recursion depth limit, defrosting");
+ processFrozenScripts(true);
+ return;
+ } else if (_window->frozenLingoStateCount() >= 64) {
+ warning("Score::update(): Stopping runaway script recursion. By this point D3 will have run out of stack space");
+ processFrozenScripts();
+ return;
+ }
- // Director 5 and above actually check for recursion for the perFrameHook.
- if (_version >= kFileVer500) {
- // new frame, first call the perFrameHook (if one exists)
- if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
- // Call the perFrameHook as soon as a frame switch is done.
- // If there is a transition, the perFrameHook is called
- // after each transition subframe instead of here.
- //
- // This also sends stepFrame message to actorList
- if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
- _lingo->executePerFrameHook(_curFrameNumber, 0);
+ // Director 5 and above actually check for recursion for the perFrameHook.
+ if (_version >= kFileVer500) {
+ // new frame, first call the perFrameHook (if one exists)
+ if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+ // Call the perFrameHook as soon as a frame switch is done.
+ // If there is a transition, the perFrameHook is called
+ // after each transition subframe instead of here.
+ //
+ // This also sends stepFrame message to actorList
+ if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
+ _lingo->executePerFrameHook(_curFrameNumber, 0);
+ }
}
+ if (_window->frozenLingoStateCount() > count)
+ return;
}
- if (_window->frozenLingoStateCount() > count)
- return;
- }
- if (_version >= kFileVer600) {
- bool prevDis = _disableGoPlayUpdateStage;
- _disableGoPlayUpdateStage = true;
+ if (_version >= kFileVer600) {
+ bool prevDis = _disableGoPlayUpdateStage;
+ _disableGoPlayUpdateStage = true;
- _movie->broadcastEvent(kEventPrepareFrame);
+ _movie->broadcastEvent(kEventPrepareFrame);
- _disableGoPlayUpdateStage = prevDis;
+ _disableGoPlayUpdateStage = prevDis;
+ }
}
bool sound1Changed = true;
@@ -787,6 +801,9 @@ void Score::update() {
renderFrame(_curFrameNumber, kRenderModeNormal, sound1Changed, sound2Changed);
_window->_newMovieStarted = false;
+ if (!_haveInteractivity)
+ return;
+
// then call the stepMovie hook (if one exists)
// D4 and above only call it if _allowOutdatedLingo is enabled.
count = _window->frozenLingoStateCount();
diff --git a/engines/director/score.h b/engines/director/score.h
index 33329321bd9..0e5a7c03d8c 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -65,7 +65,7 @@ struct Label {
class Score {
public:
- Score(Movie *movie);
+ Score(Movie *movie, bool haveInteractivity);
~Score();
Movie *getMovie() const { return _movie; }
@@ -236,6 +236,8 @@ public:
bool _disableGoPlayUpdateStage;
+ bool _haveInteractivity;
+
private:
DirectorEngine *_vm;
Lingo *_lingo;
Commit: e720eaf75509167a3e77df724fa1149e45d5b65e
https://github.com/scummvm/scummvm/commit/e720eaf75509167a3e77df724fa1149e45d5b65e
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Let Filmloop castmember Score keep its own state
Changed paths:
engines/director/castmember/filmloop.cpp
engines/director/score.cpp
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index 962b0e2a007..fa0c8c4d7ee 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -117,8 +117,8 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
// get the list of sprite IDs for this frame
Common::Array<int> spriteIds;
- for (uint i = 0; i < _score->_scoreCache[frame]->_sprites.size(); ++i) {
- if (_score->_scoreCache[frame]->_sprites[i] && !_score->_scoreCache[frame]->_sprites[i]->_castId.isNull())
+ for (uint i = 0; i < _score->_channels.size(); ++i) {
+ if (_score->_channels[i]->_sprite && !_score->_channels[i]->_sprite->_castId.isNull())
spriteIds.push_back(i);
}
@@ -133,7 +133,7 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
// copy the sprites in order to the list
for (auto &iter : spriteIds) {
- Sprite *src = _score->_scoreCache[frame]->_sprites[iter];
+ Sprite *src = _score->_channels[iter]->_sprite;
if (src->_castId.isNull())
continue;
// translate sprite relative to the global bounding box
@@ -162,6 +162,7 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
Channel chan(nullptr, src);
_subchannels.push_back(chan);
}
+
// Initialise the widgets on all of the subchannels.
// This has to be done once the list has been constructed, otherwise
// the list grow operation will erase the widgets as they aren't
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 0b81080537a..7d847451068 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -164,6 +164,9 @@ bool Score::processFrozenPlayScript() {
bool Score::processFrozenScripts(bool recursion, int count) {
+ if (!_haveInteractivity)
+ return true;
+
if (!processFrozenPlayScript())
return false;
@@ -928,11 +931,11 @@ void Score::incrementFilmLoops() {
if (!fl->_score->_scoreCache.empty()) {
// increment the film loop counter
if (fl->_looping) {
- it->_filmLoopFrame += 1;
- it->_filmLoopFrame %= fl->_score->_scoreCache.size();
- } else if (it->_filmLoopFrame < (fl->_score->_scoreCache.size() - 1)) {
- it->_filmLoopFrame += 1;
+ if (_curFrameNumber + 1 > getFramesNum())
+ fl->_score->setCurrentFrame(1);
}
+
+ fl->_score->step();
} else {
warning("Score::updateFilmLoops(): invalid film loop in castId %s", it->_sprite->_castId.asString().c_str());
}
Commit: 828966aeb749b691dfd0634eae6a045fc75ae58b
https://github.com/scummvm/scummvm/commit/828966aeb749b691dfd0634eae6a045fc75ae58b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Streamlined filmloop sprites passing
Changed paths:
engines/director/castmember/filmloop.cpp
engines/director/score.cpp
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index fa0c8c4d7ee..13a20f0edd6 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -131,35 +131,45 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
bbox.top + bbox.height()/2,
bbox.width(), bbox.height());
+ bool needToScale = (bbox.width() != _initialRect.width() || bbox.height() != _initialRect.height());
+ float scaleX = 1.0f;
+ float scaleY = 1.0f;
+
+ if (needToScale) {
+ scaleX = (float)bbox.width() / _initialRect.width();
+ scaleY = (float)bbox.height() / _initialRect.height();
+ }
+
// copy the sprites in order to the list
for (auto &iter : spriteIds) {
- Sprite *src = _score->_channels[iter]->_sprite;
- if (src->_castId.isNull())
+ Sprite src = *_score->_channels[iter]->_sprite;
+ if (src._castId.isNull())
continue;
+
+ debugCN(5, kDebugImages, "FilmLoopCastMember::getSubChannels(): sprite: %d - cast: %s, orig: %d,%d %dx%d",
+ iter, src._castId.asString().c_str(),
+ src._startPoint.x, src._startPoint.y, src._width, src._height);
+
// translate sprite relative to the global bounding box
- int16 relX = (src->_startPoint.x - _initialRect.left) * widgetRect.width() / _initialRect.width();
- int16 relY = (src->_startPoint.y - _initialRect.top) * widgetRect.height() / _initialRect.height();
- int16 absX = relX + bbox.left;
- int16 absY = relY + bbox.top;
- int16 width = src->_width * widgetRect.width() / _initialRect.width();
- int16 height = src->_height * widgetRect.height() / _initialRect.height();
-
- debugC(5, kDebugImages, "FilmLoopCastMember::getSubChannels(): sprite: %d - cast: %s, orig: %d,%d %dx%d, trans: %d,%d %dx%d",
- iter, src->_castId.asString().c_str(),
- src->_startPoint.x, src->_startPoint.y, src->_width, src->_height,
- absX, absY, width, height);
-
- // Re-inject the translated position into the Sprite.
- // This saves the hassle of having to force the Channel to be in puppet mode.
- src->_width = width;
- src->_height = height;
- src->_startPoint = Common::Point(absX, absY);
- src->_stretch = true;
+ if (needToScale) {
+ src._startPoint.x = (src._startPoint.x - _initialRect.left) * scaleX + bbox.left;
+ src._startPoint.y = (src._startPoint.y - _initialRect.top) * scaleY + bbox.top;
+ src._width = widgetRect.width();
+ src._height = widgetRect.height();
+ src._stretch = true;
+
+ debugCN(5, kDebugImages, ", scaled: %d,%d %dx%d", src._startPoint.x, src._startPoint.y, src._width, src._height);
+ } else {
+ src._startPoint.x += bbox.left;
+ src._startPoint.y += bbox.top;
+
+ debugCN(5, kDebugImages, ", no scaling");
+ }
// Film loop frames are constructed as a series of Channels, much like how a normal frame
// is rendered by the Score. We don't include a pointer to the current Score here,
// that's only for querying the constraint channel which is not used.
- Channel chan(nullptr, src);
+ Channel chan(nullptr, &src);
_subchannels.push_back(chan);
}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 7d847451068..ca8623760a9 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -799,14 +799,14 @@ void Score::update() {
}
_firstRun = false;
-
- // Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
- renderFrame(_curFrameNumber, kRenderModeNormal, sound1Changed, sound2Changed);
_window->_newMovieStarted = false;
if (!_haveInteractivity)
return;
+ // Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
+ renderFrame(_curFrameNumber, kRenderModeNormal, sound1Changed, sound2Changed);
+
// then call the stepMovie hook (if one exists)
// D4 and above only call it if _allowOutdatedLingo is enabled.
count = _window->frozenLingoStateCount();
Commit: 13836af96c200771343b938cd5a70fdc214306bf
https://github.com/scummvm/scummvm/commit/13836af96c200771343b938cd5a70fdc214306bf
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Filmloop: Fix filmloop scaling bug
Changed paths:
engines/director/castmember/filmloop.cpp
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index 13a20f0edd6..fd851a4d44a 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -160,8 +160,8 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, u
debugCN(5, kDebugImages, ", scaled: %d,%d %dx%d", src._startPoint.x, src._startPoint.y, src._width, src._height);
} else {
- src._startPoint.x += bbox.left;
- src._startPoint.y += bbox.top;
+ src._startPoint.x = (src._startPoint.x - _initialRect.left) + bbox.left;
+ src._startPoint.y = (src._startPoint.y - _initialRect.top) + bbox.top;
debugCN(5, kDebugImages, ", no scaling");
}
Commit: b0f735987622de32ee3bb471a5e0895541d05927
https://github.com/scummvm/scummvm/commit/b0f735987622de32ee3bb471a5e0895541d05927
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-04-09T12:51:31+02:00
Commit Message:
DIRECTOR: Fix crash when setting picture of unloaded bitmap cast member
Changed paths:
engines/director/castmember/bitmap.cpp
diff --git a/engines/director/castmember/bitmap.cpp b/engines/director/castmember/bitmap.cpp
index 726534b1c90..6fa40e136b2 100644
--- a/engines/director/castmember/bitmap.cpp
+++ b/engines/director/castmember/bitmap.cpp
@@ -409,6 +409,8 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
}
Graphics::Surface *BitmapCastMember::getDitherImg() {
+ if (!_picture->_surface.getPixels())
+ return nullptr;
Graphics::Surface *dither = nullptr;
// Convert indexed image to indexed palette
More information about the Scummvm-git-logs
mailing list