[Scummvm-git-logs] scummvm master -> 4c27273b6071d5347d901809452734312e966ad7
sev-
noreply at scummvm.org
Mon Jul 10 14:03:36 UTC 2023
This automated email contains information about 44 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
2b331582aa DIRECTOR: Change preloading of frames to demand loading
81a0a5b7e0 DIRECTOR: Fix indirect memory leakage, added in-memory data store.
bcc3ad7f66 DIRECTOR: Refactored quickSelect to getFrameData
fdd8c34691 DIRECTOR: Rename _frame, getCurrentFrame(), getTotalFrames() to improve readability
2cac64a069 DIRECTOR: Debugger use frame demand loading to view channels
5ec6a62fe8 DIRECTOR: Change _frameStream to read and wrap stream data
b29f01dc20 DIRECTOR: Added corner condition while on demand reading of frames.
6cdd4a92db DIRECTOR: Load all of VWSC resource in framesStream
64a214fa86 DIRECTOR: Fix framesSize exceeded for demand loaded frames
f3928ec4cf DIRECTOR: Rebuild channel data when frame jumping, fix screen freeze bugs.
af82ea2769 DIRECTOR: Fix frame number mismatch with total frames in score
8b259c8627 DIRECTOR: Minor changes, comments and some more corrections
8112a3b89c DIRECTOR: Remove redundant null check from frames
5c3f4b837b DIRECTOR: Refactored score class, changed comments
aeac3e2d21 DIRECTOR: Refactor loadOneFrame() to remove clutter
4245cc2607 DIRECTOR: Initial frame loading refactoring
4a259ea14f DIRECTOR: Set autopuppet flag for all D versions
c849d2423c DIRECTOR: Skip autopuppet sprites on channel loading
aa44019679 DIRECTOR: Copy channels to _currentFrame before frame data loading
e99a9d4511 DIRECTOR: Check sprites for bg/fg changes when rendering
f594c08eca DIRECTOR: Treat autopuppets same as puppets when looking at sprite changes
9160173b0a DIRECTOR: Do not override autopuppet sprites
c25f7663e4 DIRECTOR: Incremental frame loading for D2
f8a7541bbb DIRECTOR: JANITORIAL: Rearrange channel loading methods in logical order
5b964c31d6 DIRECTOR: Initial code for incremental D5 frame loading
0ce2892a19 DIRECTOR: Initial code for incremental D6 frame loading
30fdc2a9e2 DIRECTOR: Do not process frame actions multiple times
4eadd3b7bf DIRECTOR: Reset frame fully on rewind. This fixes D2-D3
cd3be9ac18 DIRECTOR: Remove Score::_channelData. We now read frames dynamically
5d13fc92d2 DIRECTOR: Improve debug output
6c179cd213 DIRECTOR: D5 score loading fixes
e59fe04d0f DIRECTOR: Added sanity checks to frame loading
f04dc8b105 DIRECTOR: More splits for D5 channel loading
564482ac8f DIRECTOR: Remove now obsolete Frame::readChannels()
00cacd4fdb DIRECTOR: Split more D4 channel loading
85c11d9b5a DIRECTOR: More channel loading split
7a4456785b DIRECTOR: Split D2 channel loading
582c673193 DIRECTOR: Optimize frameOffsets calculation
e0648bd308 DIRECTOR: Confirmed behaviour of immediateSprite and puppetSprite built-ins
18ab952dd4 DIRECTOR: Added another patch for warlock-win
013b8c3068 DIRECTOR: Simplified offset calculation in channel loading
64b3159825 DIRECTOR: Added forceredraw debugger command
4a535f6b52 DIRECTOR: Copy sprites from the channel to the current frame
4c27273b60 DIRECTOR: Disable frame copying code and added puppet check to it
Commit: 2b331582aa883f190cf16c0e4d4a20d85ea9d6bc
https://github.com/scummvm/scummvm/commit/2b331582aa883f190cf16c0e4d4a20d85ea9d6bc
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Change preloading of frames to demand loading
Frames are now loaded on demand, when they are first accessed. Also
the starting offsets of each frames are stored in a special array, so
any previously visited frame might have quick access time. Much of the
work is done in Score class itself.
Warning: This commit is not yet complete. There are various issues
and crashes on the way.
Demand loading of frames is implemented to replicate the behavior of
the original engine. The original engine does not load frames until
it is accessed, this property when used with lingo is exploited to
allow changes in sprite properties when there is no next frame changes
of that property. In essential what happened was that for a non puppet
sprites, the game can have its property changed and rendered until there
was full refresh (in form of jumps, etc) of screen. This was not possible
with precached frames.
The first example use was seen in movie `ATD\HD\bdDREAMA.DXR` of game
'totaldistortion-win'.
Changed paths:
engines/director/debugger.cpp
engines/director/events.cpp
engines/director/lingo/lingo-builtins.cpp
engines/director/lingo/lingo-events.cpp
engines/director/lingo/lingo-the.cpp
engines/director/movie.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 6356e2a43fa..cd8941da93b 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -230,7 +230,7 @@ bool Debugger::cmdInfo(int argc, const char **argv) {
debugPrintf("Copy protected: %d\n", cast->_isProtected);
debugPrintf("Remap palettes when needed flag: %d\n", movie->_remapPalettesWhenNeeded);
debugPrintf("Allow outdated Lingo flag: %d\n", movie->_allowOutdatedLingo);
- debugPrintf("Frame count: %d\n", score->_frames.size());
+ debugPrintf("Frame count: %d\n", score->getTotalFrames());
debugPrintf("Cast member count: %d\n", cast->getCastSize());
debugPrintf("Search paths:\n");
if (g_lingo->_searchPath.isArray() && g_lingo->_searchPath.u.farr->arr.size() > 0) {
@@ -276,7 +276,7 @@ bool Debugger::cmdMovie(int argc, const char **argv) {
bool Debugger::cmdChannels(int argc, const char **argv) {
Score *score = g_director->getCurrentMovie()->getScore();
- int maxSize = (int)score->_frames.size();
+ int maxSize = (int)score->getTotalFrames();
int frameId = score->getCurrentFrame();
if (argc == 1) {
debugPrintf("Channel info for current frame %d of %d\n", frameId, maxSize);
@@ -289,7 +289,7 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
if (frameId >= 1 && frameId <= maxSize) {
debugPrintf("Channel info for frame %d of %d\n", frameId, maxSize);
- debugPrintf("%s\n", score->_frames[frameId-1]->formatChannelInfo().c_str());
+ debugPrintf("%s\n", score->quickSelect(frameId-1)->formatChannelInfo().c_str());
} else {
debugPrintf("Must specify a frame number between 1 and %d.\n", maxSize);
}
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index dc697d9288d..08bb80b7602 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -113,8 +113,8 @@ bool Window::processEvent(Common::Event &event) {
bool Movie::processEvent(Common::Event &event) {
Score *sc = getScore();
- if (sc->getCurrentFrame() >= sc->_frames.size()) {
- warning("processEvents: request to access frame %d of %d", sc->getCurrentFrame(), sc->_frames.size() - 1);
+ if (sc->getCurrentFrame() >= sc->getTotalFrames()) {
+ warning("processEvents: request to access frame %d of %d", sc->getCurrentFrame(), sc->getTotalFrames() - 1);
return false;
}
uint16 spriteId = 0;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 3a9acf5daf2..a99cae0f86a 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1546,7 +1546,7 @@ void LB::b_preLoad(int nargs) {
// We always pretend we preloaded all frames
// Returning the number of the last frame successfully "loaded"
if (nargs == 0) {
- g_lingo->_theResult = Datum((int)g_director->getCurrentMovie()->getScore()->_frames.size());
+ g_lingo->_theResult = Datum((int)g_director->getCurrentMovie()->getScore()->getTotalFrames());
return;
}
@@ -2334,7 +2334,7 @@ void LB::b_move(int nargs) {
b_erase(1);
Score *score = movie->getScore();
uint16 frame = score->getCurrentFrame();
- Frame *currentFrame = score->_frames[frame];
+ Frame *currentFrame = score->_frame;
auto channels = score->_channels;
score->renderFrame(frame, kRenderForceUpdate);
@@ -2363,7 +2363,7 @@ void LB::b_move(int nargs) {
void LB::b_moveableSprite(int nargs) {
Movie *movie = g_director->getCurrentMovie();
Score *score = movie->getScore();
- Frame *frame = score->_frames[score->getCurrentFrame()];
+ Frame *frame = score->_frame;
if (g_lingo->_currentChannelId == -1) {
warning("b_moveableSprite: channel Id is missing");
@@ -2394,7 +2394,7 @@ void LB::b_pasteClipBoardInto(int nargs) {
Score *score = movie->getScore();
uint16 frame = score->getCurrentFrame();
- Frame *currentFrame = score->_frames[frame];
+ Frame *currentFrame = score->_frame;
auto channels = score->_channels;
castMember->setModified(true);
@@ -2567,8 +2567,8 @@ void LB::b_immediateSprite(int nargs) {
if (sc->getNextFrame() && !sp->_immediate) {
// same as puppetSprite
Channel *channel = sc->getChannelById(sprite.asInt());
-
- channel->replaceSprite(sc->_frames[sc->getNextFrame()]->_sprites[sprite.asInt()]);
+ // TODO: Fix logic here for next sprite
+ channel->replaceSprite(sc->_frame->_sprites[sprite.asInt()]);
channel->_dirty = true;
}
@@ -2609,7 +2609,8 @@ void LB::b_puppetSprite(int nargs) {
// sprite in new frame before setting puppet (Majestic).
Channel *channel = sc->getChannelById(sprite.asInt());
- channel->replaceSprite(sc->_frames[sc->getNextFrame()]->_sprites[sprite.asInt()]);
+ // TODO: Fix this properly.
+ channel->replaceSprite(sc->_frame->_sprites[sprite.asInt()]);
channel->_dirty = true;
}
@@ -2766,15 +2767,18 @@ void LB::b_zoomBox(int nargs) {
// Looks for endSprite in the next frame
Common::Rect endRect = score->_channels[endSpriteId]->getBbox();
if (endRect.isEmpty()) {
- if ((uint)curFrame + 1 < score->_frames.size()) {
- Channel endChannel(nullptr, score->_frames[curFrame + 1]->_sprites[endSpriteId]);
- endRect = endChannel.getBbox();
+ if ((uint)curFrame + 1 < score->getTotalFrames()) {
+ Frame* nextFrame = score->quickSelect(curFrame + 1);
+ if (nextFrame) {
+ Channel endChannel(nullptr, nextFrame->_sprites[endSpriteId]);
+ endRect = endChannel.getBbox();
+ }
}
}
if (endRect.isEmpty()) {
if ((uint)curFrame - 1 > 0) {
- Channel endChannel(nullptr, score->_frames[curFrame - 1]->_sprites[endSpriteId]);
+ Channel endChannel(nullptr, score->quickSelect(curFrame - 1)->_sprites[endSpriteId]);
endRect = endChannel.getBbox();
}
}
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 821c712c360..257f542c8a4 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -119,7 +119,7 @@ void Movie::queueSpriteEvent(Common::Queue<LingoEvent> &queue, LEvent event, int
* When more than one movie script [...]
* [D4 docs] */
- Frame *currentFrame = _score->_frames[_score->getCurrentFrame()];
+ Frame *currentFrame = _score->_frame;
assert(currentFrame != nullptr);
Sprite *sprite = _score->getSpriteById(spriteId);
@@ -160,8 +160,8 @@ void Movie::queueFrameEvent(Common::Queue<LingoEvent> &queue, LEvent event, int
// entity = score->getCurrentFrame();
// } else {
- assert(_score->_frames[_score->getCurrentFrame()] != nullptr);
- CastMemberID scriptId = _score->_frames[_score->getCurrentFrame()]->_actionId;
+ assert(_score->_frame != nullptr);
+ CastMemberID scriptId = _score->_frame->_actionId;
if (!scriptId.member)
return;
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index a102382159d..845f76b1942 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -466,7 +466,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
d.u.s = score->getFrameLabel(score->getCurrentFrame());
break;
case kTheFrameScript:
- d = score->_frames[score->getCurrentFrame()]->_actionId.member;
+ d = score->_frame->_actionId.member;
break;
case kTheFramePalette:
d = score->getCurrentPalette();
@@ -523,7 +523,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
d = (int)(_vm->getMacTicks() - movie->_lastEventTime);
break;
case kTheLastFrame:
- d = (int)score->_frames.size() - 1;
+ d = (int)score->getTotalFrames() - 1;
break;
case kTheLastKey:
d = (int)(_vm->getMacTicks() - movie->_lastKeyTime);
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 11774459d2d..6e645f664dd 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -240,7 +240,7 @@ bool Movie::loadArchive() {
}
_score->loadFrames(*r, _version);
- delete r;
+ // delete r;
// Action list
if ((r = _movieArchive->getMovieResourceIfPresent(MKTAG('V', 'W', 'A', 'C'))) != nullptr) {
@@ -248,7 +248,7 @@ bool Movie::loadArchive() {
delete r;
}
- _score->setSpriteCasts();
+ // _score->setSpriteCasts(); TODO: Dynamic loading change this
return true;
}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 22b52a65254..abb4c0a445e 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -39,7 +39,6 @@
#include "director/director.h"
#include "director/cast.h"
#include "director/score.h"
-#include "director/frame.h"
#include "director/movie.h"
#include "director/sound.h"
#include "director/cursor.h"
@@ -72,7 +71,6 @@ Score::Score(Movie *movie) {
_labels = nullptr;
_currentFrameRate = 20;
- _currentFrame = 0;
_nextFrame = 0;
_currentLabel = 0;
_nextFrameTime = 0;
@@ -90,9 +88,6 @@ Score::Score(Movie *movie) {
}
Score::~Score() {
- for (uint i = 0; i < _frames.size(); i++)
- delete _frames[i];
-
for (uint i = 0; i < _channels.size(); i++)
delete _channels[i];
@@ -101,6 +96,10 @@ Score::~Score() {
delete it;
delete _labels;
+
+ if (_framesStream) {
+ delete _framesStream;
+ }
}
CastMemberID Score::getCurrentPalette() {
@@ -199,7 +198,7 @@ int Score::getCurrentLabelNumber() {
int frame = 0;
for (auto &i : *_labels) {
- if (i->number <= _currentFrame)
+ if (i->number <= _curFrameNumber)
frame = i->number;
}
@@ -208,7 +207,7 @@ int Score::getCurrentLabelNumber() {
void Score::gotoNext() {
// we can just try to use the current frame and get the next label
- _nextFrame = getNextLabelNumber(_currentFrame);
+ _nextFrame = getNextLabelNumber(_curFrameNumber);
}
void Score::gotoPrevious() {
@@ -262,11 +261,11 @@ int Score::getPreviousLabelNumber(int referenceFrame) {
}
void Score::startPlay() {
- _currentFrame = 1;
+ _curFrameNumber = 1;
_playState = kPlayStarted;
_nextFrameTime = 0;
- if (_frames.size() <= 1) { // We added one empty sprite
+ if (!_frame) {
warning("Score::startLoop(): Movie has no frames");
_playState = kPlayStopped;
@@ -275,8 +274,8 @@ void Score::startPlay() {
// All frames in the same movie have the same number of channels
if (_playState != kPlayStopped)
- for (uint i = 0; i < _frames[1]->_sprites.size(); i++)
- _channels.push_back(new Channel(this, _frames[1]->_sprites[i], i));
+ for (uint i = 0; i < _frame->_sprites.size(); i++)
+ _channels.push_back(new Channel(this, _frame->_sprites[i], i));
if (_vm->getVersion() >= 300)
_movie->processEvent(kEventStartMovie);
@@ -370,8 +369,8 @@ void Score::update() {
// If there is a transition, the perFrameHook is called
// after each transition subframe instead.
- if (_frames[_currentFrame]->_transType == 0 && _frames[_currentFrame]->_trans.isNull()) {
- _lingo->executePerFrameHook(_currentFrame, 0);
+ if (_frame->_transType == 0 && _frame->_trans.isNull()) {
+ _lingo->executePerFrameHook(_curFrameNumber, 0);
}
}
@@ -385,14 +384,14 @@ void Score::update() {
if (!_vm->_playbackPaused) {
if (_nextFrame)
- _currentFrame = _nextFrame;
+ _curFrameNumber = _nextFrame;
else if (!_window->_newMovieStarted)
- _currentFrame++;
+ _curFrameNumber++;
}
_nextFrame = 0;
- if (_currentFrame >= _frames.size()) {
+ if (_curFrameNumber >= getTotalFrames()) {
Window *window = _vm->getCurrentWindow();
if (!window->_movieStack.empty()) {
MovieReference ref = window->_movieStack.back();
@@ -405,7 +404,7 @@ void Score::update() {
return;
}
- _currentFrame = ref.frameI;
+ _curFrameNumber = ref.frameI;
} else {
if (debugChannelSet(-1, kDebugNoLoop)) {
_playState = kPlayStopped;
@@ -413,21 +412,21 @@ void Score::update() {
return;
}
- _currentFrame = 1;
+ _curFrameNumber = 1;
}
}
if (_labels != nullptr) {
for (auto &i : *_labels) {
- if (i->number == _currentFrame) {
- _currentLabel = _currentFrame;
+ if (i->number == _curFrameNumber) {
+ _currentLabel = _curFrameNumber;
}
}
}
- byte tempo = _frames[_currentFrame]->_scoreCachedTempo;
+ byte tempo = _frame->_scoreCachedTempo;
// puppetTempo is overridden by changes in score tempo
- if (_frames[_currentFrame]->_tempo || tempo != _lastTempo) {
+ if (_frame->_tempo || tempo != _lastTempo) {
_puppetTempo = 0;
} else if (_puppetTempo) {
tempo = _puppetTempo;
@@ -485,10 +484,10 @@ void Score::update() {
if (debugChannelSet(-1, kDebugSlow))
_nextFrameTime += 1000;
- debugC(1, kDebugLoading, "****************************** Current frame: %d, time: %d", _currentFrame, g_system->getMillis(false));
+ debugC(1, kDebugLoading, "****************************** Current frame: %d, time: %d", _curFrameNumber, g_system->getMillis(false));
g_debugger->frameHook();
- _lingo->executeImmediateScripts(_frames[_currentFrame]);
+ _lingo->executeImmediateScripts(_frame);
if (_vm->getVersion() >= 600) {
// _movie->processEvent(kEventBeginSprite);
@@ -497,8 +496,9 @@ void Score::update() {
// TODO: Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
}
+ loadFrame(_curFrameNumber);
// Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
- renderFrame(_currentFrame);
+ renderFrame(_curFrameNumber);
_window->_newMovieStarted = false;
// Enter and exit from previous frame
@@ -578,7 +578,7 @@ void Score::renderFrame(uint16 frameId, RenderMode mode) {
}
bool Score::renderTransition(uint16 frameId) {
- Frame *currentFrame = _frames[frameId];
+ Frame *currentFrame = _frame;
TransParams *tp = _window->_puppetTransition;
if (tp) {
@@ -612,7 +612,7 @@ void Score::renderSprites(uint16 frameId, RenderMode mode) {
for (uint16 i = 0; i < _channels.size(); i++) {
Channel *channel = _channels[i];
Sprite *currentSprite = channel->_sprite;
- Sprite *nextSprite = _frames[frameId]->_sprites[i];
+ Sprite *nextSprite = _frame->_sprites[i];
// widget content has changed and needs a redraw.
// this doesn't include changes in dimension or position!
@@ -666,14 +666,14 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
return false;
// Skip this if we don't have a palette instruction
- CastMemberID currentPalette = _frames[frameId]->_palette.paletteId;
+ CastMemberID currentPalette = _frame->_palette.paletteId;
if (currentPalette.isNull())
return false;
- if (!_frames[frameId]->_palette.colorCycling &&
- !_frames[frameId]->_palette.overTime) {
+ if (!_frame->_palette.colorCycling &&
+ !_frame->_palette.overTime) {
- int frameRate = CLIP<int>(_frames[frameId]->_palette.speed, 1, 30);
+ int frameRate = CLIP<int>(_frame->_palette.speed, 1, 30);
if (debugChannelSet(-1, kDebugFast))
frameRate = 30;
@@ -693,10 +693,10 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
return false;
}
- if (_frames[frameId]->_palette.normal) {
+ if (_frame->_palette.normal) {
// If the target palette ID is the same as the previous palette ID,
// a normal fade is a no-op.
- if (_frames[frameId]->_palette.paletteId == g_director->_lastPalette) {
+ if (_frame->_palette.paletteId == g_director->_lastPalette) {
return false;
}
@@ -734,11 +734,11 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
// the first half happens with the previous frame's layout.
byte *fadePal = nullptr;
- if (_frames[frameId]->_palette.fadeToBlack) {
+ if (_frame->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to black over %d frames", fadeFrames);
fadePal = kBlackPalette;
- } else if (_frames[frameId]->_palette.fadeToWhite) {
+ } else if (_frame->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to white over %d frames", fadeFrames);
fadePal = kWhitePalette;
@@ -782,12 +782,12 @@ void Score::setLastPalette(uint16 frameId) {
return;
bool isCachedPalette = false;
- CastMemberID currentPalette = _frames[frameId]->_palette.paletteId;
+ CastMemberID currentPalette = _frame->_palette.paletteId;
// Palette not specified in the frame
if (currentPalette.isNull()) {
// Use the score cached palette ID
isCachedPalette = true;
- currentPalette = _frames[frameId]->_scoreCachedPaletteId;
+ currentPalette = _frame->_scoreCachedPaletteId;
// The cached ID is created before the cast gets loaded; if it's zero,
// this corresponds to the movie default palette.
if (currentPalette.isNull())
@@ -808,14 +808,14 @@ void Score::setLastPalette(uint16 frameId) {
// Switch to a new palette immediately if:
// - this is color cycling mode, or
// - the cached palette ID is different (i.e. we jumped in the score)
- if (_frames[frameId]->_palette.colorCycling || isCachedPalette)
+ if (_frame->_palette.colorCycling || isCachedPalette)
g_director->setPalette(g_director->_lastPalette);
}
}
bool Score::isPaletteColorCycling() {
- return _frames[_currentFrame]->_palette.colorCycling;
+ return _frame->_palette.colorCycling;
}
void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
@@ -824,7 +824,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// If the palette is defined in the frame and doesn't match
// the current one, set it
- CastMemberID currentPalette = _frames[frameId]->_palette.paletteId;
+ CastMemberID currentPalette = _frame->_palette.paletteId;
if (currentPalette.isNull())
return;
@@ -837,7 +837,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// offset will remain.
// Cycle speed in FPS
- int speed = _frames[frameId]->_palette.speed;
+ int speed = _frame->_palette.speed;
if (speed == 0)
return;
@@ -846,12 +846,12 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// 30 (the maximum) is actually unbounded
int delay = speed == 30 ? 10 : 1000 / speed;
- if (_frames[frameId]->_palette.colorCycling) {
+ if (_frame->_palette.colorCycling) {
// Cycle the colors of a chosen palette
- int firstColor = _frames[frameId]->_palette.firstColor;
- int lastColor = _frames[frameId]->_palette.lastColor;
+ int firstColor = _frame->_palette.firstColor;
+ int lastColor = _frame->_palette.lastColor;
- if (_frames[frameId]->_palette.overTime) {
+ if (_frame->_palette.overTime) {
// Do a single color step in one frame transition
debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, by 1 frame", currentPalette.asString().c_str(), firstColor, lastColor);
g_director->shiftPalette(firstColor, lastColor, false);
@@ -865,8 +865,8 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// Do a full color cycle in one frame transition
int steps = lastColor - firstColor + 1;
- debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, over %d steps %d times", currentPalette.asString().c_str(), firstColor, lastColor, steps, _frames[frameId]->_palette.cycleCount);
- for (int i = 0; i < _frames[frameId]->_palette.cycleCount; i++) {
+ debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, over %d steps %d times", currentPalette.asString().c_str(), firstColor, lastColor, steps, _frame->_palette.cycleCount);
+ for (int i = 0; i < _frame->_palette.cycleCount; i++) {
for (int j = 0; j < steps; j++) {
uint32 startTime = g_system->getMillis();
g_director->shiftPalette(firstColor, lastColor, false);
@@ -884,7 +884,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
int diff = (int)delay - (int)(endTime - startTime);
g_director->delayMillis(MAX(0, diff));
}
- if (_frames[frameId]->_palette.autoReverse) {
+ if (_frame->_palette.autoReverse) {
for (int j = 0; j < steps; j++) {
uint32 startTime = g_system->getMillis();
g_director->shiftPalette(firstColor, lastColor, true);
@@ -912,10 +912,10 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
warning("Score::renderPaletteCycle(): no match for palette id %s", currentPalette.asString().c_str());
return;
}
- int frameCount = _frames[frameId]->_palette.frameCount;
+ int frameCount = _frame->_palette.frameCount;
byte calcPal[768];
- if (_frames[frameId]->_palette.overTime) {
+ if (_frame->_palette.overTime) {
// Transition over a series of frames
if (_paletteTransitionIndex == 0) {
// Copy the current palette into the snapshot buffer
@@ -924,7 +924,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
debugC(2, kDebugImages, "Score::renderPaletteCycle(): fading palette to %s over %d frames", currentPalette.asString().c_str(), frameCount);
}
- if (_frames[frameId]->_palette.normal) {
+ if (_frame->_palette.normal) {
// Fade the palette directly to the new palette
lerpPalette(
calcPal,
@@ -939,10 +939,10 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
int halfway = frameCount / 2;
byte *fadePal = nullptr;
- if (_frames[frameId]->_palette.fadeToBlack) {
+ if (_frame->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
fadePal = kBlackPalette;
- } else if (_frames[frameId]->_palette.fadeToWhite) {
+ } else if (_frame->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
fadePal = kWhitePalette;
} else {
@@ -981,19 +981,19 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// Do a full cycle in one frame transition
// For normal mode, we've already faded the palette in renderPrePaletteCycle
- if (!_frames[frameId]->_palette.normal) {
+ if (!_frame->_palette.normal) {
byte *fadePal = nullptr;
- if (_frames[frameId]->_palette.fadeToBlack) {
+ if (_frame->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
fadePal = kBlackPalette;
- } else if (_frames[frameId]->_palette.fadeToWhite) {
+ } else if (_frame->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
fadePal = kWhitePalette;
} else {
// Shouldn't reach here
return;
}
- int frameRate = CLIP<int>(_frames[frameId]->_palette.speed, 1, 30);
+ int frameRate = CLIP<int>(_frame->_palette.speed, 1, 30);
if (debugChannelSet(-1, kDebugFast))
frameRate = 30;
@@ -1278,13 +1278,13 @@ Sprite *Score::getSpriteById(uint16 id) {
if (channel) {
return channel->_sprite;
} else {
- warning("Score::getSpriteById(): sprite on frame %d with id %d not found", _currentFrame, id);
+ warning("Score::getSpriteById(): sprite on frame %d with id %d not found", _curFrameNumber, id);
return nullptr;
}
}
Sprite *Score::getOriginalSpriteById(uint16 id) {
- Frame *frame = _frames[_currentFrame];
+ Frame *frame = _frame;
if (id < frame->_sprites.size())
return frame->_sprites[id];
warning("Score::getOriginalSpriteById(%d): out of bounds, >= %d", id, frame->_sprites.size());
@@ -1301,7 +1301,7 @@ Channel *Score::getChannelById(uint16 id) {
}
void Score::playSoundChannel(uint16 frameId, bool puppetOnly) {
- Frame *frame = _frames[frameId];
+ Frame *frame = _frame;
debugC(5, kDebugSound, "playSoundChannel(): Sound1 %s Sound2 %s", frame->_sound1.asString().c_str(), frame->_sound2.asString().c_str());
DirectorSound *sound = _window->getSoundManager();
@@ -1352,16 +1352,16 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_numChannelsDisplayed = 30;
} else if (version >= kFileVer400 && version < kFileVer600) {
uint32 frame1Offset = stream.readUint32();
- uint32 numFrames = stream.readUint32();
- uint16 framesVersion = stream.readUint16();
+ _numFrames = stream.readUint32();
+ _framesVersion = stream.readUint16();
uint16 spriteRecordSize = stream.readUint16();
- uint16 numChannels = stream.readUint16();
+ _numChannels = stream.readUint16();
size -= 14;
- if (framesVersion > 13) {
+ if (_framesVersion > 13) {
_numChannelsDisplayed = stream.readUint16();
} else {
- if (framesVersion <= 7) // Director5
+ if (_framesVersion <= 7) // Director5
_numChannelsDisplayed = 48;
else
_numChannelsDisplayed = 120; // D6
@@ -1372,92 +1372,171 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
size -= 2;
warning("STUB: Score::loadFrames. frame1Offset: %x numFrames: %x version: %x spriteRecordSize: %x numChannels: %x numChannelsDisplayed: %x",
- frame1Offset, numFrames, framesVersion, spriteRecordSize, numChannels, _numChannelsDisplayed);
+ frame1Offset, _numFrames, _framesVersion, spriteRecordSize, _numChannels, _numChannelsDisplayed);
// Unknown, some bytes - constant (refer to contuinity).
}
- uint16 channelSize;
- uint16 channelOffset;
+ // TODO How to work with channelData that gets overridden
+ // partically by channels, hence we keep it and read the score from left to right
+ // TODO Merge it with shared cast
+ memset(_channelData, 0, kChannelDataSize);
Frame *initial = new Frame(this, _numChannelsDisplayed);
- // Push a frame at frame#0 position.
+
// This makes all indexing simpler
- _frames.push_back(initial);
+ _frameOffsets.push_back(0);
- // This is a representation of the channelData. It gets overridden
- // partically by channels, hence we keep it and read the score from left to right
- //
- // TODO Merge it with shared cast
- byte channelData[kChannelDataSize];
- memset(channelData, 0, kChannelDataSize);
+ _currentTempo = 0;
+ _currentPaletteId = CastMemberID(0, 0);
+
+ // Setup our streams for further frames processing!
+ _framesStream = &stream;
+ _version = version;
+
+ _frameOffsets.push_back(stream.pos());
+
+ // In case number of frames not known, precompute them!
+ if (_numFrames == 0) {
+ // Calculate number of frames beforehand.
+ int frameCount = 1;
+ while (loadFrame(frameCount)) {
+ frameCount++;
+ }
+ _numFrames = frameCount;
+ }
+
+ loadFrame(1);
+}
+
+bool Score::loadFrame(int frameNum) {
+ // Read existing frame (ie already visited)
+ if (frameNum < (int)_frameOffsets.size()) {
+ // TODO: How _channelData be modified.
+ // We have this frame already, seek and load
+ _framesStream->seek(_frameOffsets[frameNum]);
+ warning("Frame %d, offset %ld", frameNum, _framesStream->pos());
+ if (readOneFrame()) {
+ setSpriteCasts(); // Set sprite casts for each sprite in frame!
+ _curFrameNumber = frameNum;
+ return true;
+ } else {
+ warning("Score::loadFrame(): Problem reading previous frame %d, current offset: %ld", frameNum, _framesStream->pos());
+ return false;
+ }
+ }
+
+ // Seek to latest frame
+ _framesStream->seek(_frameOffsets[_frameOffsets.size() - 1]);
- uint8 currentTempo = 0;
- CastMemberID currentPaletteId = CastMemberID(0, 0);
+ debugC(7, kDebugLoading, "****** Frame request %d, offset %ld", frameNum, _framesStream->pos());
- while (size != 0 && !stream.eos()) {
- uint16 frameSize = stream.readUint16();
- debugC(3, kDebugLoading, "++++++++++ score frame %d (frameSize %d) size %d", _frames.size(), frameSize, size);
+ int currentFrameSkipped = frameNum;
+ // Else read until that specific frame
+ while (_frameOffsets.size() < (uint)frameNum) {
+ if (!readOneFrame(true)) {
+ warning("Score::loadFrame(): Problem reading frame %d, is it outside maximum frames?", frameNum);
+ return false;
+ }
+
+ debugC(7, kDebugLoading, "****** Skipping over a frame %d, offset %ld", currentFrameSkipped, _framesStream->pos());
+ currentFrameSkipped++;
+ }
+
+ bool isRead = readOneFrame(true); // Now final read the frame, this is our target frame!
+ if (isRead) {
+ setSpriteCasts();
+ _curFrameNumber = frameNum;
+ } else {
+ warning("Score::loadFrame(): Problem reading frame %d, current offset: %ld", frameNum, _framesStream->pos());
+ }
+
+ return isRead;
+}
+
+bool Score::readOneFrame(bool saveOffset) {
+ uint16 channelSize;
+ uint16 channelOffset;
+
+ if (!_framesStream->eos()) {
+ uint16 frameSize = _framesStream->readUint16();
+ debugC(3, kDebugLoading, "++++++++++ score frame %d (frameSize %d) saveOffset %d", getTotalFrames(), frameSize, saveOffset);
if (debugChannelSet(8, kDebugLoading)) {
- stream.hexdump(frameSize);
+ _framesStream->hexdump(frameSize);
}
if (frameSize > 0) {
Frame *frame = new Frame(this, _numChannelsDisplayed);
- size -= frameSize;
frameSize -= 2;
while (frameSize != 0) {
if (_vm->getVersion() < 400) {
- channelSize = stream.readByte() * 2;
- channelOffset = stream.readByte() * 2;
+ channelSize = _framesStream->readByte() * 2;
+ channelOffset = _framesStream->readByte() * 2;
frameSize -= channelSize + 2;
} else {
- channelSize = stream.readUint16();
- channelOffset = stream.readUint16();
+ channelSize = _framesStream->readUint16();
+ channelOffset = _framesStream->readUint16();
frameSize -= channelSize + 4;
}
- assert(channelOffset + channelSize < kChannelDataSize);
- stream.read(&channelData[channelOffset], channelSize);
+ if (channelOffset + channelSize >= kChannelDataSize) {
+ // Data ended, no more frames, return
+ return false;
+ }
+ _framesStream->read(&_channelData[channelOffset], channelSize);
}
- Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(channelData, ARRAYSIZE(channelData), stream.isBE());
+ Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(_channelData, ARRAYSIZE(_channelData), _framesStream->isBE());
// str->hexdump(str->size(), 32);
- frame->readChannels(str, version);
+ frame->readChannels(str, _version);
delete str;
// Precache the current FPS tempo, as this carries forward to frames to the right
// of the instruction.
// Delay type tempos (e.g. wait commands, delays) apply to only a single frame, and are ignored here.
if (frame->_tempo && frame->_tempo <= 120)
- currentTempo = frame->_tempo;
- frame->_scoreCachedTempo = frame->_tempo ? frame->_tempo : currentTempo;
+ _currentTempo = frame->_tempo;
+ frame->_scoreCachedTempo = frame->_tempo ? frame->_tempo : _currentTempo;
// Precache the current palette ID, as this carries forward to frames to the right
// of the instruction.
if (!frame->_palette.paletteId.isNull())
- currentPaletteId = frame->_palette.paletteId;
- frame->_scoreCachedPaletteId = currentPaletteId;
+ _currentPaletteId = frame->_palette.paletteId;
+ frame->_scoreCachedPaletteId = _currentPaletteId;
+
+ debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", getTotalFrames(), frame->_actionId.asString().c_str());
- debugC(8, kDebugLoading, "Score::loadFrames(): Frame %d actionId: %s", _frames.size(), frame->_actionId.asString().c_str());
+ _frame = frame;
- _frames.push_back(frame);
+ if (saveOffset) {
+ // Record the starting offset for this frame!
+ _frameOffsets.push_back(_framesStream->pos());
+ }
+ return true;
} else {
- warning("zero sized frame!? exiting loop until we know what to do with the tags that follow.");
- size = 0;
+ warning("Score::readOneFrame(): Zero sized frame!? exiting loop until we know what to do with the tags that follow.");
}
}
+
+ return false; // Error in loading frame
+}
+
+Frame *Score::quickSelect(int frameNum){
+ // This function is for quickly selecting the frame number, and returning the frame
+ // In case of any problem, it returns nullptr.
+ if (loadFrame(frameNum))
+ return _frame;
+
+ return nullptr;
}
void Score::setSpriteCasts() {
// Update sprite cache of cast pointers/info
- 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);
+ for (uint16 j = 0; j < _frame->_sprites.size(); j++) {
+ _frame->_sprites[j]->setCast(_frame->_sprites[j]->_castId);
- debugC(5, kDebugImages, "Score::setSpriteCasts(): Frame: %d Channel: %d castId: %s type: %d (%s)",
- i, j, _frames[i]->_sprites[j]->_castId.asString().c_str(), _frames[i]->_sprites[j]->_spriteType,
- spriteType2str(_frames[i]->_sprites[j]->_spriteType));
- }
+ debugC(5, kDebugImages, "Score::setSpriteCasts(): Frame: 0 Channel: %d castId: %s type: %d (%s)",
+ j, _frame->_sprites[j]->_castId.asString().c_str(), _frame->_sprites[j]->_spriteType,
+ spriteType2str(_frame->_sprites[j]->_spriteType));
}
}
@@ -1557,16 +1636,20 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
bool *scriptRefs = (bool *)calloc(_actions.size() + 1, sizeof(bool));
+ int currentFrame = _curFrameNumber;
// Now let's scan which scripts are actually referenced
- for (uint i = 0; i < _frames.size(); i++) {
- if ((uint)_frames[i]->_actionId.member <= _actions.size())
- scriptRefs[_frames[i]->_actionId.member] = true;
-
- for (uint16 j = 0; j <= _frames[i]->_numChannels; j++) {
- if ((uint)_frames[i]->_sprites[j]->_scriptId.member <= _actions.size())
- scriptRefs[_frames[i]->_sprites[j]->_scriptId.member] = true;
+ for (uint i = 0; i < getTotalFrames(); i++) {
+ Frame *frame_i = quickSelect(i);
+ if ((uint)frame_i->_actionId.member <= _actions.size())
+ scriptRefs[frame_i->_actionId.member] = true;
+
+ for (uint16 j = 0; j <= frame_i->_numChannels; j++) {
+ if ((uint)frame_i->_sprites[j]->_scriptId.member <= _actions.size())
+ scriptRefs[frame_i->_sprites[j]->_scriptId.member] = true;
}
}
+ _curFrameNumber = currentFrame;
+ loadFrame(_curFrameNumber);
if (ConfMan.getBool("dump_scripts"))
for (auto &j : _actions) {
@@ -1601,7 +1684,7 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
}
Common::String Score::formatChannelInfo() {
- Frame &frame = *_frames[_currentFrame];
+ Frame &frame = *_frame;
Common::String result;
CastMemberID defaultPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
result += Common::String::format("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d, currentFPS: %d\n",
diff --git a/engines/director/score.h b/engines/director/score.h
index fe5d06ff77c..cfd9e6d72e8 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -25,6 +25,7 @@
//#include "graphics/macgui/macwindowmanager.h"
#include "director/cursor.h"
+#include "director/frame.h"
namespace Graphics {
struct Surface;
@@ -74,6 +75,10 @@ public:
Movie *getMovie() const { return _movie; }
void loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version);
+ bool loadFrame(int frame);
+ bool readOneFrame(bool saveOffset = false);
+ Frame *quickSelect(int frameNum);
+
void loadLabels(Common::SeekableReadStreamEndian &stream);
void loadActions(Common::SeekableReadStreamEndian &stream);
void loadSampleSounds(uint type);
@@ -91,8 +96,9 @@ public:
void stopPlay();
void setCurrentFrame(uint16 frameId) { _nextFrame = frameId; }
- uint16 getCurrentFrame() { return _currentFrame; }
+ uint16 getCurrentFrame() { return _curFrameNumber; }
int getNextFrame() { return _nextFrame; }
+ int getTotalFrames() { return _numFrames; }
CastMemberID getCurrentPalette();
@@ -140,11 +146,25 @@ private:
public:
Common::Array<Channel *> _channels;
- Common::Array<Frame *> _frames;
Common::SortedArray<Label *> *_labels;
Common::HashMap<uint16, Common::String> _actions;
Common::HashMap<uint16, bool> _immediateActions;
+ // On demand frames loading
+ uint32 _version;
+ Frame *_frame;
+ uint32 _curFrameNumber;
+ uint32 _numFrames;
+ uint32 _framesVersion;
+ uint32 _numChannels;
+ byte _channelData[kChannelDataSize];
+ uint8 _currentTempo;
+ CastMemberID _currentPaletteId;
+
+ Common::Array<int64> _frameOffsets;
+ uint _framesStreamSize;
+ Common::SeekableReadStreamEndian *_framesStream;
+
byte _currentFrameRate;
byte _puppetTempo;
@@ -173,7 +193,6 @@ private:
Movie *_movie;
Window *_window;
- uint16 _currentFrame;
uint16 _nextFrame;
int _currentLabel;
DirectorSound *_soundManager;
Commit: 81a0a5b7e0029a4487a9f7bb7e205ea5fb119211
https://github.com/scummvm/scummvm/commit/81a0a5b7e0029a4487a9f7bb7e205ea5fb119211
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Fix indirect memory leakage, added in-memory data store.
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index abb4c0a445e..fa2ed2d6104 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -85,6 +85,9 @@ Score::Score(Movie *movie) {
_numChannelsDisplayed = 0;
_skipTransition = false;
+
+ _framesStream = nullptr;
+ _frame = nullptr;
}
Score::~Score() {
@@ -100,6 +103,10 @@ Score::~Score() {
if (_framesStream) {
delete _framesStream;
}
+
+ if (_frame) {
+ delete _frame;
+ }
}
CastMemberID Score::getCurrentPalette() {
@@ -1381,8 +1388,6 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// TODO Merge it with shared cast
memset(_channelData, 0, kChannelDataSize);
- Frame *initial = new Frame(this, _numChannelsDisplayed);
-
// This makes all indexing simpler
_frameOffsets.push_back(0);
@@ -1414,7 +1419,6 @@ bool Score::loadFrame(int frameNum) {
// TODO: How _channelData be modified.
// We have this frame already, seek and load
_framesStream->seek(_frameOffsets[frameNum]);
- warning("Frame %d, offset %ld", frameNum, _framesStream->pos());
if (readOneFrame()) {
setSpriteCasts(); // Set sprite casts for each sprite in frame!
_curFrameNumber = frameNum;
@@ -1481,6 +1485,7 @@ bool Score::readOneFrame(bool saveOffset) {
}
if (channelOffset + channelSize >= kChannelDataSize) {
+ delete frame;
// Data ended, no more frames, return
return false;
}
@@ -1503,12 +1508,17 @@ bool Score::readOneFrame(bool saveOffset) {
_currentPaletteId = frame->_palette.paletteId;
frame->_scoreCachedPaletteId = _currentPaletteId;
- debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", getTotalFrames(), frame->_actionId.asString().c_str());
+ debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, frame->_actionId.asString().c_str());
+ if (_frame != nullptr) {
+ // Delete previous frame before assigning new one!
+ delete _frame;
+ _frame = nullptr;
+ }
_frame = frame;
if (saveOffset) {
- // Record the starting offset for this frame!
+ // Record the starting offset for next frame!
_frameOffsets.push_back(_framesStream->pos());
}
return true;
Commit: bcc3ad7f66f35990d71986d5bd43be8e878af5b7
https://github.com/scummvm/scummvm/commit/bcc3ad7f66f35990d71986d5bd43be8e878af5b7
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Refactored quickSelect to getFrameData
Earlier quickSelect was modifying and contaminating current state
of the score. This was causing problems with the frame demand.
Now quickSelect is only used for previewing one frame and it
doesn't modify the score.
Changed paths:
engines/director/debugger.cpp
engines/director/lingo/lingo-builtins.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index cd8941da93b..01054d5e2d9 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -289,7 +289,7 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
if (frameId >= 1 && frameId <= maxSize) {
debugPrintf("Channel info for frame %d of %d\n", frameId, maxSize);
- debugPrintf("%s\n", score->quickSelect(frameId-1)->formatChannelInfo().c_str());
+ debugPrintf("%s\n", score->getFrameData(frameId-1)->formatChannelInfo().c_str());
} else {
debugPrintf("Must specify a frame number between 1 and %d.\n", maxSize);
}
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index a99cae0f86a..b84970e9eb4 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2768,18 +2768,23 @@ void LB::b_zoomBox(int nargs) {
Common::Rect endRect = score->_channels[endSpriteId]->getBbox();
if (endRect.isEmpty()) {
if ((uint)curFrame + 1 < score->getTotalFrames()) {
- Frame* nextFrame = score->quickSelect(curFrame + 1);
+ Frame *nextFrame = score->getFrameData(curFrame + 1);
if (nextFrame) {
Channel endChannel(nullptr, nextFrame->_sprites[endSpriteId]);
endRect = endChannel.getBbox();
+ delete nextFrame;
}
}
}
if (endRect.isEmpty()) {
if ((uint)curFrame - 1 > 0) {
- Channel endChannel(nullptr, score->quickSelect(curFrame - 1)->_sprites[endSpriteId]);
- endRect = endChannel.getBbox();
+ Frame *prevFrame = score->getFrameData(curFrame - 1);
+ if (prevFrame) {
+ Channel endChannel(nullptr, prevFrame->_sprites[endSpriteId]);
+ endRect = endChannel.getBbox();
+ delete prevFrame;
+ }
}
}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index fa2ed2d6104..36ebf3f4206 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1530,12 +1530,29 @@ bool Score::readOneFrame(bool saveOffset) {
return false; // Error in loading frame
}
-Frame *Score::quickSelect(int frameNum){
- // This function is for quickly selecting the frame number, and returning the frame
+Frame *Score::getFrameData(int frameNum){
+ // This function is for previewing selected frame,
+ // It doesn't make any changes to current render state
// In case of any problem, it returns nullptr.
- if (loadFrame(frameNum))
- return _frame;
+ // Be sure to delete this frame after use!
+
+ // Backup variables
+ int curFrameNumber = _curFrameNumber;
+ Frame *frame = _frame;
+ _frame = nullptr; // To avoid later deletion of frame inside renderOneFrame()
+ byte channelData[kChannelDataSize];
+ memcpy(channelData, _channelData, kChannelDataSize);
+
+ bool isFrameRead = loadFrame(frameNum);
+ // Start restoring all states
+ _curFrameNumber = curFrameNumber;
+ _frame = frame;
+ memcpy(_channelData, channelData, kChannelDataSize);
+
+ if (isFrameRead) {
+ return _frame;
+ }
return nullptr;
}
@@ -1646,10 +1663,9 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
bool *scriptRefs = (bool *)calloc(_actions.size() + 1, sizeof(bool));
- int currentFrame = _curFrameNumber;
// Now let's scan which scripts are actually referenced
for (uint i = 0; i < getTotalFrames(); i++) {
- Frame *frame_i = quickSelect(i);
+ Frame *frame_i = getFrameData(i);
if ((uint)frame_i->_actionId.member <= _actions.size())
scriptRefs[frame_i->_actionId.member] = true;
@@ -1658,8 +1674,6 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
scriptRefs[frame_i->_sprites[j]->_scriptId.member] = true;
}
}
- _curFrameNumber = currentFrame;
- loadFrame(_curFrameNumber);
if (ConfMan.getBool("dump_scripts"))
for (auto &j : _actions) {
diff --git a/engines/director/score.h b/engines/director/score.h
index cfd9e6d72e8..ea4f5bb4554 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -77,7 +77,7 @@ public:
void loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version);
bool loadFrame(int frame);
bool readOneFrame(bool saveOffset = false);
- Frame *quickSelect(int frameNum);
+ Frame *getFrameData(int frameNum);
void loadLabels(Common::SeekableReadStreamEndian &stream);
void loadActions(Common::SeekableReadStreamEndian &stream);
Commit: fdd8c346917cabb61c4b51017e24fbe1b26263c1
https://github.com/scummvm/scummvm/commit/fdd8c346917cabb61c4b51017e24fbe1b26263c1
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Rename _frame, getCurrentFrame(), getTotalFrames() to improve readability
Changed paths:
engines/director/debugger.cpp
engines/director/events.cpp
engines/director/lingo/lingo-builtins.cpp
engines/director/lingo/lingo-events.cpp
engines/director/lingo/lingo-funcs.cpp
engines/director/lingo/lingo-the.cpp
engines/director/lingo/xlibs/unittest.cpp
engines/director/movie.cpp
engines/director/score.cpp
engines/director/score.h
engines/director/window.cpp
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 01054d5e2d9..f08e9a4f7ae 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -230,7 +230,7 @@ bool Debugger::cmdInfo(int argc, const char **argv) {
debugPrintf("Copy protected: %d\n", cast->_isProtected);
debugPrintf("Remap palettes when needed flag: %d\n", movie->_remapPalettesWhenNeeded);
debugPrintf("Allow outdated Lingo flag: %d\n", movie->_allowOutdatedLingo);
- debugPrintf("Frame count: %d\n", score->getTotalFrames());
+ debugPrintf("Frame count: %d\n", score->getFramesNum());
debugPrintf("Cast member count: %d\n", cast->getCastSize());
debugPrintf("Search paths:\n");
if (g_lingo->_searchPath.isArray() && g_lingo->_searchPath.u.farr->arr.size() > 0) {
@@ -256,7 +256,7 @@ bool Debugger::cmdFrame(int argc, const char **argv) {
}
lingo->func_goto(frame, movie);
} else {
- debugPrintf("%d\n", score->getCurrentFrame());
+ debugPrintf("%d\n", score->getCurrentFrameNum());
}
return true;
}
@@ -276,8 +276,8 @@ bool Debugger::cmdMovie(int argc, const char **argv) {
bool Debugger::cmdChannels(int argc, const char **argv) {
Score *score = g_director->getCurrentMovie()->getScore();
- int maxSize = (int)score->getTotalFrames();
- int frameId = score->getCurrentFrame();
+ int maxSize = (int)score->getFramesNum();
+ int frameId = score->getCurrentFrameNum();
if (argc == 1) {
debugPrintf("Channel info for current frame %d of %d\n", frameId, maxSize);
debugPrintf("%s\n", score->formatChannelInfo().c_str());
@@ -387,11 +387,11 @@ bool Debugger::cmdFuncs(int argc, const char **argv) {
Score *score = movie->getScore();
ScriptContext *csc = lingo->_state->context;
if (csc) {
- debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrame());
+ debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrameNum());
debugPrintf(" %d:", csc->_id);
debugPrintf("%s", csc->formatFunctionList(" ").c_str());
} else {
- debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrame());
+ debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrameNum());
debugPrintf(" [empty]\n");
}
debugPrintf("\n");
@@ -430,12 +430,12 @@ bool Debugger::cmdDisasm(int argc, const char **argv) {
Score *score = movie->getScore();
ScriptContext *csc = lingo->_state->context;
if (csc) {
- debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrame());
+ debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrameNum());
for (auto &it : csc->_functionHandlers) {
debugPrintf("%s\n\n", g_lingo->formatFunctionBody(it._value).c_str());
}
} else {
- debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrame());
+ debugPrintf("Functions attached to frame %d:\n", score->getCurrentFrameNum());
debugPrintf(" [empty]\n");
}
debugPrintf("\n");
@@ -963,7 +963,7 @@ void Debugger::bpTest(bool forceCheck) {
bool stop = forceCheck;
uint funcOffset = g_lingo->_state->pc;
Score *score = g_director->getCurrentMovie()->getScore();
- uint frameOffset = score->getCurrentFrame();
+ uint frameOffset = score->getCurrentFrameNum();
if (_bpCheckFunc) {
stop |= _bpMatchFuncOffsets.contains(funcOffset);
}
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 08bb80b7602..3b4d5df48a1 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -113,8 +113,8 @@ bool Window::processEvent(Common::Event &event) {
bool Movie::processEvent(Common::Event &event) {
Score *sc = getScore();
- if (sc->getCurrentFrame() >= sc->getTotalFrames()) {
- warning("processEvents: request to access frame %d of %d", sc->getCurrentFrame(), sc->getTotalFrames() - 1);
+ if (sc->getCurrentFrameNum() >= sc->getFramesNum()) {
+ warning("processEvents: request to access frame %d of %d", sc->getCurrentFrameNum(), sc->getFramesNum() - 1);
return false;
}
uint16 spriteId = 0;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index b84970e9eb4..1d09f6a1c82 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1546,7 +1546,7 @@ void LB::b_preLoad(int nargs) {
// We always pretend we preloaded all frames
// Returning the number of the last frame successfully "loaded"
if (nargs == 0) {
- g_lingo->_theResult = Datum((int)g_director->getCurrentMovie()->getScore()->getTotalFrames());
+ g_lingo->_theResult = Datum((int)g_director->getCurrentMovie()->getScore()->getFramesNum());
return;
}
@@ -2333,8 +2333,8 @@ void LB::b_move(int nargs) {
// Room for improvement, b_erase already marks the sprites as dirty
b_erase(1);
Score *score = movie->getScore();
- uint16 frame = score->getCurrentFrame();
- Frame *currentFrame = score->_frame;
+ uint16 frame = score->getCurrentFrameNum();
+ Frame *currentFrame = score->_currentFrame;
auto channels = score->_channels;
score->renderFrame(frame, kRenderForceUpdate);
@@ -2363,7 +2363,7 @@ void LB::b_move(int nargs) {
void LB::b_moveableSprite(int nargs) {
Movie *movie = g_director->getCurrentMovie();
Score *score = movie->getScore();
- Frame *frame = score->_frame;
+ Frame *frame = score->_currentFrame;
if (g_lingo->_currentChannelId == -1) {
warning("b_moveableSprite: channel Id is missing");
@@ -2393,8 +2393,8 @@ void LB::b_pasteClipBoardInto(int nargs) {
}
Score *score = movie->getScore();
- uint16 frame = score->getCurrentFrame();
- Frame *currentFrame = score->_frame;
+ uint16 frame = score->getCurrentFrameNum();
+ Frame *currentFrame = score->_currentFrame;
auto channels = score->_channels;
castMember->setModified(true);
@@ -2568,7 +2568,7 @@ void LB::b_immediateSprite(int nargs) {
// same as puppetSprite
Channel *channel = sc->getChannelById(sprite.asInt());
// TODO: Fix logic here for next sprite
- channel->replaceSprite(sc->_frame->_sprites[sprite.asInt()]);
+ channel->replaceSprite(sc->_currentFrame->_sprites[sprite.asInt()]);
channel->_dirty = true;
}
@@ -2610,7 +2610,7 @@ void LB::b_puppetSprite(int nargs) {
Channel *channel = sc->getChannelById(sprite.asInt());
// TODO: Fix this properly.
- channel->replaceSprite(sc->_frame->_sprites[sprite.asInt()]);
+ channel->replaceSprite(sc->_currentFrame->_sprites[sprite.asInt()]);
channel->_dirty = true;
}
@@ -2755,7 +2755,7 @@ void LB::b_zoomBox(int nargs) {
int startSpriteId = g_lingo->pop().asInt();
Score *score = g_director->getCurrentMovie()->getScore();
- uint16 curFrame = score->getCurrentFrame();
+ uint16 curFrame = score->getCurrentFrameNum();
Common::Rect startRect = score->_channels[startSpriteId]->getBbox();
if (startRect.isEmpty()) {
@@ -2767,7 +2767,7 @@ void LB::b_zoomBox(int nargs) {
// Looks for endSprite in the next frame
Common::Rect endRect = score->_channels[endSpriteId]->getBbox();
if (endRect.isEmpty()) {
- if ((uint)curFrame + 1 < score->getTotalFrames()) {
+ if ((uint)curFrame + 1 < score->getFramesNum()) {
Frame *nextFrame = score->getFrameData(curFrame + 1);
if (nextFrame) {
Channel endChannel(nullptr, nextFrame->_sprites[endSpriteId]);
@@ -2824,7 +2824,7 @@ void LB::b_updateStage(int nargs) {
movie->getWindow()->render();
// play any puppet sounds that have been queued
- score->playSoundChannel(score->getCurrentFrame(), true);
+ score->playSoundChannel(score->getCurrentFrameNum(), true);
if (score->_cursorDirty) {
score->renderCursor(movie->getWindow()->getMousePos());
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 257f542c8a4..0da7859ebc4 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -119,7 +119,7 @@ void Movie::queueSpriteEvent(Common::Queue<LingoEvent> &queue, LEvent event, int
* When more than one movie script [...]
* [D4 docs] */
- Frame *currentFrame = _score->_frame;
+ Frame *currentFrame = _score->_currentFrame;
assert(currentFrame != nullptr);
Sprite *sprite = _score->getSpriteById(spriteId);
@@ -157,11 +157,11 @@ void Movie::queueFrameEvent(Common::Queue<LingoEvent> &queue, LEvent event, int
*/
// if (event == kEventPrepareFrame || event == kEventIdle) {
- // entity = score->getCurrentFrame();
+ // entity = score->getCurrentFrameNum();
// } else {
- assert(_score->_frame != nullptr);
- CastMemberID scriptId = _score->_frame->_actionId;
+ assert(_score->_currentFrame != nullptr);
+ CastMemberID scriptId = _score->_currentFrame->_actionId;
if (!scriptId.member)
return;
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 58e8c883609..830915f779c 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -111,7 +111,7 @@ void Lingo::func_gotoloop() {
if (!_vm->getCurrentMovie())
return;
Score *score = _vm->getCurrentMovie()->getScore();
- debugC(3, kDebugLingoExec, "Lingo::func_gotoloop(): looping frame %d", score->getCurrentFrame());
+ debugC(3, kDebugLingoExec, "Lingo::func_gotoloop(): looping frame %d", score->getCurrentFrameNum());
score->gotoLoop();
@@ -183,7 +183,7 @@ void Lingo::func_play(Datum &frame, Datum &movie) {
if (movie.type != VOID) {
ref.movie = _vm->getCurrentMovie()->_movieArchive->getPathName();
}
- ref.frameI = _vm->getCurrentMovie()->getScore()->getCurrentFrame();
+ ref.frameI = _vm->getCurrentMovie()->getScore()->getCurrentFrameNum();
// if we are issuing play command from script channel script. then play done should return to next frame
if (g_lingo->_currentChannelId == 0)
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 845f76b1942..6a1806b071f 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -459,14 +459,14 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
d = _floatPrecision;
break;
case kTheFrame:
- d = (int)score->getCurrentFrame();
+ d = (int)score->getCurrentFrameNum();
break;
case kTheFrameLabel:
d.type = STRING;
- d.u.s = score->getFrameLabel(score->getCurrentFrame());
+ d.u.s = score->getFrameLabel(score->getCurrentFrameNum());
break;
case kTheFrameScript:
- d = score->_frame->_actionId.member;
+ d = score->_currentFrame->_actionId.member;
break;
case kTheFramePalette:
d = score->getCurrentPalette();
@@ -523,7 +523,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
d = (int)(_vm->getMacTicks() - movie->_lastEventTime);
break;
case kTheLastFrame:
- d = (int)score->getTotalFrames() - 1;
+ d = (int)score->getFramesNum() - 1;
break;
case kTheLastKey:
d = (int)(_vm->getMacTicks() - movie->_lastKeyTime);
@@ -1149,7 +1149,7 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
g_director->getCurrentWindow()->setStageColor(g_director->transformColor(d.asInt()));
// Redraw the stage
- score->renderSprites(score->getCurrentFrame(), kRenderForceUpdate);
+ score->renderSprites(score->getCurrentFrameNum(), kRenderForceUpdate);
g_director->getCurrentWindow()->render();
break;
case kTheSwitchColorDepth:
@@ -1609,7 +1609,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
break;
case kTheRect:
if (d.type == RECT || (d.type == ARRAY && d.u.farr->arr.size() >= 4)) {
- score->renderSprites(score->getCurrentFrame(), kRenderForceUpdate);
+ score->renderSprites(score->getCurrentFrameNum(), kRenderForceUpdate);
channel->setBbox(
d.u.farr->arr[0].u.i, d.u.farr->arr[1].u.i,
d.u.farr->arr[2].u.i, d.u.farr->arr[3].u.i
diff --git a/engines/director/lingo/xlibs/unittest.cpp b/engines/director/lingo/xlibs/unittest.cpp
index c27af2cc131..e12666a2f8e 100644
--- a/engines/director/lingo/xlibs/unittest.cpp
+++ b/engines/director/lingo/xlibs/unittest.cpp
@@ -86,7 +86,7 @@ void UnitTest::m_UTScreenshot(int nargs) {
// force a full screen redraw before taking the screenshot
Score *score = g_director->getCurrentMovie()->getScore();
- score->renderSprites(score->getCurrentFrame(), kRenderForceUpdate);
+ score->renderSprites(score->getCurrentFrameNum(), kRenderForceUpdate);
Window *window = g_director->getCurrentWindow();
window->render();
Graphics::ManagedSurface *windowSurface = window->getSurface();
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 6e645f664dd..2c910bd639d 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -248,8 +248,6 @@ bool Movie::loadArchive() {
delete r;
}
- // _score->setSpriteCasts(); TODO: Dynamic loading change this
-
return true;
}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 36ebf3f4206..5a26c00cbe9 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -87,7 +87,7 @@ Score::Score(Movie *movie) {
_skipTransition = false;
_framesStream = nullptr;
- _frame = nullptr;
+ _currentFrame = nullptr;
}
Score::~Score() {
@@ -104,8 +104,8 @@ Score::~Score() {
delete _framesStream;
}
- if (_frame) {
- delete _frame;
+ if (_currentFrame) {
+ delete _currentFrame;
}
}
@@ -272,7 +272,7 @@ void Score::startPlay() {
_playState = kPlayStarted;
_nextFrameTime = 0;
- if (!_frame) {
+ if (!_currentFrame) {
warning("Score::startLoop(): Movie has no frames");
_playState = kPlayStopped;
@@ -281,8 +281,8 @@ void Score::startPlay() {
// All frames in the same movie have the same number of channels
if (_playState != kPlayStopped)
- for (uint i = 0; i < _frame->_sprites.size(); i++)
- _channels.push_back(new Channel(this, _frame->_sprites[i], i));
+ for (uint i = 0; i < _currentFrame->_sprites.size(); i++)
+ _channels.push_back(new Channel(this, _currentFrame->_sprites[i], i));
if (_vm->getVersion() >= 300)
_movie->processEvent(kEventStartMovie);
@@ -376,7 +376,7 @@ void Score::update() {
// If there is a transition, the perFrameHook is called
// after each transition subframe instead.
- if (_frame->_transType == 0 && _frame->_trans.isNull()) {
+ if (_currentFrame->_transType == 0 && _currentFrame->_trans.isNull()) {
_lingo->executePerFrameHook(_curFrameNumber, 0);
}
}
@@ -398,7 +398,7 @@ void Score::update() {
_nextFrame = 0;
- if (_curFrameNumber >= getTotalFrames()) {
+ if (_curFrameNumber >= getFramesNum()) {
Window *window = _vm->getCurrentWindow();
if (!window->_movieStack.empty()) {
MovieReference ref = window->_movieStack.back();
@@ -431,9 +431,9 @@ void Score::update() {
}
}
- byte tempo = _frame->_scoreCachedTempo;
+ byte tempo = _currentFrame->_scoreCachedTempo;
// puppetTempo is overridden by changes in score tempo
- if (_frame->_tempo || tempo != _lastTempo) {
+ if (_currentFrame->_tempo || tempo != _lastTempo) {
_puppetTempo = 0;
} else if (_puppetTempo) {
tempo = _puppetTempo;
@@ -494,7 +494,7 @@ void Score::update() {
debugC(1, kDebugLoading, "****************************** Current frame: %d, time: %d", _curFrameNumber, g_system->getMillis(false));
g_debugger->frameHook();
- _lingo->executeImmediateScripts(_frame);
+ _lingo->executeImmediateScripts(_currentFrame);
if (_vm->getVersion() >= 600) {
// _movie->processEvent(kEventBeginSprite);
@@ -585,7 +585,7 @@ void Score::renderFrame(uint16 frameId, RenderMode mode) {
}
bool Score::renderTransition(uint16 frameId) {
- Frame *currentFrame = _frame;
+ Frame *currentFrame = _currentFrame;
TransParams *tp = _window->_puppetTransition;
if (tp) {
@@ -619,7 +619,7 @@ void Score::renderSprites(uint16 frameId, RenderMode mode) {
for (uint16 i = 0; i < _channels.size(); i++) {
Channel *channel = _channels[i];
Sprite *currentSprite = channel->_sprite;
- Sprite *nextSprite = _frame->_sprites[i];
+ Sprite *nextSprite = _currentFrame->_sprites[i];
// widget content has changed and needs a redraw.
// this doesn't include changes in dimension or position!
@@ -673,19 +673,19 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
return false;
// Skip this if we don't have a palette instruction
- CastMemberID currentPalette = _frame->_palette.paletteId;
+ CastMemberID currentPalette = _currentFrame->_palette.paletteId;
if (currentPalette.isNull())
return false;
- if (!_frame->_palette.colorCycling &&
- !_frame->_palette.overTime) {
+ if (!_currentFrame->_palette.colorCycling &&
+ !_currentFrame->_palette.overTime) {
- int frameRate = CLIP<int>(_frame->_palette.speed, 1, 30);
+ int frameRate = CLIP<int>(_currentFrame->_palette.speed, 1, 30);
if (debugChannelSet(-1, kDebugFast))
frameRate = 30;
- int frameDelay = 1000/60;
+ int frameDelay = 1000 / 60;
int fadeFrames = kFadeColorFrames[frameRate - 1];
if (_vm->getVersion() >= 500)
fadeFrames = kFadeColorFramesD5[frameRate - 1];
@@ -700,10 +700,10 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
return false;
}
- if (_frame->_palette.normal) {
+ if (_currentFrame->_palette.normal) {
// If the target palette ID is the same as the previous palette ID,
// a normal fade is a no-op.
- if (_frame->_palette.paletteId == g_director->_lastPalette) {
+ if (_currentFrame->_palette.paletteId == g_director->_lastPalette) {
return false;
}
@@ -741,11 +741,11 @@ bool Score::renderPrePaletteCycle(uint16 frameId, RenderMode mode) {
// the first half happens with the previous frame's layout.
byte *fadePal = nullptr;
- if (_frame->_palette.fadeToBlack) {
+ if (_currentFrame->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to black over %d frames", fadeFrames);
fadePal = kBlackPalette;
- } else if (_frame->_palette.fadeToWhite) {
+ } else if (_currentFrame->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): fading palette to white over %d frames", fadeFrames);
fadePal = kWhitePalette;
@@ -789,12 +789,12 @@ void Score::setLastPalette(uint16 frameId) {
return;
bool isCachedPalette = false;
- CastMemberID currentPalette = _frame->_palette.paletteId;
+ CastMemberID currentPalette = _currentFrame->_palette.paletteId;
// Palette not specified in the frame
if (currentPalette.isNull()) {
// Use the score cached palette ID
isCachedPalette = true;
- currentPalette = _frame->_scoreCachedPaletteId;
+ currentPalette = _currentFrame->_scoreCachedPaletteId;
// The cached ID is created before the cast gets loaded; if it's zero,
// this corresponds to the movie default palette.
if (currentPalette.isNull())
@@ -815,14 +815,14 @@ void Score::setLastPalette(uint16 frameId) {
// Switch to a new palette immediately if:
// - this is color cycling mode, or
// - the cached palette ID is different (i.e. we jumped in the score)
- if (_frame->_palette.colorCycling || isCachedPalette)
+ if (_currentFrame->_palette.colorCycling || isCachedPalette)
g_director->setPalette(g_director->_lastPalette);
}
}
bool Score::isPaletteColorCycling() {
- return _frame->_palette.colorCycling;
+ return _currentFrame->_palette.colorCycling;
}
void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
@@ -831,7 +831,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// If the palette is defined in the frame and doesn't match
// the current one, set it
- CastMemberID currentPalette = _frame->_palette.paletteId;
+ CastMemberID currentPalette = _currentFrame->_palette.paletteId;
if (currentPalette.isNull())
return;
@@ -844,7 +844,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// offset will remain.
// Cycle speed in FPS
- int speed = _frame->_palette.speed;
+ int speed = _currentFrame->_palette.speed;
if (speed == 0)
return;
@@ -853,12 +853,12 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// 30 (the maximum) is actually unbounded
int delay = speed == 30 ? 10 : 1000 / speed;
- if (_frame->_palette.colorCycling) {
+ if (_currentFrame->_palette.colorCycling) {
// Cycle the colors of a chosen palette
- int firstColor = _frame->_palette.firstColor;
- int lastColor = _frame->_palette.lastColor;
+ int firstColor = _currentFrame->_palette.firstColor;
+ int lastColor = _currentFrame->_palette.lastColor;
- if (_frame->_palette.overTime) {
+ if (_currentFrame->_palette.overTime) {
// Do a single color step in one frame transition
debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, by 1 frame", currentPalette.asString().c_str(), firstColor, lastColor);
g_director->shiftPalette(firstColor, lastColor, false);
@@ -872,8 +872,8 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// Do a full color cycle in one frame transition
int steps = lastColor - firstColor + 1;
- debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, over %d steps %d times", currentPalette.asString().c_str(), firstColor, lastColor, steps, _frame->_palette.cycleCount);
- for (int i = 0; i < _frame->_palette.cycleCount; i++) {
+ debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, over %d steps %d times", currentPalette.asString().c_str(), firstColor, lastColor, steps, _currentFrame->_palette.cycleCount);
+ for (int i = 0; i < _currentFrame->_palette.cycleCount; i++) {
for (int j = 0; j < steps; j++) {
uint32 startTime = g_system->getMillis();
g_director->shiftPalette(firstColor, lastColor, false);
@@ -891,7 +891,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
int diff = (int)delay - (int)(endTime - startTime);
g_director->delayMillis(MAX(0, diff));
}
- if (_frame->_palette.autoReverse) {
+ if (_currentFrame->_palette.autoReverse) {
for (int j = 0; j < steps; j++) {
uint32 startTime = g_system->getMillis();
g_director->shiftPalette(firstColor, lastColor, true);
@@ -919,10 +919,10 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
warning("Score::renderPaletteCycle(): no match for palette id %s", currentPalette.asString().c_str());
return;
}
- int frameCount = _frame->_palette.frameCount;
+ int frameCount = _currentFrame->_palette.frameCount;
byte calcPal[768];
- if (_frame->_palette.overTime) {
+ if (_currentFrame->_palette.overTime) {
// Transition over a series of frames
if (_paletteTransitionIndex == 0) {
// Copy the current palette into the snapshot buffer
@@ -931,7 +931,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
debugC(2, kDebugImages, "Score::renderPaletteCycle(): fading palette to %s over %d frames", currentPalette.asString().c_str(), frameCount);
}
- if (_frame->_palette.normal) {
+ if (_currentFrame->_palette.normal) {
// Fade the palette directly to the new palette
lerpPalette(
calcPal,
@@ -946,10 +946,10 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
int halfway = frameCount / 2;
byte *fadePal = nullptr;
- if (_frame->_palette.fadeToBlack) {
+ if (_currentFrame->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
fadePal = kBlackPalette;
- } else if (_frame->_palette.fadeToWhite) {
+ } else if (_currentFrame->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
fadePal = kWhitePalette;
} else {
@@ -988,24 +988,24 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
// Do a full cycle in one frame transition
// For normal mode, we've already faded the palette in renderPrePaletteCycle
- if (!_frame->_palette.normal) {
+ if (!_currentFrame->_palette.normal) {
byte *fadePal = nullptr;
- if (_frame->_palette.fadeToBlack) {
+ if (_currentFrame->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
fadePal = kBlackPalette;
- } else if (_frame->_palette.fadeToWhite) {
+ } else if (_currentFrame->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
fadePal = kWhitePalette;
} else {
// Shouldn't reach here
return;
}
- int frameRate = CLIP<int>(_frame->_palette.speed, 1, 30);
+ int frameRate = CLIP<int>(_currentFrame->_palette.speed, 1, 30);
if (debugChannelSet(-1, kDebugFast))
frameRate = 30;
- int frameDelay = 1000/60;
+ int frameDelay = 1000 / 60;
int fadeFrames = kFadeColorFrames[frameRate - 1];
if (_vm->getVersion() >= 500)
fadeFrames = kFadeColorFramesD5[frameRate - 1];
@@ -1291,7 +1291,7 @@ Sprite *Score::getSpriteById(uint16 id) {
}
Sprite *Score::getOriginalSpriteById(uint16 id) {
- Frame *frame = _frame;
+ Frame *frame = _currentFrame;
if (id < frame->_sprites.size())
return frame->_sprites[id];
warning("Score::getOriginalSpriteById(%d): out of bounds, >= %d", id, frame->_sprites.size());
@@ -1308,7 +1308,7 @@ Channel *Score::getChannelById(uint16 id) {
}
void Score::playSoundChannel(uint16 frameId, bool puppetOnly) {
- Frame *frame = _frame;
+ Frame *frame = _currentFrame;
debugC(5, kDebugSound, "playSoundChannel(): Sound1 %s Sound2 %s", frame->_sound1.asString().c_str(), frame->_sound2.asString().c_str());
DirectorSound *sound = _window->getSoundManager();
@@ -1368,10 +1368,10 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
if (_framesVersion > 13) {
_numChannelsDisplayed = stream.readUint16();
} else {
- if (_framesVersion <= 7) // Director5
+ if (_framesVersion <= 7) // Director5
_numChannelsDisplayed = 48;
else
- _numChannelsDisplayed = 120; // D6
+ _numChannelsDisplayed = 120; // D6
stream.readUint16(); // Skip
}
@@ -1446,7 +1446,7 @@ bool Score::loadFrame(int frameNum) {
currentFrameSkipped++;
}
- bool isRead = readOneFrame(true); // Now final read the frame, this is our target frame!
+ bool isRead = readOneFrame(true); // Now final read the frame, this is our target frame!
if (isRead) {
setSpriteCasts();
_curFrameNumber = frameNum;
@@ -1463,7 +1463,7 @@ bool Score::readOneFrame(bool saveOffset) {
if (!_framesStream->eos()) {
uint16 frameSize = _framesStream->readUint16();
- debugC(3, kDebugLoading, "++++++++++ score frame %d (frameSize %d) saveOffset %d", getTotalFrames(), frameSize, saveOffset);
+ debugC(3, kDebugLoading, "++++++++++ score frame %d (frameSize %d) saveOffset %d", getFramesNum(), frameSize, saveOffset);
if (debugChannelSet(8, kDebugLoading)) {
_framesStream->hexdump(frameSize);
}
@@ -1510,12 +1510,12 @@ bool Score::readOneFrame(bool saveOffset) {
debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, frame->_actionId.asString().c_str());
- if (_frame != nullptr) {
+ if (_currentFrame != nullptr) {
// Delete previous frame before assigning new one!
- delete _frame;
- _frame = nullptr;
+ delete _currentFrame;
+ _currentFrame = nullptr;
}
- _frame = frame;
+ _currentFrame = frame;
if (saveOffset) {
// Record the starting offset for next frame!
@@ -1538,8 +1538,8 @@ Frame *Score::getFrameData(int frameNum){
// Backup variables
int curFrameNumber = _curFrameNumber;
- Frame *frame = _frame;
- _frame = nullptr; // To avoid later deletion of frame inside renderOneFrame()
+ Frame *frame = _currentFrame;
+ _currentFrame = nullptr; // To avoid later deletion of frame inside renderOneFrame()
byte channelData[kChannelDataSize];
memcpy(channelData, _channelData, kChannelDataSize);
@@ -1547,23 +1547,23 @@ Frame *Score::getFrameData(int frameNum){
// Start restoring all states
_curFrameNumber = curFrameNumber;
- _frame = frame;
+ _currentFrame = frame;
memcpy(_channelData, channelData, kChannelDataSize);
if (isFrameRead) {
- return _frame;
+ return _currentFrame;
}
return nullptr;
}
void Score::setSpriteCasts() {
// Update sprite cache of cast pointers/info
- for (uint16 j = 0; j < _frame->_sprites.size(); j++) {
- _frame->_sprites[j]->setCast(_frame->_sprites[j]->_castId);
+ for (uint16 j = 0; j < _currentFrame->_sprites.size(); j++) {
+ _currentFrame->_sprites[j]->setCast(_currentFrame->_sprites[j]->_castId);
debugC(5, kDebugImages, "Score::setSpriteCasts(): Frame: 0 Channel: %d castId: %s type: %d (%s)",
- j, _frame->_sprites[j]->_castId.asString().c_str(), _frame->_sprites[j]->_spriteType,
- spriteType2str(_frame->_sprites[j]->_spriteType));
+ j, _currentFrame->_sprites[j]->_castId.asString().c_str(), _currentFrame->_sprites[j]->_spriteType,
+ spriteType2str(_currentFrame->_sprites[j]->_spriteType));
}
}
@@ -1592,7 +1592,7 @@ void Score::loadLabels(Common::SeekableReadStreamEndian &stream) {
uint32 j = stringPos;
// handle label
- while(j < nextStringPos) {
+ while (j < nextStringPos) {
j++;
ch = stream.readByte();
if (ch == '\r')
@@ -1600,7 +1600,7 @@ void Score::loadLabels(Common::SeekableReadStreamEndian &stream) {
label += ch;
}
// handle label comments
- while(j < nextStringPos) {
+ while (j < nextStringPos) {
j++;
ch = stream.readByte();
if (ch == '\r')
@@ -1664,7 +1664,7 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
bool *scriptRefs = (bool *)calloc(_actions.size() + 1, sizeof(bool));
// Now let's scan which scripts are actually referenced
- for (uint i = 0; i < getTotalFrames(); i++) {
+ for (uint i = 0; i < getFramesNum(); i++) {
Frame *frame_i = getFrameData(i);
if ((uint)frame_i->_actionId.member <= _actions.size())
scriptRefs[frame_i->_actionId.member] = true;
@@ -1708,7 +1708,7 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
}
Common::String Score::formatChannelInfo() {
- Frame &frame = *_frame;
+ Frame &frame = *_currentFrame;
Common::String result;
CastMemberID defaultPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
result += Common::String::format("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d, currentFPS: %d\n",
diff --git a/engines/director/score.h b/engines/director/score.h
index ea4f5bb4554..9e5871ff15a 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -96,9 +96,9 @@ public:
void stopPlay();
void setCurrentFrame(uint16 frameId) { _nextFrame = frameId; }
- uint16 getCurrentFrame() { return _curFrameNumber; }
+ uint16 getCurrentFrameNum() { return _curFrameNumber; }
int getNextFrame() { return _nextFrame; }
- int getTotalFrames() { return _numFrames; }
+ uint16 getFramesNum() { return _numFrames; }
CastMemberID getCurrentPalette();
@@ -152,7 +152,7 @@ public:
// On demand frames loading
uint32 _version;
- Frame *_frame;
+ Frame *_currentFrame;
uint32 _curFrameNumber;
uint32 _numFrames;
uint32 _framesVersion;
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 612bcc4bbba..846e04392c5 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -115,7 +115,7 @@ void Window::invertChannel(Channel *channel, const Common::Rect &destRect) {
void Window::drawFrameCounter(Graphics::ManagedSurface *blitTo) {
const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont);
- Common::String msg = Common::String::format("Frame: %d", g_director->getCurrentMovie()->getScore()->getCurrentFrame());
+ Common::String msg = Common::String::format("Frame: %d", g_director->getCurrentMovie()->getScore()->getCurrentFrameNum());
uint32 width = font->getStringWidth(msg);
blitTo->fillRect(Common::Rect(blitTo->w - 3 - width, 1, blitTo->w - 1, font->getFontHeight() + 1), _wm->_colorBlack);
Commit: 2cac64a0693e5289ff77c98d3ab3576761705034
https://github.com/scummvm/scummvm/commit/2cac64a0693e5289ff77c98d3ab3576761705034
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Debugger use frame demand loading to view channels
Changed paths:
engines/director/debugger.cpp
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index f08e9a4f7ae..51afd87065a 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -289,7 +289,9 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
if (frameId >= 1 && frameId <= maxSize) {
debugPrintf("Channel info for frame %d of %d\n", frameId, maxSize);
- debugPrintf("%s\n", score->getFrameData(frameId-1)->formatChannelInfo().c_str());
+ Frame *frame = score->getFrameData(frameId-1);
+ debugPrintf("%s\n", frame->formatChannelInfo().c_str());
+ delete frame;
} else {
debugPrintf("Must specify a frame number between 1 and %d.\n", maxSize);
}
Commit: 5ec6a62fe8a7a10e9a0d94bc36ea59fddd5c9dfc
https://github.com/scummvm/scummvm/commit/5ec6a62fe8a7a10e9a0d94bc36ea59fddd5c9dfc
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Change _frameStream to read and wrap stream data
Changed paths:
engines/director/movie.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 2c910bd639d..6c0b528dc33 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -240,7 +240,7 @@ bool Movie::loadArchive() {
}
_score->loadFrames(*r, _version);
- // delete r;
+ delete r;
// Action list
if ((r = _movieArchive->getMovieResourceIfPresent(MKTAG('V', 'W', 'A', 'C'))) != nullptr) {
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 5a26c00cbe9..62f75459bce 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1395,31 +1395,47 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_currentPaletteId = CastMemberID(0, 0);
// Setup our streams for further frames processing!
- _framesStream = &stream;
+ int dataSize = size;
+ byte *data = (byte *)malloc(dataSize);
+ stream.read(data, dataSize);
+ _framesStream = new Common::MemoryReadStreamEndian(data, dataSize, stream.isBE(), DisposeAfterUse::YES);
_version = version;
- _frameOffsets.push_back(stream.pos());
+ _frameOffsets.push_back(_framesStream->pos());
// In case number of frames not known, precompute them!
if (_numFrames == 0) {
+ debugC(1, kDebugLoading, "Score::loadFrames(): Precomputing total number of frames!");
// Calculate number of frames beforehand.
int frameCount = 1;
while (loadFrame(frameCount)) {
frameCount++;
}
_numFrames = frameCount;
+
+ memset(_channelData, 0, kChannelDataSize); // Reset channel data
}
loadFrame(1);
+
+ // Read over frame offset array and print each item
+ for (uint i = 0; i < _frameOffsets.size(); i++) {
+ debugC(1, kDebugLoading, "Score::loadFrames(): Frame %d, offset %ld", i, _frameOffsets[i]);
+ }
+
+ debugC(1, kDebugLoading, "Score::loadFrames(): Number of frames: %d", _numFrames);
}
bool Score::loadFrame(int frameNum) {
// Read existing frame (ie already visited)
- if (frameNum < (int)_frameOffsets.size()) {
+ if (frameNum < (int)_frameOffsets.size() - 1) {
// TODO: How _channelData be modified.
// We have this frame already, seek and load
_framesStream->seek(_frameOffsets[frameNum]);
+ debugC(7, kDebugLoading, "****** Frame request %d, offset %ld", frameNum, _framesStream->pos());
+
if (readOneFrame()) {
+ loadCurrentFrameAction(); // Load actions of current frame!
setSpriteCasts(); // Set sprite casts for each sprite in frame!
_curFrameNumber = frameNum;
return true;
@@ -1432,22 +1448,25 @@ bool Score::loadFrame(int frameNum) {
// Seek to latest frame
_framesStream->seek(_frameOffsets[_frameOffsets.size() - 1]);
- debugC(7, kDebugLoading, "****** Frame request %d, offset %ld", frameNum, _framesStream->pos());
+ debugC(7, kDebugLoading, "****** Frame request %d, last recorded frame offset %ld", frameNum, _framesStream->pos());
int currentFrameSkipped = frameNum;
// Else read until that specific frame
- while (_frameOffsets.size() < (uint)frameNum) {
+ while (_frameOffsets.size() <= (uint)frameNum) {
+ debugC(7, kDebugLoading, "****** Skipping over a frame %d, offset %ld", _frameOffsets.size() - 1, _framesStream->pos());
+
if (!readOneFrame(true)) {
warning("Score::loadFrame(): Problem reading frame %d, is it outside maximum frames?", frameNum);
return false;
}
-
- debugC(7, kDebugLoading, "****** Skipping over a frame %d, offset %ld", currentFrameSkipped, _framesStream->pos());
currentFrameSkipped++;
}
+ debugC(7, kDebugLoading, "****** Frame loading %d, offset %ld", frameNum, _framesStream->pos());
+
bool isRead = readOneFrame(true); // Now final read the frame, this is our target frame!
if (isRead) {
+ loadCurrentFrameAction();
setSpriteCasts();
_curFrameNumber = frameNum;
} else {
@@ -1457,13 +1476,44 @@ bool Score::loadFrame(int frameNum) {
return isRead;
}
+// TODO: Not used right now, for future if there are issues with backwards jumping
+// Why? Because director works on concept of "delta" changes between frame, to save
+// space each frame only contains changes from previous frame, so we need to rebuild
+// whole channel data if we were to make a very big jump. This is essential because
+// without it we might have leftover casts/properties which will interfere with channel
+// data after the jump!
+void Score::rebuildChannelData(int frameNum) {
+ // Builds channel data from frame 1 to frame.
+ if (frameNum > (int)_numFrames) {
+ warning("Score::rebuildChannelData(): frameNum %d is greater than total frames %d", frameNum, _numFrames);
+ return;
+ }
+
+ memset(_channelData, 0, kChannelDataSize);
+
+ // Lock variables
+ int curFrameNumber = _curFrameNumber;
+ Frame *frame = _currentFrame;
+ _currentFrame = nullptr; // To avoid later deletion of frame inside renderOneFrame()
+
+ _framesStream->seek(_frameOffsets[1]); // Seek to frame 1
+ for (int i = 1; i < frameNum; i++) {
+ readOneFrame(false);
+ }
+
+ // Unlock variables
+ delete _currentFrame; // Destroy the built frame
+ _curFrameNumber = curFrameNumber;
+ _currentFrame = frame;
+}
+
bool Score::readOneFrame(bool saveOffset) {
uint16 channelSize;
uint16 channelOffset;
if (!_framesStream->eos()) {
uint16 frameSize = _framesStream->readUint16();
- debugC(3, kDebugLoading, "++++++++++ score frame %d (frameSize %d) saveOffset %d", getFramesNum(), frameSize, saveOffset);
+ debugC(3, kDebugLoading, "++++++++++ score prev frame %d (frameSize %d) saveOffset %d", _curFrameNumber, frameSize, saveOffset);
if (debugChannelSet(8, kDebugLoading)) {
_framesStream->hexdump(frameSize);
}
@@ -1661,25 +1711,24 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
break;
}
- bool *scriptRefs = (bool *)calloc(_actions.size() + 1, sizeof(bool));
-
- // Now let's scan which scripts are actually referenced
- for (uint i = 0; i < getFramesNum(); i++) {
- Frame *frame_i = getFrameData(i);
- if ((uint)frame_i->_actionId.member <= _actions.size())
- scriptRefs[frame_i->_actionId.member] = true;
-
- for (uint16 j = 0; j <= frame_i->_numChannels; j++) {
- if ((uint)frame_i->_sprites[j]->_scriptId.member <= _actions.size())
- scriptRefs[frame_i->_sprites[j]->_scriptId.member] = true;
- }
- }
-
if (ConfMan.getBool("dump_scripts"))
for (auto &j : _actions) {
if (!j._value.empty())
_movie->getCast()->dumpScript(j._value.c_str(), kScoreScript, j._key);
}
+}
+
+void Score::loadCurrentFrameAction() {
+ bool *scriptRefs = (bool *)calloc(_actions.size() + 1, sizeof(bool));
+
+ // Now let's scan which scripts are actually referenced
+ if ((uint)_currentFrame->_actionId.member <= _actions.size())
+ scriptRefs[_currentFrame->_actionId.member] = true;
+
+ for (uint16 j = 0; j <= _currentFrame->_numChannels; j++) {
+ if ((uint)_currentFrame->_sprites[j]->_scriptId.member <= _actions.size())
+ scriptRefs[_currentFrame->_sprites[j]->_scriptId.member] = true;
+ }
for (auto &j : _actions) {
if (!scriptRefs[j._key]) {
diff --git a/engines/director/score.h b/engines/director/score.h
index 9e5871ff15a..526a2cc0e6a 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -37,6 +37,7 @@ namespace Graphics {
namespace Common {
class ReadStreamEndian;
+ class MemoryReadStreamEndian;
class SeekableReadStreamEndian;
}
@@ -78,9 +79,11 @@ public:
bool loadFrame(int frame);
bool readOneFrame(bool saveOffset = false);
Frame *getFrameData(int frameNum);
+ void rebuildChannelData(int frameNum);
void loadLabels(Common::SeekableReadStreamEndian &stream);
void loadActions(Common::SeekableReadStreamEndian &stream);
+ void loadCurrentFrameAction();
void loadSampleSounds(uint type);
static int compareLabels(const void *a, const void *b);
@@ -163,7 +166,7 @@ public:
Common::Array<int64> _frameOffsets;
uint _framesStreamSize;
- Common::SeekableReadStreamEndian *_framesStream;
+ Common::MemoryReadStreamEndian *_framesStream;
byte _currentFrameRate;
Commit: b29f01dc20e9eed9db3aef08ec86076b9f8bad93
https://github.com/scummvm/scummvm/commit/b29f01dc20e9eed9db3aef08ec86076b9f8bad93
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Added corner condition while on demand reading of frames.
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 62f75459bce..606109e62f1 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1427,6 +1427,8 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
}
bool Score::loadFrame(int frameNum) {
+ debugC(7, kDebugLoading, "****** A call to loadFrame %d", frameNum);
+
// Read existing frame (ie already visited)
if (frameNum < (int)_frameOffsets.size() - 1) {
// TODO: How _channelData be modified.
@@ -1513,11 +1515,15 @@ bool Score::readOneFrame(bool saveOffset) {
if (!_framesStream->eos()) {
uint16 frameSize = _framesStream->readUint16();
+ if (frameSize > _framesStream->size()) {
+ warning("Score::readOneFrame(): frameSize %d is greater than stream size %ld", frameSize, _framesStream->size());
+ return false;
+ }
+
debugC(3, kDebugLoading, "++++++++++ score prev frame %d (frameSize %d) saveOffset %d", _curFrameNumber, frameSize, saveOffset);
if (debugChannelSet(8, kDebugLoading)) {
_framesStream->hexdump(frameSize);
}
-
if (frameSize > 0) {
Frame *frame = new Frame(this, _numChannelsDisplayed);
frameSize -= 2;
Commit: 6cdd4a92db6bb3c3675252833d8f0b2eefa8e24f
https://github.com/scummvm/scummvm/commit/6cdd4a92db6bb3c3675252833d8f0b2eefa8e24f
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Load all of VWSC resource in framesStream
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 606109e62f1..19b7ceec36e 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1348,32 +1348,39 @@ void Score::playQueuedSound() {
void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version) {
debugC(1, kDebugLoading, "****** Loading frames VWSC");
+ // Setup our streams for frames processing!
+ int dataSize = stream.size();
+ byte *data = (byte *)malloc(dataSize);
+ stream.read(data, dataSize);
+
+ _framesStream = new Common::MemoryReadStreamEndian(data, dataSize, stream.isBE(), DisposeAfterUse::YES);
+
if (debugChannelSet(8, kDebugLoading)) {
- stream.hexdump(stream.size());
+ _framesStream->hexdump(_framesStream->size());
}
- uint32 size = stream.readUint32();
+ uint32 size = _framesStream->readUint32();
size -= 4;
if (version < kFileVer400) {
_numChannelsDisplayed = 30;
} else if (version >= kFileVer400 && version < kFileVer600) {
- uint32 frame1Offset = stream.readUint32();
- _numFrames = stream.readUint32();
- _framesVersion = stream.readUint16();
- uint16 spriteRecordSize = stream.readUint16();
- _numChannels = stream.readUint16();
+ uint32 frame1Offset = _framesStream->readUint32();
+ _numFrames = _framesStream->readUint32();
+ _framesVersion = _framesStream->readUint16();
+ uint16 spriteRecordSize = _framesStream->readUint16();
+ _numChannels = _framesStream->readUint16();
size -= 14;
if (_framesVersion > 13) {
- _numChannelsDisplayed = stream.readUint16();
+ _numChannelsDisplayed = _framesStream->readUint16();
} else {
if (_framesVersion <= 7) // Director5
_numChannelsDisplayed = 48;
else
_numChannelsDisplayed = 120; // D6
- stream.readUint16(); // Skip
+ _framesStream->readUint16(); // Skip
}
size -= 2;
@@ -1394,13 +1401,8 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_currentTempo = 0;
_currentPaletteId = CastMemberID(0, 0);
- // Setup our streams for further frames processing!
- int dataSize = size;
- byte *data = (byte *)malloc(dataSize);
- stream.read(data, dataSize);
- _framesStream = new Common::MemoryReadStreamEndian(data, dataSize, stream.isBE(), DisposeAfterUse::YES);
+ // Prepare frameOffsets
_version = version;
-
_frameOffsets.push_back(_framesStream->pos());
// In case number of frames not known, precompute them!
Commit: 64a214fa866e46ac22b8267b2fa89fb4b9b1d1fc
https://github.com/scummvm/scummvm/commit/64a214fa866e46ac22b8267b2fa89fb4b9b1d1fc
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Fix framesSize exceeded for demand loaded frames
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 19b7ceec36e..da550dc5fba 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1359,8 +1359,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_framesStream->hexdump(_framesStream->size());
}
- uint32 size = _framesStream->readUint32();
- size -= 4;
+ _framesStreamSize = _framesStream->readUint32();
if (version < kFileVer400) {
_numChannelsDisplayed = 30;
@@ -1370,7 +1369,6 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_framesVersion = _framesStream->readUint16();
uint16 spriteRecordSize = _framesStream->readUint16();
_numChannels = _framesStream->readUint16();
- size -= 14;
if (_framesVersion > 13) {
_numChannelsDisplayed = _framesStream->readUint16();
@@ -1383,8 +1381,6 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_framesStream->readUint16(); // Skip
}
- size -= 2;
-
warning("STUB: Score::loadFrames. frame1Offset: %x numFrames: %x version: %x spriteRecordSize: %x numChannels: %x numChannelsDisplayed: %x",
frame1Offset, _numFrames, _framesVersion, spriteRecordSize, _numChannels, _numChannelsDisplayed);
// Unknown, some bytes - constant (refer to contuinity).
@@ -1411,9 +1407,11 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Calculate number of frames beforehand.
int frameCount = 1;
while (loadFrame(frameCount)) {
+ debugC(1, kDebugLoading, "Score::loadFrames(): Skipped over frame %d!", frameCount);
frameCount++;
}
_numFrames = frameCount;
+ debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
memset(_channelData, 0, kChannelDataSize); // Reset channel data
}
@@ -1425,7 +1423,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
debugC(1, kDebugLoading, "Score::loadFrames(): Frame %d, offset %ld", i, _frameOffsets[i]);
}
- debugC(1, kDebugLoading, "Score::loadFrames(): Number of frames: %d", _numFrames);
+ debugC(1, kDebugLoading, "Score::loadFrames(): Number of frames: %d, framesStreamSize: %d", _numFrames, _framesStreamSize);
}
bool Score::loadFrame(int frameNum) {
@@ -1515,14 +1513,11 @@ bool Score::readOneFrame(bool saveOffset) {
uint16 channelSize;
uint16 channelOffset;
- if (!_framesStream->eos()) {
+ if (_framesStream->pos() < _framesStreamSize && !_framesStream->eos()) {
uint16 frameSize = _framesStream->readUint16();
- if (frameSize > _framesStream->size()) {
- warning("Score::readOneFrame(): frameSize %d is greater than stream size %ld", frameSize, _framesStream->size());
- return false;
- }
+ assert(frameSize < _framesStreamSize);
- debugC(3, kDebugLoading, "++++++++++ score prev frame %d (frameSize %d) saveOffset %d", _curFrameNumber, frameSize, saveOffset);
+ debugC(3, kDebugLoading, "++++++++++ score load frame (frameSize %d) saveOffset %d", frameSize, saveOffset);
if (debugChannelSet(8, kDebugLoading)) {
_framesStream->hexdump(frameSize);
}
@@ -1542,11 +1537,7 @@ bool Score::readOneFrame(bool saveOffset) {
frameSize -= channelSize + 4;
}
- if (channelOffset + channelSize >= kChannelDataSize) {
- delete frame;
- // Data ended, no more frames, return
- return false;
- }
+ assert(channelOffset + channelSize < kChannelDataSize);
_framesStream->read(&_channelData[channelOffset], channelSize);
}
@@ -1575,7 +1566,7 @@ bool Score::readOneFrame(bool saveOffset) {
}
_currentFrame = frame;
- if (saveOffset) {
+ if (saveOffset && _framesStream->pos() < _framesStreamSize) {
// Record the starting offset for next frame!
_frameOffsets.push_back(_framesStream->pos());
}
Commit: f3928ec4cf4799aead8ffeea67510e713ca42584
https://github.com/scummvm/scummvm/commit/f3928ec4cf4799aead8ffeea67510e713ca42584
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Rebuild channel data when frame jumping, fix screen freeze bugs.
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index da550dc5fba..a47b57d0eb8 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -86,6 +86,7 @@ Score::Score(Movie *movie) {
_numChannelsDisplayed = 0;
_skipTransition = false;
+ _curFrameNumber = -1;
_framesStream = nullptr;
_currentFrame = nullptr;
}
@@ -390,8 +391,13 @@ void Score::update() {
}
if (!_vm->_playbackPaused) {
- if (_nextFrame)
+ if (_nextFrame) {
+ // With the advent of demand loading frames and due to partial updates, we rebuild our channel data
+ // when jumping.
+ if (_nextFrame != _curFrameNumber)
+ rebuildChannelData(_nextFrame);
_curFrameNumber = _nextFrame;
+ }
else if (!_window->_newMovieStarted)
_curFrameNumber++;
}
@@ -1432,6 +1438,7 @@ bool Score::loadFrame(int frameNum) {
// Read existing frame (ie already visited)
if (frameNum < (int)_frameOffsets.size() - 1) {
// TODO: How _channelData be modified.
+ // As of now channelData is left unchanged, only rebuilt when there is jumps
// We have this frame already, seek and load
_framesStream->seek(_frameOffsets[frameNum]);
debugC(7, kDebugLoading, "****** Frame request %d, offset %ld", frameNum, _framesStream->pos());
Commit: af82ea2769d6256a3000aec2a2a3ed944acee2d8
https://github.com/scummvm/scummvm/commit/af82ea2769d6256a3000aec2a2a3ed944acee2d8
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Fix frame number mismatch with total frames in score
Total number of frames were being read from VWSC resource
(version > kFileVer400), however it has been found that for some movies
there is mismatch between version and total frames. Therefore now changed
the code to load all frames initially to read total number of frames.
`ATD\HD\ABPOPUP1.DXR` of `totaldistortion` is one such example.
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index a47b57d0eb8..86834cfb180 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -407,6 +407,7 @@ void Score::update() {
if (_curFrameNumber >= getFramesNum()) {
Window *window = _vm->getCurrentWindow();
if (!window->_movieStack.empty()) {
+ warning("Are we changing movie?");
MovieReference ref = window->_movieStack.back();
window->_movieStack.pop_back();
if (!ref.movie.empty()) {
@@ -417,6 +418,7 @@ void Score::update() {
return;
}
+ rebuildChannelData(ref.frameI);
_curFrameNumber = ref.frameI;
} else {
if (debugChannelSet(-1, kDebugNoLoop)) {
@@ -1407,20 +1409,18 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_version = version;
_frameOffsets.push_back(_framesStream->pos());
- // In case number of frames not known, precompute them!
- if (_numFrames == 0) {
- debugC(1, kDebugLoading, "Score::loadFrames(): Precomputing total number of frames!");
- // Calculate number of frames beforehand.
- int frameCount = 1;
- while (loadFrame(frameCount)) {
- debugC(1, kDebugLoading, "Score::loadFrames(): Skipped over frame %d!", frameCount);
- frameCount++;
- }
- _numFrames = frameCount;
- debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
-
- memset(_channelData, 0, kChannelDataSize); // Reset channel data
+ // Pre-computing number of frames, as sometimes the frameNumber in stream mismatches.
+ debugC(1, kDebugLoading, "Score::loadFrames(): Precomputing total number of frames!");
+ // Calculate number of frames beforehand.
+ int frameCount = 1;
+ while (loadFrame(frameCount)) {
+ debugC(1, kDebugLoading, "Score::loadFrames(): Skipped over frame %d!", frameCount);
+ frameCount++;
}
+ _numFrames = frameCount;
+ debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
+
+ memset(_channelData, 0, kChannelDataSize); // Reset channel data
loadFrame(1);
Commit: 8b259c8627607e190edefa962de15c3dad66de5f
https://github.com/scummvm/scummvm/commit/8b259c8627607e190edefa962de15c3dad66de5f
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Minor changes, comments and some more corrections
Changed paths:
engines/director/lingo/lingo-builtins.cpp
engines/director/lingo/lingo-the.cpp
engines/director/score.cpp
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 1d09f6a1c82..ea1dc82ff5a 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2566,10 +2566,11 @@ void LB::b_immediateSprite(int nargs) {
if ((uint)sprite.asInt() < sc->_channels.size()) {
if (sc->getNextFrame() && !sp->_immediate) {
// same as puppetSprite
- Channel *channel = sc->getChannelById(sprite.asInt());
- // TODO: Fix logic here for next sprite
- channel->replaceSprite(sc->_currentFrame->_sprites[sprite.asInt()]);
- channel->_dirty = true;
+ // Channel *channel = sc->getChannelById(sprite.asInt());
+ // channel->replaceSprite(sc->_frames[sc->getNextFrame()]->_sprites[sprite.asInt()]);
+ // channel->_dirty = true;
+
+ warning("STUB: LB::b_immediateSprite(): Fix logic here for next sprite");
}
sc->getSpriteById(sprite.asInt())->_immediate = (bool)state.asInt();
@@ -2607,11 +2608,11 @@ void LB::b_puppetSprite(int nargs) {
if (sc->getNextFrame() && !sp->_puppet) {
// WORKAROUND: If a frame update is queued, update the sprite to the
// sprite in new frame before setting puppet (Majestic).
- Channel *channel = sc->getChannelById(sprite.asInt());
+ // Channel *channel = sc->getChannelById(sprite.asInt());
+ // channel->replaceSprite(sc->_frames[sc->getNextFrame()]->_sprites[sprite.asInt()]);
+ // channel->_dirty = true;
- // TODO: Fix this properly.
- channel->replaceSprite(sc->_currentFrame->_sprites[sprite.asInt()]);
- channel->_dirty = true;
+ warning("STUB: LB::b_puppetSprite(): Fix logic here for next sprite");
}
sc->getSpriteById(sprite.asInt())->_puppet = (bool)state.asInt();
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 6a1806b071f..5c0bd955e9c 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -523,7 +523,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
d = (int)(_vm->getMacTicks() - movie->_lastEventTime);
break;
case kTheLastFrame:
- d = (int)score->getFramesNum() - 1;
+ d = (int)score->getFramesNum();
break;
case kTheLastKey:
d = (int)(_vm->getMacTicks() - movie->_lastKeyTime);
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 86834cfb180..524efd3b27c 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -101,9 +101,8 @@ Score::~Score() {
delete _labels;
- if (_framesStream) {
+ if (_framesStream)
delete _framesStream;
- }
if (_currentFrame) {
delete _currentFrame;
Commit: 8112a3b89c4b262fe0ec7708782e5b86ed16cdef
https://github.com/scummvm/scummvm/commit/8112a3b89c4b262fe0ec7708782e5b86ed16cdef
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Remove redundant null check from frames
Changed paths:
engines/director/lingo/lingo-builtins.cpp
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index ea1dc82ff5a..ecb9838e800 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2393,7 +2393,6 @@ void LB::b_pasteClipBoardInto(int nargs) {
}
Score *score = movie->getScore();
- uint16 frame = score->getCurrentFrameNum();
Frame *currentFrame = score->_currentFrame;
auto channels = score->_channels;
@@ -2770,22 +2769,18 @@ void LB::b_zoomBox(int nargs) {
if (endRect.isEmpty()) {
if ((uint)curFrame + 1 < score->getFramesNum()) {
Frame *nextFrame = score->getFrameData(curFrame + 1);
- if (nextFrame) {
- Channel endChannel(nullptr, nextFrame->_sprites[endSpriteId]);
- endRect = endChannel.getBbox();
- delete nextFrame;
- }
+ Channel endChannel(nullptr, nextFrame->_sprites[endSpriteId]);
+ endRect = endChannel.getBbox();
+ delete nextFrame;
}
}
if (endRect.isEmpty()) {
if ((uint)curFrame - 1 > 0) {
Frame *prevFrame = score->getFrameData(curFrame - 1);
- if (prevFrame) {
- Channel endChannel(nullptr, prevFrame->_sprites[endSpriteId]);
- endRect = endChannel.getBbox();
- delete prevFrame;
- }
+ Channel endChannel(nullptr, prevFrame->_sprites[endSpriteId]);
+ endRect = endChannel.getBbox();
+ delete prevFrame;
}
}
Commit: 5c3f4b837ba59f4fba5b04d17191d3b22ae9dc51
https://github.com/scummvm/scummvm/commit/5c3f4b837ba59f4fba5b04d17191d3b22ae9dc51
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Refactored score class, changed comments
Changed paths:
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 524efd3b27c..bd4ba2142f4 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -86,7 +86,7 @@ Score::Score(Movie *movie) {
_numChannelsDisplayed = 0;
_skipTransition = false;
- _curFrameNumber = -1;
+ _curFrameNumber = 0;
_framesStream = nullptr;
_currentFrame = nullptr;
}
@@ -1298,10 +1298,9 @@ Sprite *Score::getSpriteById(uint16 id) {
}
Sprite *Score::getOriginalSpriteById(uint16 id) {
- Frame *frame = _currentFrame;
- if (id < frame->_sprites.size())
- return frame->_sprites[id];
- warning("Score::getOriginalSpriteById(%d): out of bounds, >= %d", id, frame->_sprites.size());
+ if (id < _currentFrame->_sprites.size())
+ return _currentFrame->_sprites[id];
+ warning("Score::getOriginalSpriteById(%d): out of bounds, >= %d", id, _currentFrame->_sprites.size());
return nullptr;
}
@@ -1315,28 +1314,26 @@ Channel *Score::getChannelById(uint16 id) {
}
void Score::playSoundChannel(uint16 frameId, bool puppetOnly) {
- Frame *frame = _currentFrame;
-
- debugC(5, kDebugSound, "playSoundChannel(): Sound1 %s Sound2 %s", frame->_sound1.asString().c_str(), frame->_sound2.asString().c_str());
+ debugC(5, kDebugSound, "playSoundChannel(): Sound1 %s Sound2 %s", _currentFrame->_sound1.asString().c_str(), _currentFrame->_sound2.asString().c_str());
DirectorSound *sound = _window->getSoundManager();
if (sound->isChannelPuppet(1)) {
sound->playPuppetSound(1);
} else if (!puppetOnly) {
- if (frame->_soundType1 >= kMinSampledMenu && frame->_soundType1 <= kMaxSampledMenu) {
- sound->playExternalSound(frame->_soundType1, frame->_sound1.member, 1);
+ if (_currentFrame->_soundType1 >= kMinSampledMenu && _currentFrame->_soundType1 <= kMaxSampledMenu) {
+ sound->playExternalSound(_currentFrame->_soundType1, _currentFrame->_sound1.member, 1);
} else {
- sound->playCastMember(frame->_sound1, 1);
+ sound->playCastMember(_currentFrame->_sound1, 1);
}
}
if (sound->isChannelPuppet(2)) {
sound->playPuppetSound(2);
} else if (!puppetOnly) {
- if (frame->_soundType2 >= kMinSampledMenu && frame->_soundType2 <= kMaxSampledMenu) {
- sound->playExternalSound(frame->_soundType2, frame->_sound2.member, 2);
+ if (_currentFrame->_soundType2 >= kMinSampledMenu && _currentFrame->_soundType2 <= kMaxSampledMenu) {
+ sound->playExternalSound(_currentFrame->_soundType2, _currentFrame->_sound2.member, 2);
} else {
- sound->playCastMember(frame->_sound2, 2);
+ sound->playCastMember(_currentFrame->_sound2, 2);
}
}
@@ -1355,8 +1352,8 @@ void Score::playQueuedSound() {
void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version) {
debugC(1, kDebugLoading, "****** Loading frames VWSC");
- // Setup our streams for frames processing!
- int dataSize = stream.size();
+ // Setup our streams for frames processing
+ uint dataSize = stream.size();
byte *data = (byte *)malloc(dataSize);
stream.read(data, dataSize);
@@ -1372,7 +1369,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_numChannelsDisplayed = 30;
} else if (version >= kFileVer400 && version < kFileVer600) {
uint32 frame1Offset = _framesStream->readUint32();
- _numFrames = _framesStream->readUint32();
+ /* uint32 numOfFrames = */ _framesStream->readUint32();
_framesVersion = _framesStream->readUint16();
uint16 spriteRecordSize = _framesStream->readUint16();
_numChannels = _framesStream->readUint16();
@@ -1393,7 +1390,6 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Unknown, some bytes - constant (refer to contuinity).
}
- // TODO How to work with channelData that gets overridden
// partically by channels, hence we keep it and read the score from left to right
// TODO Merge it with shared cast
memset(_channelData, 0, kChannelDataSize);
@@ -1408,15 +1404,12 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_version = version;
_frameOffsets.push_back(_framesStream->pos());
- // Pre-computing number of frames, as sometimes the frameNumber in stream mismatches.
+ // Pre-computing number of frames, as sometimes the frameNumber in stream mismatches
debugC(1, kDebugLoading, "Score::loadFrames(): Precomputing total number of frames!");
- // Calculate number of frames beforehand.
- int frameCount = 1;
- while (loadFrame(frameCount)) {
- debugC(1, kDebugLoading, "Score::loadFrames(): Skipped over frame %d!", frameCount);
- frameCount++;
- }
- _numFrames = frameCount;
+
+ // Calculate number of frames beforehand
+ for (_numFrames = 1; loadFrame(_numFrames); _numFrames++) { }
+
debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
memset(_channelData, 0, kChannelDataSize); // Reset channel data
@@ -1425,73 +1418,50 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Read over frame offset array and print each item
for (uint i = 0; i < _frameOffsets.size(); i++) {
- debugC(1, kDebugLoading, "Score::loadFrames(): Frame %d, offset %ld", i, _frameOffsets[i]);
+ debugC(8, kDebugLoading, "Score::loadFrames(): Frame %d, offset %ld", i, _frameOffsets[i]);
}
debugC(1, kDebugLoading, "Score::loadFrames(): Number of frames: %d, framesStreamSize: %d", _numFrames, _framesStreamSize);
}
bool Score::loadFrame(int frameNum) {
- debugC(7, kDebugLoading, "****** A call to loadFrame %d", frameNum);
+ debugC(7, kDebugLoading, "****** Frame request %d, current pos: %ld", frameNum, _framesStream->pos());
// Read existing frame (ie already visited)
- if (frameNum < (int)_frameOffsets.size() - 1) {
- // TODO: How _channelData be modified.
- // As of now channelData is left unchanged, only rebuilt when there is jumps
- // We have this frame already, seek and load
+ if (frameNum < (int)_frameOffsets.size()) {
+ // Seek to existing frame in offsets
_framesStream->seek(_frameOffsets[frameNum]);
- debugC(7, kDebugLoading, "****** Frame request %d, offset %ld", frameNum, _framesStream->pos());
-
- if (readOneFrame()) {
- loadCurrentFrameAction(); // Load actions of current frame!
- setSpriteCasts(); // Set sprite casts for each sprite in frame!
- _curFrameNumber = frameNum;
- return true;
- } else {
- warning("Score::loadFrame(): Problem reading previous frame %d, current offset: %ld", frameNum, _framesStream->pos());
- return false;
- }
+ } else {
+ // Seek to latest frame
+ _framesStream->seek(_frameOffsets[_frameOffsets.size() - 1]);
+ _curFrameNumber = _frameOffsets.size() - 1;
}
- // Seek to latest frame
- _framesStream->seek(_frameOffsets[_frameOffsets.size() - 1]);
-
- debugC(7, kDebugLoading, "****** Frame request %d, last recorded frame offset %ld", frameNum, _framesStream->pos());
+ debugC(7, kDebugLoading, "****** Frame request %d, current offset %ld", frameNum, _framesStream->pos());
- int currentFrameSkipped = frameNum;
- // Else read until that specific frame
- while (_frameOffsets.size() <= (uint)frameNum) {
- debugC(7, kDebugLoading, "****** Skipping over a frame %d, offset %ld", _frameOffsets.size() - 1, _framesStream->pos());
+ while (_frameOffsets.size() <= (uint)frameNum && readOneFrame())
+ _curFrameNumber++;
- if (!readOneFrame(true)) {
- warning("Score::loadFrame(): Problem reading frame %d, is it outside maximum frames?", frameNum);
- return false;
- }
- currentFrameSkipped++;
- }
-
- debugC(7, kDebugLoading, "****** Frame loading %d, offset %ld", frameNum, _framesStream->pos());
+ // Finally read the target frame!
+ bool isFrameRead = readOneFrame();
+ if (!isFrameRead)
+ return false;
- bool isRead = readOneFrame(true); // Now final read the frame, this is our target frame!
- if (isRead) {
- loadCurrentFrameAction();
- setSpriteCasts();
- _curFrameNumber = frameNum;
- } else {
- warning("Score::loadFrame(): Problem reading frame %d, current offset: %ld", frameNum, _framesStream->pos());
- }
+ // Load frame action, cast
+ loadCurrentFrameAction();
+ setSpriteCasts();
- return isRead;
+ return true;
}
-// TODO: Not used right now, for future if there are issues with backwards jumping
+// Rebuild channel data from frame 1 to frameNum, to prepare for next frame loading
// Why? Because director works on concept of "delta" changes between frame, to save
// space each frame only contains changes from previous frame, so we need to rebuild
// whole channel data if we were to make a very big jump. This is essential because
// without it we might have leftover casts/properties which will interfere with channel
-// data after the jump!
+// data after the jump
void Score::rebuildChannelData(int frameNum) {
- // Builds channel data from frame 1 to frame.
+ // Builds channel data from frame 1 to frame
if (frameNum > (int)_numFrames) {
warning("Score::rebuildChannelData(): frameNum %d is greater than total frames %d", frameNum, _numFrames);
return;
@@ -1506,7 +1476,7 @@ void Score::rebuildChannelData(int frameNum) {
_framesStream->seek(_frameOffsets[1]); // Seek to frame 1
for (int i = 1; i < frameNum; i++) {
- readOneFrame(false);
+ readOneFrame();
}
// Unlock variables
@@ -1515,81 +1485,83 @@ void Score::rebuildChannelData(int frameNum) {
_currentFrame = frame;
}
-bool Score::readOneFrame(bool saveOffset) {
+bool Score::readOneFrame() {
uint16 channelSize;
uint16 channelOffset;
- if (_framesStream->pos() < _framesStreamSize && !_framesStream->eos()) {
- uint16 frameSize = _framesStream->readUint16();
- assert(frameSize < _framesStreamSize);
+ if (_framesStream->pos() >= _framesStreamSize || _framesStream->eos())
+ return false;
- debugC(3, kDebugLoading, "++++++++++ score load frame (frameSize %d) saveOffset %d", frameSize, saveOffset);
- if (debugChannelSet(8, kDebugLoading)) {
- _framesStream->hexdump(frameSize);
- }
- if (frameSize > 0) {
- Frame *frame = new Frame(this, _numChannelsDisplayed);
- frameSize -= 2;
+ uint16 frameSize = _framesStream->readUint16();
+ assert(frameSize < _framesStreamSize);
- while (frameSize != 0) {
+ debugC(3, kDebugLoading, "++++++++++ score load frame (frameSize %d) saveOffset", frameSize);
+ if (debugChannelSet(8, kDebugLoading)) {
+ _framesStream->hexdump(frameSize);
+ }
+ if (frameSize > 0) {
+ Frame *frame = new Frame(this, _numChannelsDisplayed);
+ frameSize -= 2;
- if (_vm->getVersion() < 400) {
- channelSize = _framesStream->readByte() * 2;
- channelOffset = _framesStream->readByte() * 2;
- frameSize -= channelSize + 2;
- } else {
- channelSize = _framesStream->readUint16();
- channelOffset = _framesStream->readUint16();
- frameSize -= channelSize + 4;
- }
+ while (frameSize != 0) {
- assert(channelOffset + channelSize < kChannelDataSize);
- _framesStream->read(&_channelData[channelOffset], channelSize);
+ if (_vm->getVersion() < 400) {
+ channelSize = _framesStream->readByte() * 2;
+ channelOffset = _framesStream->readByte() * 2;
+ frameSize -= channelSize + 2;
+ } else {
+ channelSize = _framesStream->readUint16();
+ channelOffset = _framesStream->readUint16();
+ frameSize -= channelSize + 4;
}
- Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(_channelData, ARRAYSIZE(_channelData), _framesStream->isBE());
- // str->hexdump(str->size(), 32);
- frame->readChannels(str, _version);
- delete str;
- // Precache the current FPS tempo, as this carries forward to frames to the right
- // of the instruction.
- // Delay type tempos (e.g. wait commands, delays) apply to only a single frame, and are ignored here.
- if (frame->_tempo && frame->_tempo <= 120)
- _currentTempo = frame->_tempo;
- frame->_scoreCachedTempo = frame->_tempo ? frame->_tempo : _currentTempo;
- // Precache the current palette ID, as this carries forward to frames to the right
- // of the instruction.
- if (!frame->_palette.paletteId.isNull())
- _currentPaletteId = frame->_palette.paletteId;
- frame->_scoreCachedPaletteId = _currentPaletteId;
-
- debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, frame->_actionId.asString().c_str());
-
- if (_currentFrame != nullptr) {
- // Delete previous frame before assigning new one!
- delete _currentFrame;
- _currentFrame = nullptr;
- }
- _currentFrame = frame;
+ assert(channelOffset + channelSize < kChannelDataSize);
+ _framesStream->read(&_channelData[channelOffset], channelSize);
+ }
- if (saveOffset && _framesStream->pos() < _framesStreamSize) {
- // Record the starting offset for next frame!
- _frameOffsets.push_back(_framesStream->pos());
- }
- return true;
- } else {
- warning("Score::readOneFrame(): Zero sized frame!? exiting loop until we know what to do with the tags that follow.");
+ Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(_channelData, ARRAYSIZE(_channelData), _framesStream->isBE());
+ // str->hexdump(str->size(), 32);
+ frame->readChannels(str, _version);
+ delete str;
+ // Precache the current FPS tempo, as this carries forward to frames to the right
+ // of the instruction
+ // Delay type tempos (e.g. wait commands, delays) apply to only a single frame, and are ignored here
+ if (frame->_tempo && frame->_tempo <= 120)
+ _currentTempo = frame->_tempo;
+ frame->_scoreCachedTempo = frame->_tempo ? frame->_tempo : _currentTempo;
+ // Precache the current palette ID, as this carries forward to frames to the right
+ // of the instruction
+ if (!frame->_palette.paletteId.isNull())
+ _currentPaletteId = frame->_palette.paletteId;
+ frame->_scoreCachedPaletteId = _currentPaletteId;
+
+ debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, frame->_actionId.asString().c_str());
+
+ if (_currentFrame != nullptr) {
+ // Delete previous frame before assigning new one
+ delete _currentFrame;
+ _currentFrame = nullptr;
}
+ _currentFrame = frame;
+
+ if (_curFrameNumber == _frameOffsets.size() - 1 && _framesStream->pos() < _framesStreamSize) {
+ // Record the starting offset for next frame
+ _frameOffsets.push_back(_framesStream->pos());
+ }
+ return true;
+ } else {
+ warning("Score::readOneFrame(): Zero sized frame!? exiting loop until we know what to do with the tags that follow.");
}
+
return false; // Error in loading frame
}
Frame *Score::getFrameData(int frameNum){
// This function is for previewing selected frame,
// It doesn't make any changes to current render state
- // In case of any problem, it returns nullptr.
- // Be sure to delete this frame after use!
+ // In case of any problem, it returns nullptr
+ // Be sure to delete this frame after use
// Backup variables
int curFrameNumber = _curFrameNumber;
diff --git a/engines/director/score.h b/engines/director/score.h
index 526a2cc0e6a..bdcbd68ad3d 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -77,7 +77,7 @@ public:
void loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version);
bool loadFrame(int frame);
- bool readOneFrame(bool saveOffset = false);
+ bool readOneFrame();
Frame *getFrameData(int frameNum);
void rebuildChannelData(int frameNum);
Commit: aeac3e2d217e683447524eb092f44023ed8c919d
https://github.com/scummvm/scummvm/commit/aeac3e2d217e683447524eb092f44023ed8c919d
Author: Harishankar Kumar (hari01584 at gmail.com)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Refactor loadOneFrame() to remove clutter
Changed paths:
engines/director/score.h
diff --git a/engines/director/score.h b/engines/director/score.h
index bdcbd68ad3d..f03a92c3a20 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -78,6 +78,7 @@ public:
void loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version);
bool loadFrame(int frame);
bool readOneFrame();
+ void updateFrame(Frame *frame);
Frame *getFrameData(int frameNum);
void rebuildChannelData(int frameNum);
Commit: 4245cc26070c5cb41d1164e882f02211f14176ce
https://github.com/scummvm/scummvm/commit/4245cc26070c5cb41d1164e882f02211f14176ce
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Initial frame loading refactoring
D4 is working, rhe rest is broken
Changed paths:
engines/director/frame.cpp
engines/director/frame.h
engines/director/score.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 32a55ccf128..67c14884db4 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/memstream.h"
#include "common/substream.h"
#include "director/director.h"
@@ -108,27 +109,74 @@ Frame::~Frame() {
delete _sprites[i];
}
-void Frame::readChannel(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size) {
+void Frame::readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size, uint16 version) {
+ if (version < kFileVer400) {
+ readChannelD2(stream, offset, size);
+ } else if (version >= kFileVer400 && version < kFileVer500) {
+ readChannelD4(stream, offset, size);
+ } else if (version >= kFileVer500 && version < kFileVer600) {
+ readChannelD5(stream, offset, size);
+ } else if (version >= kFileVer600 && version < kFileVer700) {
+ readChannelD6(stream, offset, size);
+ } else {
+ error("Frame::readChannel(): Unsupported Director version: %d", version);
+ }
+}
+
+void Frame::readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
if (offset >= 32) {
if (size <= 16)
- readSprite(stream, offset, size);
+ readSpriteD2(stream, offset, size);
else {
// read > 1 sprites channel
while (size > 16) {
byte spritePosition = (offset - 32) / 16;
uint16 nextStart = (spritePosition + 1) * 16 + 32;
uint16 needSize = nextStart - offset;
- readSprite(stream, offset, needSize);
+ readSpriteD2(stream, offset, needSize);
offset += needSize;
size -= needSize;
}
- readSprite(stream, offset, size);
+ readSpriteD2(stream, offset, size);
}
} else {
- readMainChannels(stream, offset, size);
+ readMainChannelsD2(stream, offset, size);
}
}
+enum {
+ kMainChannelSizeD4 = 40,
+ kSprChannelSizeD4 = 20
+};
+
+void Frame::readChannelD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ // 40 bytes header
+ if (offset >= kMainChannelSizeD4) {
+ if (size <= kSprChannelSizeD4)
+ readSpriteD4(stream, offset, size);
+ else {
+ // read > 1 sprites channel
+ while (size > kSprChannelSizeD4) {
+ byte spritePosition = (offset - kMainChannelSizeD4) / kSprChannelSizeD4;
+ uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD4 + kMainChannelSizeD4;
+ uint16 needSize = nextStart - offset;
+ readSpriteD4(stream, offset, needSize);
+ offset += needSize;
+ size -= needSize;
+ }
+ readSpriteD4(stream, offset, size);
+ }
+ } else {
+ readMainChannelsD4(stream, offset, size);
+ }
+}
+
+void Frame::readChannelD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+}
+
+void Frame::readChannelD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+}
+
void Frame::readChannels(Common::SeekableReadStreamEndian *stream, uint16 version) {
byte unk[24];
@@ -472,7 +520,7 @@ Common::String Frame::formatChannelInfo() {
}
-void Frame::readMainChannels(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size) {
+void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
uint16 finishPosition = offset + size;
while (offset < finishPosition) {
@@ -552,7 +600,167 @@ void Frame::readPaletteInfo(Common::SeekableReadStreamEndian &stream) {
stream.skip(8); // unknown
}
-void Frame::readSprite(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size) {
+void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readMainChannelsD4(): 40 byte header");
+ stream.hexdump(kMainChannelSizeD4);
+ }
+
+ uint16 finishPosition = offset + size;
+ int unk1;
+
+ while (offset < finishPosition) {
+ switch (offset) {
+ case 0:
+ // Sound/Tempo/Transition
+ unk1 = stream.readByte();
+ if (unk1) {
+ warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
+ }
+ offset++;
+ break;
+ case 1:
+ _soundType1 = stream.readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+ offset++;
+ break;
+ case 2: {
+ uint8 transFlags = stream.readByte();
+ if (transFlags & 0x80) // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
+ _transArea = 1;
+ else
+ _transArea = 0;
+ _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
+ }
+
+ offset++;
+ break;
+ case 3:
+ _transChunkSize = stream.readByte();
+ offset++;
+ break;
+ case 4:
+ _tempo = stream.readByte();
+ offset++;
+ break;
+ case 5:
+ _transType = static_cast<TransitionType>(stream.readByte());
+ offset++;
+ break;
+ case 6:
+ _sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 8:
+ _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 10:
+ _soundType2 = stream.readByte();
+ offset++;
+ break;
+ case 11:
+ _skipFrameFlag = stream.readByte();
+ offset++;
+ break;
+ case 12:
+ _blend = stream.readByte();
+ offset++;
+ break;
+ case 13:
+ _colorTempo = stream.readByte();
+ offset++;
+ break;
+ case 14:
+ _colorSound1 = stream.readByte();
+ offset++;
+ break;
+ case 15:
+ _colorSound2 = stream.readByte();
+ offset++;
+ break;
+ case 16:
+ _actionId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 18:
+ _colorScript = stream.readByte();
+ offset++;
+ break;
+ case 19:
+ _colorTrans = stream.readByte();
+ offset++;
+ break;
+ case 20: {
+ // palette, 13 bytes
+ int16 paletteId = stream.readSint16();
+ if (paletteId == 0) {
+ _palette.paletteId = CastMemberID(0, 0);
+ } else if (paletteId < 0) {
+ _palette.paletteId = CastMemberID(paletteId, -1);
+ } else {
+ _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
+ }
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
+ _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
+ warning("first: %d last: %d", _palette.firstColor, _palette.lastColor);
+ _palette.flags = stream.readByte(); // 24
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream.readByte(); // 25
+ _palette.frameCount = stream.readUint16(); // 26
+ _palette.cycleCount = stream.readUint16(); // 28
+ _palette.fade = stream.readByte(); // 30
+ _palette.delay = stream.readByte(); // 31
+ _palette.style = stream.readByte(); // 32
+ }
+ offset += 13;
+ break;
+ case 33:
+ unk1 = stream.readByte();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk2: %d 0x%x", unk1, unk1);
+ offset += 1;
+ break;
+ case 34:
+ unk1 = stream.readUint16();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk3: %d 0x%x", unk1, unk1);
+ offset += 2;
+ break;
+ case 36:
+ unk1 = stream.readUint16();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk4: %d 0x%x", unk1, unk1);
+ offset += 2;
+ break;
+ case 38:
+ _palette.colorCode = stream.readByte();
+ offset++;
+ break;
+ case 39:
+ unk1 = stream.readUint16();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk5: %d 0x%x", unk1, unk1);
+ offset += 2;
+ break;
+ case 40:
+ break;
+ default:
+ error("Frame::readMainChannelsD4(): Miscomputed field position: %d", offset);
+ break;
+ }
+ }
+
+ _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
+ _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
+}
+
+void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
uint16 spritePosition = (offset - 32) / 16;
uint16 spriteStart = spritePosition * 16 + 32;
@@ -563,6 +771,11 @@ void Frame::readSprite(Common::SeekableReadStreamEndian &stream, uint16 offset,
int x1 = 0;
int x2 = 0;
+ if (sprite._puppet) {
+ stream.skip(size);
+ return;
+ }
+
while (fieldPosition < finishPosition) {
switch (fieldPosition) {
case kSpritePositionUnk1:
@@ -611,13 +824,129 @@ void Frame::readSprite(Common::SeekableReadStreamEndian &stream, uint16 offset,
break;
default:
// end of channel, go to next sprite channel
- readSprite(stream, spriteStart + 16, finishPosition - fieldPosition);
+ readSpriteD2(stream, spriteStart + 16, finishPosition - fieldPosition);
+ fieldPosition = finishPosition;
+ break;
+ }
+ }
+ warning("Frame::readSpriteD2(): %s(%d)[%x,%x,%02x %02x,%d/%d/%d/%d]", sprite._castId.asString().c_str(), sprite._enabled, x1, x2, sprite._thickness, sprite._inkData, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
+}
+
+void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ uint16 spritePosition = (offset - kMainChannelSizeD4) / kSprChannelSizeD4;
+ uint16 spriteStart = spritePosition * kSprChannelSizeD4 + kMainChannelSizeD4;
+
+ uint16 fieldPosition = offset - spriteStart;
+ uint16 finishPosition = fieldPosition + size;
+
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readSpriteD4(): channel %d, 20 bytes", spritePosition);
+ stream.hexdump(kSprChannelSizeD4);
+ }
+
+ debugC(3, kDebugLoading, "Frame::readSpriteD4(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+
+ Sprite &sprite = *_sprites[spritePosition + 1];
+
+ if (sprite._puppet) {
+ stream.skip(size);
+ return;
+ }
+
+ while (fieldPosition < finishPosition) {
+ switch (fieldPosition) {
+ case 0:
+ sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
+ fieldPosition++;
+ break;
+ case 1:
+ sprite._spriteType = (SpriteType)stream.readByte();
+ fieldPosition++;
+
+ sprite._enabled = sprite._spriteType != kInactiveSprite;
+ break;
+ case 2:
+ sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 3:
+ sprite._backColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 4:
+ sprite._thickness = stream.readByte();
+ fieldPosition++;
+ break;
+ case 5:
+ sprite._inkData = stream.readByte();
+ fieldPosition++;
+
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ if (sprite._inkData & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
+
+ break;
+ case 6:
+ if (sprite.isQDShape()) {
+ sprite._pattern = stream.readUint16();
+ } else {
+ sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ }
+ fieldPosition += 2;
+ break;
+ case 8:
+ sprite._startPoint.y = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 10:
+ sprite._startPoint.x = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 12:
+ sprite._height = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 14:
+ sprite._width = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 16:
+ sprite._scriptId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ fieldPosition += 2;
+ break;
+ case 18:
+ // & 0x0f scorecolor
+ // 0x10 forecolor is rgb
+ // 0x20 bgcolor is rgb
+ // 0x40 editable
+ // 0x80 moveable
+ sprite._colorcode = stream.readByte();
+ fieldPosition++;
+
+ sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ break;
+ case 19:
+ sprite._blendAmount = stream.readByte();
+ fieldPosition++;
+ break;
+ case 20:
+ // end of channel, go to next sprite channel
+ readSpriteD4(stream, spriteStart + kSprChannelSizeD4, finishPosition - fieldPosition);
fieldPosition = finishPosition;
break;
+ default:
+ error("Frame::readSpriteD4(): Miscomputed field position: %d", fieldPosition);
}
}
- warning("Frame::readSprite(): %s(%d)[%x,%x,%02x %02x,%d/%d/%d/%d]", sprite._castId.asString().c_str(), sprite._enabled, x1, x2, sprite._thickness, sprite._inkData, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
}
} // End of namespace Director
diff --git a/engines/director/frame.h b/engines/director/frame.h
index 6f69aa6df94..2c4ef57ad48 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -33,6 +33,7 @@ struct Surface;
namespace Common {
class ReadStreamEndian;
+class MemoryReadStreamEndian;
}
namespace Director {
@@ -92,7 +93,7 @@ public:
Score *getScore() const { return _score; }
void readChannels(Common::SeekableReadStreamEndian *stream, uint16 version);
- void readChannel(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size, uint16 version);
void executeImmediateScripts();
@@ -101,8 +102,22 @@ public:
private:
void readPaletteInfo(Common::SeekableReadStreamEndian &stream);
- void readSprite(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size);
- void readMainChannels(Common::SeekableReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+
+ void readChannelD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+
+ void readChannelD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+
+ void readChannelD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+ void readMainChannelsD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
+
Image::ImageDecoder *getImageFrom(uint16 spriteId);
Common::String readTextStream(Common::SeekableReadStreamEndian *textStream, TextCastMember *textCast);
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index bd4ba2142f4..072e2fbc1e1 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1356,7 +1356,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
uint dataSize = stream.size();
byte *data = (byte *)malloc(dataSize);
stream.read(data, dataSize);
-
+
_framesStream = new Common::MemoryReadStreamEndian(data, dataSize, stream.isBE(), DisposeAfterUse::YES);
if (debugChannelSet(8, kDebugLoading)) {
@@ -1394,6 +1394,8 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// TODO Merge it with shared cast
memset(_channelData, 0, kChannelDataSize);
+ _currentFrame = new Frame(this, _numChannelsDisplayed);
+
// This makes all indexing simpler
_frameOffsets.push_back(0);
@@ -1406,7 +1408,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Pre-computing number of frames, as sometimes the frameNumber in stream mismatches
debugC(1, kDebugLoading, "Score::loadFrames(): Precomputing total number of frames!");
-
+
// Calculate number of frames beforehand
for (_numFrames = 1; loadFrame(_numFrames); _numFrames++) { }
@@ -1471,8 +1473,8 @@ void Score::rebuildChannelData(int frameNum) {
// Lock variables
int curFrameNumber = _curFrameNumber;
- Frame *frame = _currentFrame;
- _currentFrame = nullptr; // To avoid later deletion of frame inside renderOneFrame()
+ delete _currentFrame; // Destroy the built frame
+ _currentFrame = new Frame(this, _numChannelsDisplayed);
_framesStream->seek(_frameOffsets[1]); // Seek to frame 1
for (int i = 1; i < frameNum; i++) {
@@ -1480,9 +1482,7 @@ void Score::rebuildChannelData(int frameNum) {
}
// Unlock variables
- delete _currentFrame; // Destroy the built frame
_curFrameNumber = curFrameNumber;
- _currentFrame = frame;
}
bool Score::readOneFrame() {
@@ -1500,7 +1500,6 @@ bool Score::readOneFrame() {
_framesStream->hexdump(frameSize);
}
if (frameSize > 0) {
- Frame *frame = new Frame(this, _numChannelsDisplayed);
frameSize -= 2;
while (frameSize != 0) {
@@ -1515,34 +1514,30 @@ bool Score::readOneFrame() {
frameSize -= channelSize + 4;
}
- assert(channelOffset + channelSize < kChannelDataSize);
- _framesStream->read(&_channelData[channelOffset], channelSize);
+ _currentFrame->readChannel(*_framesStream, channelOffset, channelSize, _version);
+ }
+
+ if (debugChannelSet(4, kDebugLoading)) {
+ debugC(4, kDebugLoading, "%s", _currentFrame->formatChannelInfo().c_str());
}
- Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(_channelData, ARRAYSIZE(_channelData), _framesStream->isBE());
+ //Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(_channelData, ARRAYSIZE(_channelData), _framesStream->isBE());
// str->hexdump(str->size(), 32);
- frame->readChannels(str, _version);
- delete str;
+ //frame->readChannels(str, _version);
+ //delete str;
// Precache the current FPS tempo, as this carries forward to frames to the right
// of the instruction
// Delay type tempos (e.g. wait commands, delays) apply to only a single frame, and are ignored here
- if (frame->_tempo && frame->_tempo <= 120)
- _currentTempo = frame->_tempo;
- frame->_scoreCachedTempo = frame->_tempo ? frame->_tempo : _currentTempo;
+ if (_currentFrame->_tempo && _currentFrame->_tempo <= 120)
+ _currentTempo = _currentFrame->_tempo;
+ _currentFrame->_scoreCachedTempo = _currentFrame->_tempo ? _currentFrame->_tempo : _currentTempo;
// Precache the current palette ID, as this carries forward to frames to the right
// of the instruction
- if (!frame->_palette.paletteId.isNull())
- _currentPaletteId = frame->_palette.paletteId;
- frame->_scoreCachedPaletteId = _currentPaletteId;
+ if (!_currentFrame->_palette.paletteId.isNull())
+ _currentPaletteId = _currentFrame->_palette.paletteId;
+ _currentFrame->_scoreCachedPaletteId = _currentPaletteId;
- debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, frame->_actionId.asString().c_str());
-
- if (_currentFrame != nullptr) {
- // Delete previous frame before assigning new one
- delete _currentFrame;
- _currentFrame = nullptr;
- }
- _currentFrame = frame;
+ debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, _currentFrame->_actionId.asString().c_str());
if (_curFrameNumber == _frameOffsets.size() - 1 && _framesStream->pos() < _framesStreamSize) {
// Record the starting offset for next frame
@@ -1553,7 +1548,6 @@ bool Score::readOneFrame() {
warning("Score::readOneFrame(): Zero sized frame!? exiting loop until we know what to do with the tags that follow.");
}
-
return false; // Error in loading frame
}
Commit: 4a259ea14fbe23dae68430789d11cf07c64eb2af
https://github.com/scummvm/scummvm/commit/4a259ea14fbe23dae68430789d11cf07c64eb2af
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Set autopuppet flag for all D versions
Changed paths:
engines/director/channel.cpp
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index eeb5e3943f0..b8cd07c728c 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -365,7 +365,7 @@ void Channel::setCast(CastMemberID memberID) {
_height = _sprite->_height;
replaceWidget();
- if (!_sprite->_puppet && g_director->getVersion() >= 600) {
+ if (!_sprite->_puppet) {
// Based on Director in a Nutshell, page 15
_sprite->_autoPuppet = true;
}
@@ -547,7 +547,7 @@ void Channel::setWidth(int w) {
return;
_width = MAX<int>(w, 0);
- if (!_sprite->_puppet && g_director->getVersion() >= 600) {
+ if (!_sprite->_puppet) {
// Based on Director in a Nutshell, page 15
_sprite->_autoPuppet = true;
}
@@ -558,7 +558,7 @@ void Channel::setHeight(int h) {
return;
_height = MAX<int>(h, 0);
- if (!_sprite->_puppet && g_director->getVersion() >= 600) {
+ if (!_sprite->_puppet) {
// Based on Director in a Nutshell, page 15
_sprite->_autoPuppet = true;
}
@@ -580,7 +580,7 @@ void Channel::setBbox(int l, int t, int r, int b) {
if (_width <= 0 || _height <= 0)
_width = _height = 0;
- if (!_sprite->_puppet && g_director->getVersion() >= 600) {
+ if (!_sprite->_puppet) {
// Based on Director in a Nutshell, page 15
_sprite->_autoPuppet = true;
}
@@ -595,7 +595,7 @@ void Channel::setPosition(int x, int y, bool force) {
}
_currentPoint = newPos;
- if (!_sprite->_puppet && g_director->getVersion() >= 600) {
+ if (!_sprite->_puppet) {
// Based on Director in a Nutshell, page 15
_sprite->_autoPuppet = true;
}
Commit: c849d2423c3a240e97abb18a58658ce95fa9679a
https://github.com/scummvm/scummvm/commit/c849d2423c3a240e97abb18a58658ce95fa9679a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Skip autopuppet sprites on channel loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 67c14884db4..5d0697f9b99 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -771,7 +771,7 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
int x1 = 0;
int x2 = 0;
- if (sprite._puppet) {
+ if (sprite._puppet || sprite._autoPuppet) {
stream.skip(size);
return;
}
@@ -848,7 +848,7 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
Sprite &sprite = *_sprites[spritePosition + 1];
- if (sprite._puppet) {
+ if (sprite._puppet || sprite._autoPuppet) {
stream.skip(size);
return;
}
Commit: aa44019679952565f2d4be4dc130716853d79007
https://github.com/scummvm/scummvm/commit/aa44019679952565f2d4be4dc130716853d79007
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Copy channels to _currentFrame before frame data loading
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 072e2fbc1e1..bfe889a1e8e 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -510,6 +510,9 @@ void Score::update() {
// TODO: Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
}
+ for (uint ch = 0; ch < _channels.size(); ch++)
+ *_currentFrame->_sprites[ch] = *_channels[ch]->_sprite;
+
loadFrame(_curFrameNumber);
// Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
renderFrame(_curFrameNumber);
Commit: e99a9d4511525b81b52753a09496812a9f7fc5fa
https://github.com/scummvm/scummvm/commit/e99a9d4511525b81b52753a09496812a9f7fc5fa
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Check sprites for bg/fg changes when rendering
Changed paths:
engines/director/channel.cpp
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index b8cd07c728c..e5ec6758528 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -218,7 +218,8 @@ bool Channel::isDirty(Sprite *nextSprite) {
// When puppet is set, the overall dirty flag should be set when sprite is
// modified.
isDirtyFlag |= _sprite->_castId != nextSprite->_castId ||
- _sprite->_ink != nextSprite->_ink;
+ _sprite->_ink != nextSprite->_ink || _sprite->_backColor != nextSprite->_backColor ||
+ _sprite->_foreColor != nextSprite->_foreColor;
if (!_sprite->_moveable)
isDirtyFlag |= _currentPoint != nextSprite->_startPoint;
if (!_sprite->_stretch && !hasTextCastMember(_sprite))
Commit: f594c08eca46c2af262379ed8379e5d306ebabaa
https://github.com/scummvm/scummvm/commit/f594c08eca46c2af262379ed8379e5d306ebabaa
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Treat autopuppets same as puppets when looking at sprite changes
Changed paths:
engines/director/channel.cpp
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index e5ec6758528..7839255d535 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -214,7 +214,7 @@ bool Channel::isDirty(Sprite *nextSprite) {
bool isDirtyFlag = _dirty ||
(_sprite->_cast && _sprite->_cast->isModified());
- if (_sprite && !_sprite->_puppet) {
+ if (_sprite && !_sprite->_puppet && !_sprite->_autoPuppet) {
// When puppet is set, the overall dirty flag should be set when sprite is
// modified.
isDirtyFlag |= _sprite->_castId != nextSprite->_castId ||
Commit: 9160173b0ae35186b9cecaa0d057818f0f6b9526
https://github.com/scummvm/scummvm/commit/9160173b0ae35186b9cecaa0d057818f0f6b9526
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Do not override autopuppet sprites
Changed paths:
engines/director/channel.cpp
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index 7839255d535..1e6d54749ca 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -415,7 +415,7 @@ void Channel::setClean(Sprite *nextSprite, int spriteId, bool partial) {
// for the non-puppet QDShape, since we won't use isDirty to check whether the QDShape is changed.
// so we may always keep the sprite info because we need it to draw QDShape.
- if (_sprite->_puppet || (!nextSprite->isQDShape() && partial)) {
+ if (_sprite->_puppet || _sprite->_autoPuppet || (!nextSprite->isQDShape() && partial)) {
// Updating scripts, etc. does not require a full re-render
_sprite->_scriptId = nextSprite->_scriptId;
} else {
Commit: c25f7663e45cee1080df51a614aadb428c585758
https://github.com/scummvm/scummvm/commit/c25f7663e45cee1080df51a614aadb428c585758
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Incremental frame loading for D2
Changed paths:
engines/director/frame.cpp
engines/director/frame.h
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 5d0697f9b99..252e2770434 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -123,15 +123,20 @@ void Frame::readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, u
}
}
+enum {
+ kMainChannelSizeD2 = 32,
+ kSprChannelSizeD2 = 16
+};
+
void Frame::readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- if (offset >= 32) {
- if (size <= 16)
+ if (offset >= kMainChannelSizeD2) {
+ if (size <= kSprChannelSizeD2)
readSpriteD2(stream, offset, size);
else {
// read > 1 sprites channel
- while (size > 16) {
- byte spritePosition = (offset - 32) / 16;
- uint16 nextStart = (spritePosition + 1) * 16 + 32;
+ while (size > kSprChannelSizeD2) {
+ byte spritePosition = (offset - kMainChannelSizeD2) / kSprChannelSizeD2;
+ uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD2 + kMainChannelSizeD2;
uint16 needSize = nextStart - offset;
readSpriteD2(stream, offset, needSize);
offset += needSize;
@@ -522,18 +527,21 @@ Common::String Frame::formatChannelInfo() {
void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
uint16 finishPosition = offset + size;
+ byte unk[6];
while (offset < finishPosition) {
- switch(offset) {
- case kScriptIdPosition:
+ switch (offset) {
+ case 0: // Sound/Tempo/Transition
_actionId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
offset++;
break;
- case kSoundType1Position:
+ case 1:
+ // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
_soundType1 = stream.readByte();
offset++;
break;
- case kTransFlagsPosition: {
+ case 2: {
+ // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
uint8 transFlags = stream.readByte();
if (transFlags & 0x80)
_transArea = 1;
@@ -543,61 +551,90 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
offset++;
}
break;
- case kTransChunkSizePosition:
+ case 3:
_transChunkSize = stream.readByte();
offset++;
break;
- case kTempoPosition:
+ case 4:
_tempo = stream.readByte();
offset++;
break;
- case kTransTypePosition:
+ case 5:
_transType = static_cast<TransitionType>(stream.readByte());
offset++;
break;
- case kSound1Position:
+ case 6:
_sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset+=2;
+ offset += 2;
+ break;
+ case 8:
+ _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
break;
- case kSkipFrameFlagsPosition:
+ case 10:
+ _soundType2 = stream.readByte();
+ offset++;
+ break;
+ case 11:
_skipFrameFlag = stream.readByte();
offset++;
break;
- case kBlendPosition:
+ case 12:
_blend = stream.readByte();
offset++;
break;
- case kSound2Position:
- _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
- break;
- case kSound2TypePosition:
- _soundType2 = stream.readByte();
- offset += 1;
+ case 13:
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ _soundType2 = stream.readByte();
+ } else {
+ stream.read(unk, 3);
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
+ }
+ offset += 3;
break;
- case kPalettePosition:
- if (stream.readUint16())
- readPaletteInfo(stream);
+ case 16: {
+ // palette
+ int16 paletteId = stream.readSint16();
+ if (paletteId == 0) {
+ _palette.paletteId = CastMemberID(0, 0);
+ } else if (paletteId < 0) {
+ _palette.paletteId = CastMemberID(paletteId, -1);
+ } else {
+ _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
+ }
+
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream.readByte() ^ 0x80);
+ _palette.lastColor = g_director->transformColor(stream.readByte() ^ 0x80);
+ _palette.flags = stream.readByte();
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream.readByte();
+ _palette.frameCount = stream.readUint16();
+ _palette.cycleCount = stream.readUint16();
+
+ stream.read(unk, 6);
+
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
+ unk[1], unk[2], unk[3], unk[4], unk[5]);
+ }
offset += 16;
break;
+ case 32:
+ break;
default:
- offset++;
- stream.readByte();
- debugC(1, kDebugLoading, "Frame::readMainChannels: Field Position %d, Finish Position %d", offset, finishPosition);
+ error("Frame::readMainChannelsD2(): Miscomputed field position: %d", offset);
break;
}
}
- debugC(1, kDebugLoading, "Frame::readChannels(): %d %d %d %d %d %d %d %d %d %d %d", _actionId.member, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1.member, _skipFrameFlag, _blend, _sound2.member, _soundType2);
-}
-
-void Frame::readPaletteInfo(Common::SeekableReadStreamEndian &stream) {
- _palette.firstColor = stream.readByte();
- _palette.lastColor = stream.readByte();
- _palette.flags = stream.readByte();
- _palette.speed = stream.readByte();
- _palette.frameCount = stream.readUint16();
- stream.skip(8); // unknown
+ _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
+ _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
}
void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
@@ -703,7 +740,6 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
// loop points for color cycling
_palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
_palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
- warning("first: %d last: %d", _palette.firstColor, _palette.lastColor);
_palette.flags = stream.readByte(); // 24
_palette.colorCycling = (_palette.flags & 0x80) != 0;
_palette.normal = (_palette.flags & 0x60) == 0x00;
@@ -761,15 +797,20 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
}
void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- uint16 spritePosition = (offset - 32) / 16;
- uint16 spriteStart = spritePosition * 16 + 32;
+ uint16 spritePosition = (offset - kMainChannelSizeD2) / kSprChannelSizeD2;
+ uint16 spriteStart = spritePosition * kSprChannelSizeD2 + kMainChannelSizeD2;
uint16 fieldPosition = offset - spriteStart;
uint16 finishPosition = fieldPosition + size;
- Sprite &sprite = *_sprites[spritePosition];
- int x1 = 0;
- int x2 = 0;
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readSpriteD2(): channel %d, 16 bytes", spritePosition);
+ stream.hexdump(kSprChannelSizeD2);
+ }
+
+ debugC(3, kDebugLoading, "Frame::readSpriteD2(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+
+ Sprite &sprite = *_sprites[spritePosition + 1];
if (sprite._puppet || sprite._autoPuppet) {
stream.skip(size);
@@ -778,58 +819,79 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
while (fieldPosition < finishPosition) {
switch (fieldPosition) {
- case kSpritePositionUnk1:
- x1 = stream.readByte();
+ case 0:
+ sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
fieldPosition++;
break;
- case kSpritePositionEnabled:
- sprite._enabled = (stream.readByte() != 0);
+ case 1:
+ sprite._spriteType = (SpriteType)stream.readByte();
fieldPosition++;
+
+ sprite._enabled = sprite._spriteType != kInactiveSprite;
break;
- case kSpritePositionUnk2:
- x2 = stream.readUint16();
- fieldPosition += 2;
+ case 2:
+ // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
+ sprite._foreColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
+ fieldPosition++;
+ break;
+ case 3:
+ // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
+ sprite._backColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
+ fieldPosition++;
break;
- case kSpritePositionFlags:
+ case 4:
sprite._thickness = stream.readByte();
+ fieldPosition++;
+ break;
+ case 5:
sprite._inkData = stream.readByte();
- sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ fieldPosition++;
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
if (sprite._inkData & 0x40)
sprite._trails = 1;
else
sprite._trails = 0;
- fieldPosition += 2;
break;
- case kSpritePositionCastId:
- sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ case 6:
+ if (sprite.isQDShape()) {
+ sprite._pattern = stream.readUint16();
+ } else {
+ sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ }
fieldPosition += 2;
break;
- case kSpritePositionY:
- sprite._startPoint.y = stream.readUint16();
+ case 8:
+ sprite._startPoint.y = (int16)stream.readUint16();
fieldPosition += 2;
break;
- case kSpritePositionX:
- sprite._startPoint.x = stream.readUint16();
+ case 10:
+ sprite._startPoint.x = (int16)stream.readUint16();
fieldPosition += 2;
break;
- case kSpritePositionWidth:
- sprite._width = stream.readUint16();
+ case 12:
+ sprite._height = (int16)stream.readUint16();
fieldPosition += 2;
break;
- case kSpritePositionHeight:
- sprite._height = stream.readUint16();
+ case 14:
+ sprite._width = (int16)stream.readUint16();
fieldPosition += 2;
break;
- default:
+ case 16:
// end of channel, go to next sprite channel
- readSpriteD2(stream, spriteStart + 16, finishPosition - fieldPosition);
+ readSpriteD2(stream, spriteStart + kSprChannelSizeD2, finishPosition - fieldPosition);
fieldPosition = finishPosition;
break;
+ default:
+ error("Frame::readSpriteD2(): Miscomputed field position: %d", fieldPosition);
}
}
- warning("Frame::readSpriteD2(): %s(%d)[%x,%x,%02x %02x,%d/%d/%d/%d]", sprite._castId.asString().c_str(), sprite._enabled, x1, x2, sprite._thickness, sprite._inkData, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
+
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
}
void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
diff --git a/engines/director/frame.h b/engines/director/frame.h
index 2c4ef57ad48..b2d99243426 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -101,7 +101,6 @@ public:
private:
- void readPaletteInfo(Common::SeekableReadStreamEndian &stream);
void readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
void readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
void readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size);
Commit: f8a7541bbbb4ed88b462f5c51d3dac475e9805a5
https://github.com/scummvm/scummvm/commit/f8a7541bbbb4ed88b462f5c51d3dac475e9805a5
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: JANITORIAL: Rearrange channel loading methods in logical order
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 252e2770434..5d35acd2523 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -123,6 +123,12 @@ void Frame::readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, u
}
}
+/**************************
+ *
+ * D2 Loading
+ *
+ **************************/
+
enum {
kMainChannelSizeD2 = 32,
kSprChannelSizeD2 = 16
@@ -149,6 +155,223 @@ void Frame::readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
}
}
+void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ uint16 finishPosition = offset + size;
+ byte unk[6];
+
+ while (offset < finishPosition) {
+ switch (offset) {
+ case 0: // Sound/Tempo/Transition
+ _actionId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
+ offset++;
+ break;
+ case 1:
+ // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+ _soundType1 = stream.readByte();
+ offset++;
+ break;
+ case 2: {
+ // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
+ uint8 transFlags = stream.readByte();
+ if (transFlags & 0x80)
+ _transArea = 1;
+ else
+ _transArea = 0;
+ _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
+ offset++;
+ }
+ break;
+ case 3:
+ _transChunkSize = stream.readByte();
+ offset++;
+ break;
+ case 4:
+ _tempo = stream.readByte();
+ offset++;
+ break;
+ case 5:
+ _transType = static_cast<TransitionType>(stream.readByte());
+ offset++;
+ break;
+ case 6:
+ _sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 8:
+ _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 10:
+ _soundType2 = stream.readByte();
+ offset++;
+ break;
+ case 11:
+ _skipFrameFlag = stream.readByte();
+ offset++;
+ break;
+ case 12:
+ _blend = stream.readByte();
+ offset++;
+ break;
+ case 13:
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ _soundType2 = stream.readByte();
+ } else {
+ stream.read(unk, 3);
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
+ }
+ offset += 3;
+ break;
+ case 16: {
+ // palette
+ int16 paletteId = stream.readSint16();
+ if (paletteId == 0) {
+ _palette.paletteId = CastMemberID(0, 0);
+ } else if (paletteId < 0) {
+ _palette.paletteId = CastMemberID(paletteId, -1);
+ } else {
+ _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
+ }
+
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream.readByte() ^ 0x80);
+ _palette.lastColor = g_director->transformColor(stream.readByte() ^ 0x80);
+ _palette.flags = stream.readByte();
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream.readByte();
+ _palette.frameCount = stream.readUint16();
+ _palette.cycleCount = stream.readUint16();
+
+ stream.read(unk, 6);
+
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
+ unk[1], unk[2], unk[3], unk[4], unk[5]);
+ }
+ offset += 16;
+ break;
+ case 32:
+ break;
+ default:
+ error("Frame::readMainChannelsD2(): Miscomputed field position: %d", offset);
+ break;
+ }
+ }
+
+ _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
+ _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
+}
+
+void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ uint16 spritePosition = (offset - kMainChannelSizeD2) / kSprChannelSizeD2;
+ uint16 spriteStart = spritePosition * kSprChannelSizeD2 + kMainChannelSizeD2;
+
+ uint16 fieldPosition = offset - spriteStart;
+ uint16 finishPosition = fieldPosition + size;
+
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readSpriteD2(): channel %d, 16 bytes", spritePosition);
+ stream.hexdump(kSprChannelSizeD2);
+ }
+
+ debugC(3, kDebugLoading, "Frame::readSpriteD2(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+
+ Sprite &sprite = *_sprites[spritePosition + 1];
+
+ if (sprite._puppet || sprite._autoPuppet) {
+ stream.skip(size);
+ return;
+ }
+
+ while (fieldPosition < finishPosition) {
+ switch (fieldPosition) {
+ case 0:
+ sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
+ fieldPosition++;
+ break;
+ case 1:
+ sprite._spriteType = (SpriteType)stream.readByte();
+ fieldPosition++;
+
+ sprite._enabled = sprite._spriteType != kInactiveSprite;
+ break;
+ case 2:
+ // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
+ sprite._foreColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
+ fieldPosition++;
+ break;
+ case 3:
+ // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
+ sprite._backColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
+ fieldPosition++;
+ break;
+ case 4:
+ sprite._thickness = stream.readByte();
+ fieldPosition++;
+ break;
+ case 5:
+ sprite._inkData = stream.readByte();
+ fieldPosition++;
+
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ if (sprite._inkData & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
+
+ break;
+ case 6:
+ if (sprite.isQDShape()) {
+ sprite._pattern = stream.readUint16();
+ } else {
+ sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ }
+ fieldPosition += 2;
+ break;
+ case 8:
+ sprite._startPoint.y = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 10:
+ sprite._startPoint.x = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 12:
+ sprite._height = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 14:
+ sprite._width = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 16:
+ // end of channel, go to next sprite channel
+ readSpriteD2(stream, spriteStart + kSprChannelSizeD2, finishPosition - fieldPosition);
+ fieldPosition = finishPosition;
+ break;
+ default:
+ error("Frame::readSpriteD2(): Miscomputed field position: %d", fieldPosition);
+ }
+ }
+
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
+}
+
+
+/**************************
+ *
+ * D4 Loading
+ *
+ **************************/
+
enum {
kMainChannelSizeD4 = 40,
kSprChannelSizeD4 = 20
@@ -176,839 +399,650 @@ void Frame::readChannelD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
}
}
-void Frame::readChannelD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
-}
+void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readMainChannelsD4(): 40 byte header");
+ stream.hexdump(kMainChannelSizeD4);
+ }
-void Frame::readChannelD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
-}
+ uint16 finishPosition = offset + size;
+ int unk1;
-void Frame::readChannels(Common::SeekableReadStreamEndian *stream, uint16 version) {
- byte unk[24];
+ while (offset < finishPosition) {
+ switch (offset) {
+ case 0:
+ // Sound/Tempo/Transition
+ unk1 = stream.readByte();
+ if (unk1) {
+ warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
+ }
+ offset++;
+ break;
+ case 1:
+ _soundType1 = stream.readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+ offset++;
+ break;
+ case 2: {
+ uint8 transFlags = stream.readByte();
+ if (transFlags & 0x80) // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
+ _transArea = 1;
+ else
+ _transArea = 0;
+ _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
+ }
- if (version < kFileVer400) {
- // Sound/Tempo/Transition
- _actionId = CastMemberID(stream->readByte(), DEFAULT_CAST_LIB);
- _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
-
- if (transFlags & 0x80)
- _transArea = 1;
- else
- _transArea = 0;
- _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
-
- _transChunkSize = stream->readByte();
- _tempo = stream->readByte();
- _transType = static_cast<TransitionType>(stream->readByte());
- _sound1 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream->readByte();
-
- _skipFrameFlag = stream->readByte();
- _blend = stream->readByte();
-
- if (_vm->getPlatform() == Common::kPlatformWindows) {
- _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream->readByte();
- } else {
- stream->read(unk, 3);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
- }
-
- // palette
- int16 paletteId = stream->readSint16();
- if (paletteId == 0) {
- _palette.paletteId = CastMemberID(0, 0);
- } else if (paletteId < 0) {
- _palette.paletteId = CastMemberID(paletteId, -1);
- } else {
- _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
- }
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream->readByte() ^ 0x80);
- _palette.lastColor = g_director->transformColor(stream->readByte() ^ 0x80);
- _palette.flags = stream->readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream->readByte();
- _palette.frameCount = stream->readUint16();
- _palette.cycleCount = stream->readUint16();
-
- stream->read(unk, 6);
-
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
- unk[1], unk[2], unk[3], unk[4], unk[5]);
- } else if (version >= kFileVer400 && version < kFileVer500) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readChannels(): 40 byte header");
- stream->hexdump(40);
- }
- // Sound/Tempo/Transition
- int unk1 = stream->readByte();
- if (unk1) {
- warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
- }
- _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
-
- if (transFlags & 0x80)
- _transArea = 1;
- else
- _transArea = 0;
- _transDuration = (transFlags & 0x7f) * 250; // Duration is 1/4 secs
-
- _transChunkSize = stream->readByte();
- _tempo = stream->readByte();
- _transType = static_cast<TransitionType>(stream->readByte());
- _sound1 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
-
- _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream->readByte();
-
- _skipFrameFlag = stream->readByte();
- _blend = stream->readByte();
-
- _colorTempo = stream->readByte();
- _colorSound1 = stream->readByte();
- _colorSound2 = stream->readByte();
-
- _actionId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
-
- _colorScript = stream->readByte();
- _colorTrans = stream->readByte();
-
- // palette
- int16 paletteId = stream->readSint16();
- if (paletteId == 0) {
- _palette.paletteId = CastMemberID(0, 0);
- } else if (paletteId < 0) {
- _palette.paletteId = CastMemberID(paletteId, -1);
- } else {
- _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
+ offset++;
+ break;
+ case 3:
+ _transChunkSize = stream.readByte();
+ offset++;
+ break;
+ case 4:
+ _tempo = stream.readByte();
+ offset++;
+ break;
+ case 5:
+ _transType = static_cast<TransitionType>(stream.readByte());
+ offset++;
+ break;
+ case 6:
+ _sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 8:
+ _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 10:
+ _soundType2 = stream.readByte();
+ offset++;
+ break;
+ case 11:
+ _skipFrameFlag = stream.readByte();
+ offset++;
+ break;
+ case 12:
+ _blend = stream.readByte();
+ offset++;
+ break;
+ case 13:
+ _colorTempo = stream.readByte();
+ offset++;
+ break;
+ case 14:
+ _colorSound1 = stream.readByte();
+ offset++;
+ break;
+ case 15:
+ _colorSound2 = stream.readByte();
+ offset++;
+ break;
+ case 16:
+ _actionId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ offset += 2;
+ break;
+ case 18:
+ _colorScript = stream.readByte();
+ offset++;
+ break;
+ case 19:
+ _colorTrans = stream.readByte();
+ offset++;
+ break;
+ case 20: {
+ // palette, 13 bytes
+ int16 paletteId = stream.readSint16();
+ if (paletteId == 0) {
+ _palette.paletteId = CastMemberID(0, 0);
+ } else if (paletteId < 0) {
+ _palette.paletteId = CastMemberID(paletteId, -1);
+ } else {
+ _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
+ }
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
+ _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
+ _palette.flags = stream.readByte(); // 24
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream.readByte(); // 25
+ _palette.frameCount = stream.readUint16(); // 26
+ _palette.cycleCount = stream.readUint16(); // 28
+ _palette.fade = stream.readByte(); // 30
+ _palette.delay = stream.readByte(); // 31
+ _palette.style = stream.readByte(); // 32
+ }
+ offset += 13;
+ break;
+ case 33:
+ unk1 = stream.readByte();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk2: %d 0x%x", unk1, unk1);
+ offset += 1;
+ break;
+ case 34:
+ unk1 = stream.readUint16();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk3: %d 0x%x", unk1, unk1);
+ offset += 2;
+ break;
+ case 36:
+ unk1 = stream.readUint16();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk4: %d 0x%x", unk1, unk1);
+ offset += 2;
+ break;
+ case 38:
+ _palette.colorCode = stream.readByte();
+ offset++;
+ break;
+ case 39:
+ unk1 = stream.readUint16();
+ if (unk1)
+ warning("Frame::readMainChannelsD4(): STUB: unk5: %d 0x%x", unk1, unk1);
+ offset += 2;
+ break;
+ case 40:
+ break;
+ default:
+ error("Frame::readMainChannelsD4(): Miscomputed field position: %d", offset);
+ break;
}
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.lastColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.flags = stream->readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream->readByte();
- _palette.frameCount = stream->readUint16();
- _palette.cycleCount = stream->readUint16();
- _palette.fade = stream->readByte();
- _palette.delay = stream->readByte();
- _palette.style = stream->readByte();
-
-
- unk1 = stream->readByte();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk2: %d 0x%x", unk1, unk1);
- unk1 = stream->readUint16();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk3: %d 0x%x", unk1, unk1);
- unk1 = stream->readUint16();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk4: %d 0x%x", unk1, unk1);
+ }
- _palette.colorCode = stream->readByte();
+ _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
+ _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
+}
- unk1 = stream->readByte();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk5: %d 0x%x", unk1, unk1);
+void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ uint16 spritePosition = (offset - kMainChannelSizeD4) / kSprChannelSizeD4;
+ uint16 spriteStart = spritePosition * kSprChannelSizeD4 + kMainChannelSizeD4;
- } else if (version >= kFileVer500 && version < kFileVer600) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readChannels(): 48 byte header");
- stream->hexdump(48);
- }
- // Sound/Tempo/Transition channel
- uint16 actionCastLib = stream->readUint16();
- uint16 actionId = stream->readUint16();
- _actionId = CastMemberID(actionId, actionCastLib);
- uint16 sound1CastLib = stream->readUint16();
- uint16 sound1Id = stream->readUint16();
- _sound1 = CastMemberID(sound1Id, sound1CastLib);
- uint16 sound2CastLib = stream->readUint16();
- uint16 sound2Id = stream->readUint16();
- _sound2 = CastMemberID(sound2Id, sound2CastLib);
- uint16 transCastLib = stream->readUint16();
- uint16 transId = stream->readUint16();
- _trans = CastMemberID(transId, transCastLib);
+ uint16 fieldPosition = offset - spriteStart;
+ uint16 finishPosition = fieldPosition + size;
- stream->read(unk, 5);
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readSpriteD4(): channel %d, 20 bytes", spritePosition);
+ stream.hexdump(kSprChannelSizeD4);
+ }
- _tempo = stream->readByte();
+ debugC(3, kDebugLoading, "Frame::readSpriteD4(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
- stream->read(unk, 2);
+ Sprite &sprite = *_sprites[spritePosition + 1];
- // palette
- int16 paletteCastLib = stream->readSint16();
- int16 paletteId = stream->readSint16();
- _palette.paletteId = CastMemberID(paletteId, paletteCastLib);
- _palette.speed = stream->readByte();
- _palette.flags = stream->readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.firstColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.lastColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.frameCount = stream->readUint16();
- _palette.cycleCount = stream->readUint16();
- stream->read(unk, 12);
+ if (sprite._puppet || sprite._autoPuppet) {
+ stream.skip(size);
+ return;
}
- _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
- _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
-
- for (int i = 0; i < _numChannels; i++) {
- Sprite &sprite = *_sprites[i + 1];
+ while (fieldPosition < finishPosition) {
+ switch (fieldPosition) {
+ case 0:
+ sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
+ fieldPosition++;
+ break;
+ case 1:
+ sprite._spriteType = (SpriteType)stream.readByte();
+ fieldPosition++;
- if (version < kFileVer500) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readChannels(): channel %d, 22 bytes", i);
- stream->hexdump(22);
- }
- sprite._scriptId = CastMemberID(stream->readByte(), DEFAULT_CAST_LIB);
- sprite._spriteType = (SpriteType)stream->readByte();
sprite._enabled = sprite._spriteType != kInactiveSprite;
- if (version >= kFileVer400) {
- sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
- sprite._backColor = _vm->transformColor((uint8)stream->readByte());
- } else {
- // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
- sprite._foreColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
- sprite._backColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
- }
+ break;
+ case 2:
+ sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 3:
+ sprite._backColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 4:
+ sprite._thickness = stream.readByte();
+ fieldPosition++;
+ break;
+ case 5:
+ sprite._inkData = stream.readByte();
+ fieldPosition++;
- sprite._thickness = stream->readByte();
- sprite._inkData = stream->readByte();
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ if (sprite._inkData & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
+ break;
+ case 6:
if (sprite.isQDShape()) {
- sprite._pattern = stream->readUint16();
+ sprite._pattern = stream.readUint16();
} else {
- sprite._castId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
+ sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
}
+ fieldPosition += 2;
+ break;
+ case 8:
+ sprite._startPoint.y = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 10:
+ sprite._startPoint.x = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 12:
+ sprite._height = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 14:
+ sprite._width = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 16:
+ sprite._scriptId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
+ fieldPosition += 2;
+ break;
+ case 18:
+ // & 0x0f scorecolor
+ // 0x10 forecolor is rgb
+ // 0x20 bgcolor is rgb
+ // 0x40 editable
+ // 0x80 moveable
+ sprite._colorcode = stream.readByte();
+ fieldPosition++;
- sprite._startPoint.y = (int16)stream->readUint16();
- sprite._startPoint.x = (int16)stream->readUint16();
+ sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ break;
+ case 19:
+ sprite._blendAmount = stream.readByte();
+ fieldPosition++;
+ break;
+ case 20:
+ // end of channel, go to next sprite channel
+ readSpriteD4(stream, spriteStart + kSprChannelSizeD4, finishPosition - fieldPosition);
+ fieldPosition = finishPosition;
+ break;
+ default:
+ error("Frame::readSpriteD4(): Miscomputed field position: %d", fieldPosition);
+ }
+ }
- sprite._height = (int16)stream->readUint16();
- sprite._width = (int16)stream->readUint16();
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
+}
- if (version >= kFileVer400) {
- sprite._scriptId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- // & 0x0f scorecolor
- // 0x10 forecolor is rgb
- // 0x20 bgcolor is rgb
- // 0x40 editable
- // 0x80 moveable
- sprite._colorcode = stream->readByte();
- sprite._blendAmount = stream->readByte();
- }
- } else if (version >= kFileVer500 && version < kFileVer600) {
- sprite._spriteType = (SpriteType)stream->readByte();
- sprite._inkData = stream->readByte();
+/**************************
+ *
+ * D5 Loading
+ *
+ **************************/
- uint16 castLib = stream->readUint16();
- uint16 memberID = stream->readUint16();
- sprite._castId = CastMemberID(memberID, castLib);
+enum {
+ kMainChannelSizeD5 = 40,
+ kSprChannelSizeD5 = 20
+};
- uint16 scriptCastLib = stream->readUint16();
- uint16 scriptMemberID = stream->readUint16();
- sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
+void Frame::readChannelD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+}
- sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
- sprite._backColor = _vm->transformColor((uint8)stream->readByte());
+/**************************
+ *
+ * D6 Loading
+ *
+ **************************/
- sprite._startPoint.y = (int16)stream->readUint16();
- sprite._startPoint.x = (int16)stream->readUint16();
+enum {
+ kMainChannelSizeD6 = 40,
+ kSprChannelSizeD6 = 20
+};
- sprite._height = (int16)stream->readUint16();
- sprite._width = (int16)stream->readUint16();
+void Frame::readChannelD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+}
- sprite._colorcode = stream->readByte();
- sprite._blendAmount = stream->readByte();
- sprite._thickness = stream->readByte();
- stream->readByte(); // unused
- } else if (version >= kFileVer600 && version < kFileVer700) {
- sprite._spriteType = (SpriteType)stream->readByte();
- sprite._inkData = stream->readByte();
+void Frame::readChannels(Common::SeekableReadStreamEndian *stream, uint16 version) {
+ byte unk[24];
- sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
- sprite._backColor = _vm->transformColor((uint8)stream->readByte());
+ if (version < kFileVer400) {
+ // Sound/Tempo/Transition
+ _actionId = CastMemberID(stream->readByte(), DEFAULT_CAST_LIB);
+ _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+ uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
+
+ if (transFlags & 0x80)
+ _transArea = 1;
+ else
+ _transArea = 0;
+ _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
+
+ _transChunkSize = stream->readByte();
+ _tempo = stream->readByte();
+ _transType = static_cast<TransitionType>(stream->readByte());
+ _sound1 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
+ _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
+ _soundType2 = stream->readByte();
- uint16 castLib = stream->readUint16();
- uint16 memberID = stream->readUint16();
- sprite._castId = CastMemberID(memberID, castLib);
+ _skipFrameFlag = stream->readByte();
+ _blend = stream->readByte();
- /* uint32 spriteId = */stream->readUint32();
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
+ _soundType2 = stream->readByte();
+ } else {
+ stream->read(unk, 3);
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
+ }
- sprite._startPoint.y = (int16)stream->readUint16();
- sprite._startPoint.x = (int16)stream->readUint16();
+ // palette
+ int16 paletteId = stream->readSint16();
+ if (paletteId == 0) {
+ _palette.paletteId = CastMemberID(0, 0);
+ } else if (paletteId < 0) {
+ _palette.paletteId = CastMemberID(paletteId, -1);
+ } else {
+ _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
+ }
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream->readByte() ^ 0x80);
+ _palette.lastColor = g_director->transformColor(stream->readByte() ^ 0x80);
+ _palette.flags = stream->readByte();
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream->readByte();
+ _palette.frameCount = stream->readUint16();
+ _palette.cycleCount = stream->readUint16();
- sprite._height = (int16)stream->readUint16();
- sprite._width = (int16)stream->readUint16();
+ stream->read(unk, 6);
- sprite._colorcode = stream->readByte();
- sprite._blendAmount = stream->readByte();
- sprite._thickness = stream->readByte();
- stream->readByte(); // unused
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
+ unk[1], unk[2], unk[3], unk[4], unk[5]);
+ } else if (version >= kFileVer400 && version < kFileVer500) {
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readChannels(): 40 byte header");
+ stream->hexdump(40);
+ }
+ // Sound/Tempo/Transition
+ int unk1 = stream->readByte();
+ if (unk1) {
+ warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
}
+ _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+ uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
- // Sometimes removed sprites leave garbage in the channel
- // We set it to zero, so then could skip
- if (sprite._width <= 0 || sprite._height <= 0)
- sprite._width = sprite._height = 0;
+ if (transFlags & 0x80)
+ _transArea = 1;
+ else
+ _transArea = 0;
+ _transDuration = (transFlags & 0x7f) * 250; // Duration is 1/4 secs
- sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
- sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
- sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ _transChunkSize = stream->readByte();
+ _tempo = stream->readByte();
+ _transType = static_cast<TransitionType>(stream->readByte());
+ _sound1 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- if (sprite._inkData & 0x40)
- sprite._trails = 1;
- else
- sprite._trails = 0;
+ _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
+ _soundType2 = stream->readByte();
- sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
- }
+ _skipFrameFlag = stream->readByte();
+ _blend = stream->readByte();
- if (debugChannelSet(4, kDebugLoading)) {
- debugC(4, kDebugLoading, "%s", formatChannelInfo().c_str());
- }
-}
+ _colorTempo = stream->readByte();
+ _colorSound1 = stream->readByte();
+ _colorSound2 = stream->readByte();
-Common::String Frame::formatChannelInfo() {
- Common::String result;
- result += Common::String::format("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d\n",
- _tempo, _skipFrameFlag, _blend);
- if (_palette.paletteId.isNull()) {
- result += Common::String::format("PAL: paletteId: %s, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d\n",
- _palette.paletteId.asString().c_str(), _palette.firstColor, _palette.lastColor, _palette.flags,
- _palette.cycleCount, _palette.speed, _palette.frameCount,
- _palette.fade, _palette.delay, _palette.style);
- } else {
- result += Common::String::format("PAL: paletteId: 000\n");
- }
- result += Common::String::format("TRAN: transType: %d, transDuration: %d, transChunkSize: %d\n",
- _transType, _transDuration, _transChunkSize);
- result += Common::String::format("SND: 1 sound1: %d, soundType1: %d\n", _sound1.member, _soundType1);
- result += Common::String::format("SND: 2 sound2: %d, soundType2: %d\n", _sound2.member, _soundType2);
- result += Common::String::format("LSCR: actionId: %d\n", _actionId.member);
+ _actionId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- for (int i = 0; i < _numChannels; i++) {
- Sprite &sprite = *_sprites[i + 1];
- if (sprite._castId.member) {
- result += Common::String::format("CH: %-3d castId: %s, [inkData: 0x%02x [ink: %d, trails: %d, line: %d], %dx%d@%d,%d type: %d (%s) fg: %d bg: %d], script: %s, colorcode: 0x%x, blendAmount: 0x%x, unk3: 0x%x\n",
- i + 1, sprite._castId.asString().c_str(), sprite._inkData,
- sprite._ink, sprite._trails, sprite._thickness, sprite._width, sprite._height,
- sprite._startPoint.x, sprite._startPoint.y,
- sprite._spriteType, spriteType2str(sprite._spriteType), sprite._foreColor,
- sprite._backColor, sprite._scriptId.asString().c_str(), sprite._colorcode,
- sprite._blendAmount, sprite._unk3);
+ _colorScript = stream->readByte();
+ _colorTrans = stream->readByte();
+
+ // palette
+ int16 paletteId = stream->readSint16();
+ if (paletteId == 0) {
+ _palette.paletteId = CastMemberID(0, 0);
+ } else if (paletteId < 0) {
+ _palette.paletteId = CastMemberID(paletteId, -1);
} else {
- result += Common::String::format("CH: %-3d castId: 000\n", i + 1);
+ _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
}
- }
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream->readByte() + 0x80);
+ _palette.lastColor = g_director->transformColor(stream->readByte() + 0x80);
+ _palette.flags = stream->readByte();
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream->readByte();
+ _palette.frameCount = stream->readUint16();
+ _palette.cycleCount = stream->readUint16();
+ _palette.fade = stream->readByte();
+ _palette.delay = stream->readByte();
+ _palette.style = stream->readByte();
- return result;
-}
+ unk1 = stream->readByte();
+ if (unk1)
+ warning("Frame::readChannels(): STUB: unk2: %d 0x%x", unk1, unk1);
+ unk1 = stream->readUint16();
+ if (unk1)
+ warning("Frame::readChannels(): STUB: unk3: %d 0x%x", unk1, unk1);
+ unk1 = stream->readUint16();
+ if (unk1)
+ warning("Frame::readChannels(): STUB: unk4: %d 0x%x", unk1, unk1);
-void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- uint16 finishPosition = offset + size;
- byte unk[6];
+ _palette.colorCode = stream->readByte();
- while (offset < finishPosition) {
- switch (offset) {
- case 0: // Sound/Tempo/Transition
- _actionId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
- offset++;
- break;
- case 1:
- // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- _soundType1 = stream.readByte();
- offset++;
- break;
- case 2: {
- // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
- uint8 transFlags = stream.readByte();
- if (transFlags & 0x80)
- _transArea = 1;
- else
- _transArea = 0;
- _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
- offset++;
- }
- break;
- case 3:
- _transChunkSize = stream.readByte();
- offset++;
- break;
- case 4:
- _tempo = stream.readByte();
- offset++;
- break;
- case 5:
- _transType = static_cast<TransitionType>(stream.readByte());
- offset++;
- break;
- case 6:
- _sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
- break;
- case 8:
- _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
- break;
- case 10:
- _soundType2 = stream.readByte();
- offset++;
- break;
- case 11:
- _skipFrameFlag = stream.readByte();
- offset++;
- break;
- case 12:
- _blend = stream.readByte();
- offset++;
- break;
- case 13:
- if (_vm->getPlatform() == Common::kPlatformWindows) {
- _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream.readByte();
- } else {
- stream.read(unk, 3);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
- }
- offset += 3;
- break;
- case 16: {
- // palette
- int16 paletteId = stream.readSint16();
- if (paletteId == 0) {
- _palette.paletteId = CastMemberID(0, 0);
- } else if (paletteId < 0) {
- _palette.paletteId = CastMemberID(paletteId, -1);
- } else {
- _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
- }
+ unk1 = stream->readByte();
+ if (unk1)
+ warning("Frame::readChannels(): STUB: unk5: %d 0x%x", unk1, unk1);
+
+ } else if (version >= kFileVer500 && version < kFileVer600) {
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readChannels(): 48 byte header");
+ stream->hexdump(48);
+ }
+ // Sound/Tempo/Transition channel
+ uint16 actionCastLib = stream->readUint16();
+ uint16 actionId = stream->readUint16();
+ _actionId = CastMemberID(actionId, actionCastLib);
+ uint16 sound1CastLib = stream->readUint16();
+ uint16 sound1Id = stream->readUint16();
+ _sound1 = CastMemberID(sound1Id, sound1CastLib);
+ uint16 sound2CastLib = stream->readUint16();
+ uint16 sound2Id = stream->readUint16();
+ _sound2 = CastMemberID(sound2Id, sound2CastLib);
+ uint16 transCastLib = stream->readUint16();
+ uint16 transId = stream->readUint16();
+ _trans = CastMemberID(transId, transCastLib);
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream.readByte() ^ 0x80);
- _palette.lastColor = g_director->transformColor(stream.readByte() ^ 0x80);
- _palette.flags = stream.readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream.readByte();
- _palette.frameCount = stream.readUint16();
- _palette.cycleCount = stream.readUint16();
+ stream->read(unk, 5);
- stream.read(unk, 6);
+ _tempo = stream->readByte();
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
- unk[1], unk[2], unk[3], unk[4], unk[5]);
- }
- offset += 16;
- break;
- case 32:
- break;
- default:
- error("Frame::readMainChannelsD2(): Miscomputed field position: %d", offset);
- break;
- }
+ stream->read(unk, 2);
+
+ // palette
+ int16 paletteCastLib = stream->readSint16();
+ int16 paletteId = stream->readSint16();
+ _palette.paletteId = CastMemberID(paletteId, paletteCastLib);
+ _palette.speed = stream->readByte();
+ _palette.flags = stream->readByte();
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.firstColor = g_director->transformColor(stream->readByte() + 0x80);
+ _palette.lastColor = g_director->transformColor(stream->readByte() + 0x80);
+ _palette.frameCount = stream->readUint16();
+ _palette.cycleCount = stream->readUint16();
+ stream->read(unk, 12);
}
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
_transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
-}
-
-void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readMainChannelsD4(): 40 byte header");
- stream.hexdump(kMainChannelSizeD4);
- }
- uint16 finishPosition = offset + size;
- int unk1;
+ for (int i = 0; i < _numChannels; i++) {
+ Sprite &sprite = *_sprites[i + 1];
- while (offset < finishPosition) {
- switch (offset) {
- case 0:
- // Sound/Tempo/Transition
- unk1 = stream.readByte();
- if (unk1) {
- warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
+ if (version < kFileVer500) {
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readChannels(): channel %d, 22 bytes", i);
+ stream->hexdump(22);
}
- offset++;
- break;
- case 1:
- _soundType1 = stream.readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- offset++;
- break;
- case 2: {
- uint8 transFlags = stream.readByte();
- if (transFlags & 0x80) // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
- _transArea = 1;
- else
- _transArea = 0;
- _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
+ sprite._scriptId = CastMemberID(stream->readByte(), DEFAULT_CAST_LIB);
+ sprite._spriteType = (SpriteType)stream->readByte();
+ sprite._enabled = sprite._spriteType != kInactiveSprite;
+ if (version >= kFileVer400) {
+ sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
+ sprite._backColor = _vm->transformColor((uint8)stream->readByte());
+ } else {
+ // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
+ sprite._foreColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
+ sprite._backColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
}
- offset++;
- break;
- case 3:
- _transChunkSize = stream.readByte();
- offset++;
- break;
- case 4:
- _tempo = stream.readByte();
- offset++;
- break;
- case 5:
- _transType = static_cast<TransitionType>(stream.readByte());
- offset++;
- break;
- case 6:
- _sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
- break;
- case 8:
- _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
- break;
- case 10:
- _soundType2 = stream.readByte();
- offset++;
- break;
- case 11:
- _skipFrameFlag = stream.readByte();
- offset++;
- break;
- case 12:
- _blend = stream.readByte();
- offset++;
- break;
- case 13:
- _colorTempo = stream.readByte();
- offset++;
- break;
- case 14:
- _colorSound1 = stream.readByte();
- offset++;
- break;
- case 15:
- _colorSound2 = stream.readByte();
- offset++;
- break;
- case 16:
- _actionId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
- break;
- case 18:
- _colorScript = stream.readByte();
- offset++;
- break;
- case 19:
- _colorTrans = stream.readByte();
- offset++;
- break;
- case 20: {
- // palette, 13 bytes
- int16 paletteId = stream.readSint16();
- if (paletteId == 0) {
- _palette.paletteId = CastMemberID(0, 0);
- } else if (paletteId < 0) {
- _palette.paletteId = CastMemberID(paletteId, -1);
- } else {
- _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
- }
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
- _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
- _palette.flags = stream.readByte(); // 24
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream.readByte(); // 25
- _palette.frameCount = stream.readUint16(); // 26
- _palette.cycleCount = stream.readUint16(); // 28
- _palette.fade = stream.readByte(); // 30
- _palette.delay = stream.readByte(); // 31
- _palette.style = stream.readByte(); // 32
+ sprite._thickness = stream->readByte();
+ sprite._inkData = stream->readByte();
+
+ if (sprite.isQDShape()) {
+ sprite._pattern = stream->readUint16();
+ } else {
+ sprite._castId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
}
- offset += 13;
- break;
- case 33:
- unk1 = stream.readByte();
- if (unk1)
- warning("Frame::readMainChannelsD4(): STUB: unk2: %d 0x%x", unk1, unk1);
- offset += 1;
- break;
- case 34:
- unk1 = stream.readUint16();
- if (unk1)
- warning("Frame::readMainChannelsD4(): STUB: unk3: %d 0x%x", unk1, unk1);
- offset += 2;
- break;
- case 36:
- unk1 = stream.readUint16();
- if (unk1)
- warning("Frame::readMainChannelsD4(): STUB: unk4: %d 0x%x", unk1, unk1);
- offset += 2;
- break;
- case 38:
- _palette.colorCode = stream.readByte();
- offset++;
- break;
- case 39:
- unk1 = stream.readUint16();
- if (unk1)
- warning("Frame::readMainChannelsD4(): STUB: unk5: %d 0x%x", unk1, unk1);
- offset += 2;
- break;
- case 40:
- break;
- default:
- error("Frame::readMainChannelsD4(): Miscomputed field position: %d", offset);
- break;
- }
- }
- _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
- _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
-}
+ sprite._startPoint.y = (int16)stream->readUint16();
+ sprite._startPoint.x = (int16)stream->readUint16();
-void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- uint16 spritePosition = (offset - kMainChannelSizeD2) / kSprChannelSizeD2;
- uint16 spriteStart = spritePosition * kSprChannelSizeD2 + kMainChannelSizeD2;
+ sprite._height = (int16)stream->readUint16();
+ sprite._width = (int16)stream->readUint16();
- uint16 fieldPosition = offset - spriteStart;
- uint16 finishPosition = fieldPosition + size;
+ if (version >= kFileVer400) {
+ sprite._scriptId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
+ // & 0x0f scorecolor
+ // 0x10 forecolor is rgb
+ // 0x20 bgcolor is rgb
+ // 0x40 editable
+ // 0x80 moveable
+ sprite._colorcode = stream->readByte();
+ sprite._blendAmount = stream->readByte();
+ }
+ } else if (version >= kFileVer500 && version < kFileVer600) {
+ sprite._spriteType = (SpriteType)stream->readByte();
+ sprite._inkData = stream->readByte();
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readSpriteD2(): channel %d, 16 bytes", spritePosition);
- stream.hexdump(kSprChannelSizeD2);
- }
+ uint16 castLib = stream->readUint16();
+ uint16 memberID = stream->readUint16();
+ sprite._castId = CastMemberID(memberID, castLib);
+
+ uint16 scriptCastLib = stream->readUint16();
+ uint16 scriptMemberID = stream->readUint16();
+ sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
- debugC(3, kDebugLoading, "Frame::readSpriteD2(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+ sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
+ sprite._backColor = _vm->transformColor((uint8)stream->readByte());
- Sprite &sprite = *_sprites[spritePosition + 1];
+ sprite._startPoint.y = (int16)stream->readUint16();
+ sprite._startPoint.x = (int16)stream->readUint16();
- if (sprite._puppet || sprite._autoPuppet) {
- stream.skip(size);
- return;
- }
+ sprite._height = (int16)stream->readUint16();
+ sprite._width = (int16)stream->readUint16();
- while (fieldPosition < finishPosition) {
- switch (fieldPosition) {
- case 0:
- sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
- fieldPosition++;
- break;
- case 1:
- sprite._spriteType = (SpriteType)stream.readByte();
- fieldPosition++;
+ sprite._colorcode = stream->readByte();
+ sprite._blendAmount = stream->readByte();
+ sprite._thickness = stream->readByte();
+ stream->readByte(); // unused
+ } else if (version >= kFileVer600 && version < kFileVer700) {
+ sprite._spriteType = (SpriteType)stream->readByte();
+ sprite._inkData = stream->readByte();
- sprite._enabled = sprite._spriteType != kInactiveSprite;
- break;
- case 2:
- // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
- sprite._foreColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
- fieldPosition++;
- break;
- case 3:
- // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
- sprite._backColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
- fieldPosition++;
- break;
- case 4:
- sprite._thickness = stream.readByte();
- fieldPosition++;
- break;
- case 5:
- sprite._inkData = stream.readByte();
- fieldPosition++;
+ sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
+ sprite._backColor = _vm->transformColor((uint8)stream->readByte());
- sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
- if (sprite._inkData & 0x40)
- sprite._trails = 1;
- else
- sprite._trails = 0;
+ uint16 castLib = stream->readUint16();
+ uint16 memberID = stream->readUint16();
+ sprite._castId = CastMemberID(memberID, castLib);
- break;
- case 6:
- if (sprite.isQDShape()) {
- sprite._pattern = stream.readUint16();
- } else {
- sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- }
- fieldPosition += 2;
- break;
- case 8:
- sprite._startPoint.y = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 10:
- sprite._startPoint.x = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 12:
- sprite._height = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 14:
- sprite._width = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 16:
- // end of channel, go to next sprite channel
- readSpriteD2(stream, spriteStart + kSprChannelSizeD2, finishPosition - fieldPosition);
- fieldPosition = finishPosition;
- break;
- default:
- error("Frame::readSpriteD2(): Miscomputed field position: %d", fieldPosition);
- }
- }
+ /* uint32 spriteId = */stream->readUint32();
- // Sometimes removed sprites leave garbage in the channel
- // We set it to zero, so then could skip
- if (sprite._width <= 0 || sprite._height <= 0)
- sprite._width = sprite._height = 0;
-}
+ sprite._startPoint.y = (int16)stream->readUint16();
+ sprite._startPoint.x = (int16)stream->readUint16();
-void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- uint16 spritePosition = (offset - kMainChannelSizeD4) / kSprChannelSizeD4;
- uint16 spriteStart = spritePosition * kSprChannelSizeD4 + kMainChannelSizeD4;
+ sprite._height = (int16)stream->readUint16();
+ sprite._width = (int16)stream->readUint16();
- uint16 fieldPosition = offset - spriteStart;
- uint16 finishPosition = fieldPosition + size;
+ sprite._colorcode = stream->readByte();
+ sprite._blendAmount = stream->readByte();
+ sprite._thickness = stream->readByte();
+ stream->readByte(); // unused
+ }
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readSpriteD4(): channel %d, 20 bytes", spritePosition);
- stream.hexdump(kSprChannelSizeD4);
- }
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
- debugC(3, kDebugLoading, "Frame::readSpriteD4(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
- Sprite &sprite = *_sprites[spritePosition + 1];
+ if (sprite._inkData & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
- if (sprite._puppet || sprite._autoPuppet) {
- stream.skip(size);
- return;
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
}
- while (fieldPosition < finishPosition) {
- switch (fieldPosition) {
- case 0:
- sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
- fieldPosition++;
- break;
- case 1:
- sprite._spriteType = (SpriteType)stream.readByte();
- fieldPosition++;
-
- sprite._enabled = sprite._spriteType != kInactiveSprite;
- break;
- case 2:
- sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
- break;
- case 3:
- sprite._backColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
- break;
- case 4:
- sprite._thickness = stream.readByte();
- fieldPosition++;
- break;
- case 5:
- sprite._inkData = stream.readByte();
- fieldPosition++;
-
- sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
- if (sprite._inkData & 0x40)
- sprite._trails = 1;
- else
- sprite._trails = 0;
+ if (debugChannelSet(4, kDebugLoading)) {
+ debugC(4, kDebugLoading, "%s", formatChannelInfo().c_str());
+ }
+}
- break;
- case 6:
- if (sprite.isQDShape()) {
- sprite._pattern = stream.readUint16();
- } else {
- sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- }
- fieldPosition += 2;
- break;
- case 8:
- sprite._startPoint.y = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 10:
- sprite._startPoint.x = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 12:
- sprite._height = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 14:
- sprite._width = (int16)stream.readUint16();
- fieldPosition += 2;
- break;
- case 16:
- sprite._scriptId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- fieldPosition += 2;
- break;
- case 18:
- // & 0x0f scorecolor
- // 0x10 forecolor is rgb
- // 0x20 bgcolor is rgb
- // 0x40 editable
- // 0x80 moveable
- sprite._colorcode = stream.readByte();
- fieldPosition++;
+Common::String Frame::formatChannelInfo() {
+ Common::String result;
+ result += Common::String::format("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d\n",
+ _tempo, _skipFrameFlag, _blend);
+ if (_palette.paletteId.isNull()) {
+ result += Common::String::format("PAL: paletteId: %s, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d\n",
+ _palette.paletteId.asString().c_str(), _palette.firstColor, _palette.lastColor, _palette.flags,
+ _palette.cycleCount, _palette.speed, _palette.frameCount,
+ _palette.fade, _palette.delay, _palette.style);
+ } else {
+ result += Common::String::format("PAL: paletteId: 000\n");
+ }
+ result += Common::String::format("TRAN: transType: %d, transDuration: %d, transChunkSize: %d\n",
+ _transType, _transDuration, _transChunkSize);
+ result += Common::String::format("SND: 1 sound1: %d, soundType1: %d\n", _sound1.member, _soundType1);
+ result += Common::String::format("SND: 2 sound2: %d, soundType2: %d\n", _sound2.member, _soundType2);
+ result += Common::String::format("LSCR: actionId: %d\n", _actionId.member);
- sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
- sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
- sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
- break;
- case 19:
- sprite._blendAmount = stream.readByte();
- fieldPosition++;
- break;
- case 20:
- // end of channel, go to next sprite channel
- readSpriteD4(stream, spriteStart + kSprChannelSizeD4, finishPosition - fieldPosition);
- fieldPosition = finishPosition;
- break;
- default:
- error("Frame::readSpriteD4(): Miscomputed field position: %d", fieldPosition);
+ for (int i = 0; i < _numChannels; i++) {
+ Sprite &sprite = *_sprites[i + 1];
+ if (sprite._castId.member) {
+ result += Common::String::format("CH: %-3d castId: %s, [inkData: 0x%02x [ink: %d, trails: %d, line: %d], %dx%d@%d,%d type: %d (%s) fg: %d bg: %d], script: %s, colorcode: 0x%x, blendAmount: 0x%x, unk3: 0x%x\n",
+ i + 1, sprite._castId.asString().c_str(), sprite._inkData,
+ sprite._ink, sprite._trails, sprite._thickness, sprite._width, sprite._height,
+ sprite._startPoint.x, sprite._startPoint.y,
+ sprite._spriteType, spriteType2str(sprite._spriteType), sprite._foreColor,
+ sprite._backColor, sprite._scriptId.asString().c_str(), sprite._colorcode,
+ sprite._blendAmount, sprite._unk3);
+ } else {
+ result += Common::String::format("CH: %-3d castId: 000\n", i + 1);
}
}
- // Sometimes removed sprites leave garbage in the channel
- // We set it to zero, so then could skip
- if (sprite._width <= 0 || sprite._height <= 0)
- sprite._width = sprite._height = 0;
+ return result;
}
} // End of namespace Director
Commit: 5b964c31d6a5890a3b8e9b5eba27bbf3e31a70ec
https://github.com/scummvm/scummvm/commit/5b964c31d6a5890a3b8e9b5eba27bbf3e31a70ec
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Initial code for incremental D5 frame loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 5d35acd2523..d0a533ee9df 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -414,7 +414,7 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
// Sound/Tempo/Transition
unk1 = stream.readByte();
if (unk1) {
- warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
+ warning("Frame::readMainChannelsD4(): STUB: unk1: %d 0x%x", unk1, unk1);
}
offset++;
break;
@@ -682,11 +682,235 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
**************************/
enum {
- kMainChannelSizeD5 = 40,
- kSprChannelSizeD5 = 20
+ kMainChannelSizeD5 = 48,
+ kSprChannelSizeD5 = 24
};
void Frame::readChannelD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ // 48 bytes header
+ if (offset >= kMainChannelSizeD5) {
+ if (size <= kSprChannelSizeD5)
+ readSpriteD5(stream, offset, size);
+ else {
+ // read > 1 sprites channel
+ while (size > kSprChannelSizeD5) {
+ byte spritePosition = (offset - kMainChannelSizeD5) / kSprChannelSizeD5;
+ uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD5 + kMainChannelSizeD5;
+ uint16 needSize = nextStart - offset;
+ readSpriteD5(stream, offset, needSize);
+ offset += needSize;
+ size -= needSize;
+ }
+ readSpriteD5(stream, offset, size);
+ }
+ } else {
+ readMainChannelsD5(stream, offset, size);
+ }
+}
+
+void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readMainChannelsD5(): 40 byte header");
+ stream.hexdump(kMainChannelSizeD4);
+ }
+
+ uint16 finishPosition = offset + size;
+ byte unk[5];
+
+ while (offset < finishPosition) {
+ switch (offset) {
+ case 0: {
+ // Sound/Tempo/Transition
+ uint16 actionCastLib = stream.readUint16();
+ uint16 actionId = stream.readUint16();
+ _actionId = CastMemberID(actionId, actionCastLib);
+ }
+ offset += 4;
+ break;
+ case 4: {
+ uint16 sound1CastLib = stream.readUint16();
+ uint16 sound1Id = stream.readUint16();
+ _sound1 = CastMemberID(sound1Id, sound1CastLib);
+ }
+ offset += 4;
+ break;
+ case 8: {
+ uint16 sound2CastLib = stream.readUint16();
+ uint16 sound2Id = stream.readUint16();
+ _sound2 = CastMemberID(sound2Id, sound2CastLib);
+ }
+ offset += 4;
+ break;
+ case 12: {
+ uint16 transCastLib = stream.readUint16();
+ uint16 transId = stream.readUint16();
+ _trans = CastMemberID(transId, transCastLib);
+ }
+ offset += 4;
+ break;
+ case 16:
+ stream.read(unk, 5);
+ warning("Frame::readMainChannelsD5(): STUB: unk1: 0x%x 0x%x 0x%x 0x%x 0x%x", unk[0], unk[1], unk[2], unk[3], unk[4]);
+ offset += 5;
+ break;
+ case 21:
+ _tempo = stream.readByte();
+ offset++;
+ break;
+ case 22:
+ stream.read(unk, 2);
+ warning("Frame::readMainChannelsD5(): STUB: unk2: 0x%x 0x%x", unk[0], unk[1]);
+ offset += 2;
+ break;
+ case 24: {
+ // palette, 14 (26?) bytes
+ int16 paletteCastLib = stream.readSint16();
+ int16 paletteId = stream.readSint16(); // 26
+ _palette.paletteId = CastMemberID(paletteId, paletteCastLib);
+
+ _palette.speed = stream.readByte(); // 28
+ _palette.flags = stream.readByte(); // 29
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 30
+ _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 31
+ _palette.frameCount = stream.readUint16(); // 32
+ _palette.cycleCount = stream.readUint16(); // 34
+ stream.read(unk, 12);
+ }
+ offset += 14 + 12;
+ break;
+ case 48:
+ break;
+ default:
+ error("Frame::readMainChannelsD5(): Miscomputed field position: %d", offset);
+ break;
+ }
+ }
+
+ _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
+ _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
+}
+
+void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ uint16 spritePosition = (offset - kMainChannelSizeD5) / kSprChannelSizeD5;
+ uint16 spriteStart = spritePosition * kSprChannelSizeD5 + kMainChannelSizeD5;
+
+ uint16 fieldPosition = offset - spriteStart;
+ uint16 finishPosition = fieldPosition + size;
+
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readSpriteD5(): channel %d, 20 bytes", spritePosition);
+ stream.hexdump(kSprChannelSizeD4);
+ }
+
+ debugC(3, kDebugLoading, "Frame::readSpriteD5(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+
+ Sprite &sprite = *_sprites[spritePosition + 1];
+
+ if (sprite._puppet || sprite._autoPuppet) {
+ stream.skip(size);
+ return;
+ }
+
+ while (fieldPosition < finishPosition) {
+ switch (fieldPosition) {
+ case 0:
+ sprite._spriteType = (SpriteType)stream.readByte();
+ fieldPosition++;
+ break;
+ case 1:
+ sprite._inkData = stream.readByte();
+ fieldPosition++;
+
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ if (sprite._inkData & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
+
+ break;
+ case 2: {
+ uint16 castLib = stream.readUint16();
+ uint16 memberID = stream.readUint16();
+ sprite._castId = CastMemberID(memberID, castLib);
+ }
+ fieldPosition += 4;
+ break;
+ case 6: {
+ uint16 scriptCastLib = stream.readUint16();
+ uint16 scriptMemberID = stream.readUint16();
+ sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
+ }
+ fieldPosition += 4;
+ break;
+ case 10:
+ sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 11:
+ sprite._backColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 12:
+ sprite._startPoint.y = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 14:
+ sprite._startPoint.x = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 16:
+ sprite._height = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 18:
+ sprite._width = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 20:
+ // & 0x0f scorecolor
+ // 0x10 forecolor is rgb
+ // 0x20 bgcolor is rgb
+ // 0x40 editable
+ // 0x80 moveable
+ sprite._colorcode = stream.readByte();
+ fieldPosition++;
+
+ sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ break;
+ case 21:
+ sprite._blendAmount = stream.readByte();
+ fieldPosition++;
+ break;
+ case 22:
+ sprite._thickness = stream.readByte();
+ fieldPosition++;
+ break;
+ case 23:
+ (void)stream.readByte(); // unused
+ fieldPosition++;
+ break;
+ case 24:
+ // end of channel, go to next sprite channel
+ readSpriteD4(stream, spriteStart + kSprChannelSizeD5, finishPosition - fieldPosition);
+ fieldPosition = finishPosition;
+ break;
+ default:
+ error("Frame::readSpriteD5(): Miscomputed field position: %d", fieldPosition);
+ }
+ }
+
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
}
/**************************
Commit: 0ce2892a198ae050d1faf526ca77c548bbc6f4a1
https://github.com/scummvm/scummvm/commit/0ce2892a198ae050d1faf526ca77c548bbc6f4a1
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Initial code for incremental D6 frame loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index d0a533ee9df..8caa52fbc9a 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -920,11 +920,151 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
**************************/
enum {
- kMainChannelSizeD6 = 40,
- kSprChannelSizeD6 = 20
+ kMainChannelSizeD6 = 48,
+ kSprChannelSizeD6 = 24
};
void Frame::readChannelD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ // 48 bytes header
+ if (offset >= kMainChannelSizeD6) {
+ if (size <= kSprChannelSizeD6)
+ readSpriteD6(stream, offset, size);
+ else {
+ // read > 1 sprites channel
+ while (size > kSprChannelSizeD6) {
+ byte spritePosition = (offset - kMainChannelSizeD6) / kSprChannelSizeD6;
+ uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD6 + kMainChannelSizeD6;
+ uint16 needSize = nextStart - offset;
+ readSpriteD6(stream, offset, needSize);
+ offset += needSize;
+ size -= needSize;
+ }
+ readSpriteD6(stream, offset, size);
+ }
+ } else {
+ readMainChannelsD6(stream, offset, size);
+ }
+}
+
+void Frame::readMainChannelsD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ error("Frame::readMainChannelsD6(): Miscomputed field position: %d", offset);
+}
+
+void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
+ uint16 spritePosition = (offset - kMainChannelSizeD6) / kSprChannelSizeD6;
+ uint16 spriteStart = spritePosition * kSprChannelSizeD6 + kMainChannelSizeD6;
+
+ uint16 fieldPosition = offset - spriteStart;
+ uint16 finishPosition = fieldPosition + size;
+
+ if (debugChannelSet(8, kDebugLoading)) {
+ debugC(8, kDebugLoading, "Frame::readSpriteD6(): channel %d, 20 bytes", spritePosition);
+ stream.hexdump(kSprChannelSizeD6);
+ }
+
+ debugC(3, kDebugLoading, "Frame::readSpriteD6(): sprite: %d offset: %d size: %d, field: %d", spritePosition, offset, size, fieldPosition);
+
+ Sprite &sprite = *_sprites[spritePosition + 1];
+
+ if (sprite._puppet || sprite._autoPuppet) {
+ stream.skip(size);
+ return;
+ }
+
+ while (fieldPosition < finishPosition) {
+ switch (fieldPosition) {
+ case 0:
+ sprite._spriteType = (SpriteType)stream.readByte();
+ fieldPosition++;
+ break;
+ case 1:
+ sprite._inkData = stream.readByte();
+ fieldPosition++;
+
+ sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+ if (sprite._inkData & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
+
+ break;
+ case 2:
+ sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 3:
+ sprite._backColor = _vm->transformColor((uint8)stream.readByte());
+ fieldPosition++;
+ break;
+ case 4: {
+ uint16 castLib = stream.readUint16();
+ uint16 memberID = stream.readUint16();
+ sprite._castId = CastMemberID(memberID, castLib);
+ }
+ fieldPosition += 4;
+ break;
+ case 8: {
+ uint16 scriptCastLib = stream.readUint16();
+ uint16 scriptMemberID = stream.readUint16();
+ sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
+ }
+ fieldPosition += 4;
+ break;
+ case 12:
+ sprite._startPoint.y = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 14:
+ sprite._startPoint.x = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 16:
+ sprite._height = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 18:
+ sprite._width = (int16)stream.readUint16();
+ fieldPosition += 2;
+ break;
+ case 20:
+ // & 0x0f scorecolor
+ // 0x10 forecolor is rgb
+ // 0x20 bgcolor is rgb
+ // 0x40 editable
+ // 0x80 moveable
+ sprite._colorcode = stream.readByte();
+ fieldPosition++;
+
+ sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
+ break;
+ case 21:
+ sprite._blendAmount = stream.readByte();
+ fieldPosition++;
+ break;
+ case 22:
+ sprite._thickness = stream.readByte();
+ fieldPosition++;
+ break;
+ case 23:
+ (void)stream.readByte(); // unused
+ fieldPosition++;
+ break;
+ case 24:
+ // end of channel, go to next sprite channel
+ readSpriteD4(stream, spriteStart + kSprChannelSizeD5, finishPosition - fieldPosition);
+ fieldPosition = finishPosition;
+ break;
+ default:
+ error("Frame::readSpriteD6(): Miscomputed field position: %d", fieldPosition);
+ }
+ }
+
+ // Sometimes removed sprites leave garbage in the channel
+ // We set it to zero, so then could skip
+ if (sprite._width <= 0 || sprite._height <= 0)
+ sprite._width = sprite._height = 0;
}
void Frame::readChannels(Common::SeekableReadStreamEndian *stream, uint16 version) {
Commit: 30fdc2a9e2b47109f7ebc6de77e652e8a6b74b04
https://github.com/scummvm/scummvm/commit/30fdc2a9e2b47109f7ebc6de77e652e8a6b74b04
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Do not process frame actions multiple times
Also drop now impossible check for unreferenced actions
Changed paths:
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index bfe889a1e8e..e4efb834c2c 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1452,8 +1452,7 @@ bool Score::loadFrame(int frameNum) {
if (!isFrameRead)
return false;
- // Load frame action, cast
- loadCurrentFrameAction();
+ // Load frame cast
setSpriteCasts();
return true;
@@ -1685,49 +1684,16 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
break;
}
- if (ConfMan.getBool("dump_scripts"))
- for (auto &j : _actions) {
- if (!j._value.empty())
- _movie->getCast()->dumpScript(j._value.c_str(), kScoreScript, j._key);
- }
-}
-
-void Score::loadCurrentFrameAction() {
- bool *scriptRefs = (bool *)calloc(_actions.size() + 1, sizeof(bool));
-
- // Now let's scan which scripts are actually referenced
- if ((uint)_currentFrame->_actionId.member <= _actions.size())
- scriptRefs[_currentFrame->_actionId.member] = true;
-
- for (uint16 j = 0; j <= _currentFrame->_numChannels; j++) {
- if ((uint)_currentFrame->_sprites[j]->_scriptId.member <= _actions.size())
- scriptRefs[_currentFrame->_sprites[j]->_scriptId.member] = true;
- }
-
for (auto &j : _actions) {
- if (!scriptRefs[j._key]) {
- // Check if it is empty
- bool empty = true;
- Common::U32String u32Script(j._value);
- for (const Common::u32char_type_t *ptr = u32Script.c_str(); *ptr; ptr++)
- if (!(*ptr == ' ' || *ptr == '-' || *ptr == '\n' || *ptr == '\r' || *ptr == '\t' || *ptr == CONTINUATION)) {
- empty = false;
- break;
- }
-
- if (!empty)
- warning("Action id %d is not referenced, the code is:\n-----\n%s\n------", j._key, j._value.c_str());
-
- continue;
- }
if (!j._value.empty()) {
+ if (ConfMan.getBool("dump_scripts"))
+ _movie->getCast()->dumpScript(j._value.c_str(), kScoreScript, j._key);
+
_movie->getMainLingoArch()->addCode(j._value, kScoreScript, j._key);
processImmediateFrameScript(j._value, j._key);
}
}
-
- free(scriptRefs);
}
Common::String Score::formatChannelInfo() {
diff --git a/engines/director/score.h b/engines/director/score.h
index f03a92c3a20..7ed1218633e 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -84,7 +84,6 @@ public:
void loadLabels(Common::SeekableReadStreamEndian &stream);
void loadActions(Common::SeekableReadStreamEndian &stream);
- void loadCurrentFrameAction();
void loadSampleSounds(uint type);
static int compareLabels(const void *a, const void *b);
Commit: 4eadd3b7bf55e68b72ee0b13514c15819ad6a34a
https://github.com/scummvm/scummvm/commit/4eadd3b7bf55e68b72ee0b13514c15819ad6a34a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Reset frame fully on rewind. This fixes D2-D3
Changed paths:
engines/director/frame.cpp
engines/director/frame.h
engines/director/score.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 8caa52fbc9a..a34915a8b64 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -34,6 +34,13 @@ namespace Director {
Frame::Frame(Score *score, int numChannels) {
_score = score;
_vm = score->getMovie()->getVM();
+ _numChannels = numChannels;
+
+
+ reset();
+}
+
+void Frame::reset() {
_transDuration = 0;
_transType = kTransNone;
_transArea = 0;
@@ -43,8 +50,6 @@ Frame::Frame(Score *score, int numChannels) {
_scoreCachedTempo = 0;
_scoreCachedPaletteId = CastMemberID(0, 0);
- _numChannels = numChannels;
-
_sound1 = CastMemberID(0, 0);
_sound2 = CastMemberID(0, 0);
_soundType1 = 0;
@@ -63,6 +68,9 @@ Frame::Frame(Score *score, int numChannels) {
_sprites.resize(_numChannels + 1);
for (uint16 i = 0; i < _sprites.size(); i++) {
+ if (_sprites[i])
+ delete _sprites[i];
+
Sprite *sp = new Sprite(this);
_sprites[i] = sp;
}
diff --git a/engines/director/frame.h b/engines/director/frame.h
index b2d99243426..b29d836c7a1 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -90,6 +90,8 @@ public:
Frame(const Frame &frame);
~Frame();
+ void reset();
+
Score *getScore() const { return _score; }
void readChannels(Common::SeekableReadStreamEndian *stream, uint16 version);
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index e4efb834c2c..dcbbf6d94b7 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -510,9 +510,6 @@ void Score::update() {
// TODO: Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
}
- for (uint ch = 0; ch < _channels.size(); ch++)
- *_currentFrame->_sprites[ch] = *_channels[ch]->_sprite;
-
loadFrame(_curFrameNumber);
// Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
renderFrame(_curFrameNumber);
@@ -1419,6 +1416,8 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
memset(_channelData, 0, kChannelDataSize); // Reset channel data
+ _currentFrame->reset();
+
loadFrame(1);
// Read over frame offset array and print each item
@@ -1475,8 +1474,8 @@ void Score::rebuildChannelData(int frameNum) {
// Lock variables
int curFrameNumber = _curFrameNumber;
- delete _currentFrame; // Destroy the built frame
- _currentFrame = new Frame(this, _numChannelsDisplayed);
+
+ _currentFrame->reset();
_framesStream->seek(_frameOffsets[1]); // Seek to frame 1
for (int i = 1; i < frameNum; i++) {
Commit: cd3be9ac18fa4231c15fd20230a19d86f15e175a
https://github.com/scummvm/scummvm/commit/cd3be9ac18fa4231c15fd20230a19d86f15e175a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Remove Score::_channelData. We now read frames dynamically
Changed paths:
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index dcbbf6d94b7..c99e4eb72af 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1392,8 +1392,6 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// partically by channels, hence we keep it and read the score from left to right
// TODO Merge it with shared cast
- memset(_channelData, 0, kChannelDataSize);
-
_currentFrame = new Frame(this, _numChannelsDisplayed);
// This makes all indexing simpler
@@ -1414,8 +1412,6 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
- memset(_channelData, 0, kChannelDataSize); // Reset channel data
-
_currentFrame->reset();
loadFrame(1);
@@ -1470,8 +1466,6 @@ void Score::rebuildChannelData(int frameNum) {
return;
}
- memset(_channelData, 0, kChannelDataSize);
-
// Lock variables
int curFrameNumber = _curFrameNumber;
@@ -1522,10 +1516,6 @@ bool Score::readOneFrame() {
debugC(4, kDebugLoading, "%s", _currentFrame->formatChannelInfo().c_str());
}
- //Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(_channelData, ARRAYSIZE(_channelData), _framesStream->isBE());
- // str->hexdump(str->size(), 32);
- //frame->readChannels(str, _version);
- //delete str;
// Precache the current FPS tempo, as this carries forward to frames to the right
// of the instruction
// Delay type tempos (e.g. wait commands, delays) apply to only a single frame, and are ignored here
@@ -1562,15 +1552,12 @@ Frame *Score::getFrameData(int frameNum){
int curFrameNumber = _curFrameNumber;
Frame *frame = _currentFrame;
_currentFrame = nullptr; // To avoid later deletion of frame inside renderOneFrame()
- byte channelData[kChannelDataSize];
- memcpy(channelData, _channelData, kChannelDataSize);
bool isFrameRead = loadFrame(frameNum);
// Start restoring all states
_curFrameNumber = curFrameNumber;
_currentFrame = frame;
- memcpy(_channelData, channelData, kChannelDataSize);
if (isFrameRead) {
return _currentFrame;
diff --git a/engines/director/score.h b/engines/director/score.h
index 7ed1218633e..939b6a6a6fd 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -160,7 +160,6 @@ public:
uint32 _numFrames;
uint32 _framesVersion;
uint32 _numChannels;
- byte _channelData[kChannelDataSize];
uint8 _currentTempo;
CastMemberID _currentPaletteId;
Commit: 5d13fc92d20260be111397ad36ac1853db7a1650
https://github.com/scummvm/scummvm/commit/5d13fc92d20260be111397ad36ac1853db7a1650
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Improve debug output
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index c99e4eb72af..9c0c87c73d2 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1490,7 +1490,7 @@ bool Score::readOneFrame() {
uint16 frameSize = _framesStream->readUint16();
assert(frameSize < _framesStreamSize);
- debugC(3, kDebugLoading, "++++++++++ score load frame (frameSize %d) saveOffset", frameSize);
+ debugC(3, kDebugLoading, "++++++++++ score load frame %d (frameSize %d) saveOffset", _curFrameNumber, frameSize);
if (debugChannelSet(8, kDebugLoading)) {
_framesStream->hexdump(frameSize);
}
Commit: 6c179cd21330d5788ff7cbd9d9809db2a1bd35eb
https://github.com/scummvm/scummvm/commit/6c179cd21330d5788ff7cbd9d9809db2a1bd35eb
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: D5 score loading fixes
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index a34915a8b64..48011824ebc 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -118,6 +118,8 @@ Frame::~Frame() {
}
void Frame::readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size, uint16 version) {
+ debugC(6, kDebugLoading, "Frame::readChannel(..., offset=%d, size=%d, version=%x)", offset, size, version);
+
if (version < kFileVer400) {
readChannelD2(stream, offset, size);
} else if (version >= kFileVer400 && version < kFileVer500) {
@@ -723,7 +725,7 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
}
uint16 finishPosition = offset + size;
- byte unk[5];
+ byte unk[12];
while (offset < finishPosition) {
switch (offset) {
@@ -735,6 +737,12 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
}
offset += 4;
break;
+ case 2: {
+ uint16 actionId = stream.readUint16();
+ _actionId = CastMemberID(actionId, _actionId.castLib); // Read castLinb from previous frame
+ }
+ offset += 2;
+ break;
case 4: {
uint16 sound1CastLib = stream.readUint16();
uint16 sound1Id = stream.readUint16();
@@ -757,9 +765,14 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
offset += 4;
break;
case 16:
- stream.read(unk, 5);
- warning("Frame::readMainChannelsD5(): STUB: unk1: 0x%x 0x%x 0x%x 0x%x 0x%x", unk[0], unk[1], unk[2], unk[3], unk[4]);
- offset += 5;
+ stream.read(unk, 4);
+ warning("Frame::readMainChannelsD5(): STUB: unk1: 0x%02x 0x%02x 0x%02x 0x%02x", unk[0], unk[1], unk[2], unk[3]);
+ offset += 4;
+ break;
+ case 20:
+ stream.read(unk, 1);
+ warning("Frame::readMainChannelsD5(): STUB: unk2: 0x%02x", unk[0]);
+ offset++;
break;
case 21:
_tempo = stream.readByte();
@@ -767,11 +780,11 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
break;
case 22:
stream.read(unk, 2);
- warning("Frame::readMainChannelsD5(): STUB: unk2: 0x%x 0x%x", unk[0], unk[1]);
+ warning("Frame::readMainChannelsD5(): STUB: unk3: 0x%02x 0x%02x", unk[0], unk[1]);
offset += 2;
break;
case 24: {
- // palette, 14 (26?) bytes
+ // palette, 12 (24?) bytes
int16 paletteCastLib = stream.readSint16();
int16 paletteId = stream.readSint16(); // 26
_palette.paletteId = CastMemberID(paletteId, paletteCastLib);
@@ -788,9 +801,19 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 31
_palette.frameCount = stream.readUint16(); // 32
_palette.cycleCount = stream.readUint16(); // 34
+ }
+ offset += 12;
+ break;
+ case 36: {
stream.read(unk, 12);
+
+ Common::String s;
+ for (int i = 0; i < 12; i++)
+ s += Common::String::format("0x%02x ", unk[i]);
+
+ warning("Frame::readMainChannelsD5(): STUB: unk4: %s", s.c_str());
}
- offset += 14 + 12;
+ offset += 12;
break;
case 48:
break;
@@ -849,6 +872,12 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
}
fieldPosition += 4;
break;
+ case 4: {
+ uint16 memberID = stream.readUint16();
+ sprite._castId = CastMemberID(memberID, sprite._castId.castLib); // Read castLinb from previous frame
+ }
+ fieldPosition += 2;
+ break;
case 6: {
uint16 scriptCastLib = stream.readUint16();
uint16 scriptMemberID = stream.readUint16();
Commit: e59fe04d0f9f4818ad36474b84454e4f7382723a
https://github.com/scummvm/scummvm/commit/e59fe04d0f9f4818ad36474b84454e4f7382723a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Added sanity checks to frame loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 48011824ebc..98bc72a8275 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -268,11 +268,17 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
case 32:
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readMainChannelsD2(): Miscomputed field position: %d", offset);
break;
}
}
+ if (offset > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readMainChannelsD2(): Read %d extra bytes", offset - finishPosition);
+ }
+
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
_transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
}
@@ -365,10 +371,16 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
fieldPosition = finishPosition;
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readSpriteD2(): Miscomputed field position: %d", fieldPosition);
}
}
+ if (fieldPosition > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readSpriteD2(): Read %d extra bytes", fieldPosition - finishPosition);
+ }
+
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
@@ -559,11 +571,17 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
case 40:
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readMainChannelsD4(): Miscomputed field position: %d", offset);
break;
}
}
+ if (offset > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readMainChannelsD4(): Read %d extra bytes", offset - finishPosition);
+ }
+
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
_transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
}
@@ -675,10 +693,16 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
fieldPosition = finishPosition;
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readSpriteD4(): Miscomputed field position: %d", fieldPosition);
}
}
+ if (fieldPosition > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readSpriteD4(): Read %d extra bytes", fieldPosition - finishPosition);
+ }
+
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
@@ -818,11 +842,17 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
case 48:
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readMainChannelsD5(): Miscomputed field position: %d", offset);
break;
}
}
+ if (offset > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readMainChannelsD5(): Read %d extra bytes", offset - finishPosition);
+ }
+
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
_transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
}
@@ -940,10 +970,16 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
fieldPosition = finishPosition;
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readSpriteD5(): Miscomputed field position: %d", fieldPosition);
}
}
+ if (fieldPosition > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readSpriteD5(): Read %d extra bytes", fieldPosition - finishPosition);
+ }
+
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
@@ -1094,10 +1130,16 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
fieldPosition = finishPosition;
break;
default:
+ // This means that a `case` label has to be split at this position
error("Frame::readSpriteD6(): Miscomputed field position: %d", fieldPosition);
}
}
+ if (fieldPosition > finishPosition) {
+ // This means that the relevant `case` label reads too many bytes and must be split
+ error("Frame::readSpriteD6(): Read %d extra bytes", fieldPosition - finishPosition);
+ }
+
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
Commit: f04dc8b10560f8a947d5de86f7fa933320ddbb1a
https://github.com/scummvm/scummvm/commit/f04dc8b10560f8a947d5de86f7fa933320ddbb1a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: More splits for D5 channel loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 98bc72a8275..a34b4089bc3 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -763,7 +763,7 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
break;
case 2: {
uint16 actionId = stream.readUint16();
- _actionId = CastMemberID(actionId, _actionId.castLib); // Read castLinb from previous frame
+ _actionId = CastMemberID(actionId, _actionId.castLib); // Inherit castLinb from previous frame
}
offset += 2;
break;
@@ -774,6 +774,12 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
}
offset += 4;
break;
+ case 6: {
+ uint16 sound1Id = stream.readUint16();
+ _sound1 = CastMemberID(sound1Id, _sound1.castLib); // Inherit castLinb from previous frame
+ }
+ offset += 2;
+ break;
case 8: {
uint16 sound2CastLib = stream.readUint16();
uint16 sound2Id = stream.readUint16();
@@ -781,6 +787,12 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
}
offset += 4;
break;
+ case 10: {
+ uint16 sound2Id = stream.readUint16();
+ _sound2 = CastMemberID(sound2Id, _sound2.castLib); // Inherit castLinb from previous frame
+ }
+ offset += 2;
+ break;
case 12: {
uint16 transCastLib = stream.readUint16();
uint16 transId = stream.readUint16();
@@ -808,25 +820,35 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
offset += 2;
break;
case 24: {
- // palette, 12 (24?) bytes
int16 paletteCastLib = stream.readSint16();
int16 paletteId = stream.readSint16(); // 26
_palette.paletteId = CastMemberID(paletteId, paletteCastLib);
-
- _palette.speed = stream.readByte(); // 28
- _palette.flags = stream.readByte(); // 29
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 30
- _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 31
- _palette.frameCount = stream.readUint16(); // 32
- _palette.cycleCount = stream.readUint16(); // 34
}
- offset += 12;
+ offset += 4;
+ break;
+ case 28:
+ _palette.speed = stream.readByte(); // 28
+ _palette.flags = stream.readByte(); // 29
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ offset += 2;
+ break;
+ case 30:
+ _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 30
+ _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 31
+ offset += 2;
+ break;
+ case 32:
+ _palette.frameCount = stream.readUint16(); // 32
+ offset += 2;
+ break;
+ case 34:
+ _palette.cycleCount = stream.readUint16(); // 34
+ offset += 2;
break;
case 36: {
stream.read(unk, 12);
@@ -904,7 +926,7 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 4: {
uint16 memberID = stream.readUint16();
- sprite._castId = CastMemberID(memberID, sprite._castId.castLib); // Read castLinb from previous frame
+ sprite._castId = CastMemberID(memberID, sprite._castId.castLib); // Inherit castLinb from previous frame
}
fieldPosition += 2;
break;
@@ -915,6 +937,12 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
}
fieldPosition += 4;
break;
+ case 8: {
+ uint16 scriptMemberID = stream.readUint16();
+ sprite._scriptId = CastMemberID(scriptMemberID, sprite._scriptId.castLib); // Inherit castLinb from previous frame
+ }
+ fieldPosition += 2;
+ break;
case 10:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
fieldPosition++;
Commit: 564482ac8f22b48e369788259957b7a37143c9f6
https://github.com/scummvm/scummvm/commit/564482ac8f22b48e369788259957b7a37143c9f6
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Remove now obsolete Frame::readChannels()
Changed paths:
engines/director/frame.cpp
engines/director/frame.h
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index a34b4089bc3..985670701a2 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -1174,312 +1174,6 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
sprite._width = sprite._height = 0;
}
-void Frame::readChannels(Common::SeekableReadStreamEndian *stream, uint16 version) {
- byte unk[24];
-
- if (version < kFileVer400) {
- // Sound/Tempo/Transition
- _actionId = CastMemberID(stream->readByte(), DEFAULT_CAST_LIB);
- _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
-
- if (transFlags & 0x80)
- _transArea = 1;
- else
- _transArea = 0;
- _transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
-
- _transChunkSize = stream->readByte();
- _tempo = stream->readByte();
- _transType = static_cast<TransitionType>(stream->readByte());
- _sound1 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream->readByte();
-
- _skipFrameFlag = stream->readByte();
- _blend = stream->readByte();
-
- if (_vm->getPlatform() == Common::kPlatformWindows) {
- _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream->readByte();
- } else {
- stream->read(unk, 3);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
- }
-
- // palette
- int16 paletteId = stream->readSint16();
- if (paletteId == 0) {
- _palette.paletteId = CastMemberID(0, 0);
- } else if (paletteId < 0) {
- _palette.paletteId = CastMemberID(paletteId, -1);
- } else {
- _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
- }
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream->readByte() ^ 0x80);
- _palette.lastColor = g_director->transformColor(stream->readByte() ^ 0x80);
- _palette.flags = stream->readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream->readByte();
- _palette.frameCount = stream->readUint16();
- _palette.cycleCount = stream->readUint16();
-
- stream->read(unk, 6);
-
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
- unk[1], unk[2], unk[3], unk[4], unk[5]);
- } else if (version >= kFileVer400 && version < kFileVer500) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readChannels(): 40 byte header");
- stream->hexdump(40);
- }
- // Sound/Tempo/Transition
- int unk1 = stream->readByte();
- if (unk1) {
- warning("Frame::readChannels(): STUB: unk1: %d 0x%x", unk1, unk1);
- }
- _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
-
- if (transFlags & 0x80)
- _transArea = 1;
- else
- _transArea = 0;
- _transDuration = (transFlags & 0x7f) * 250; // Duration is 1/4 secs
-
- _transChunkSize = stream->readByte();
- _tempo = stream->readByte();
- _transType = static_cast<TransitionType>(stream->readByte());
- _sound1 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
-
- _sound2 = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream->readByte();
-
- _skipFrameFlag = stream->readByte();
- _blend = stream->readByte();
-
- _colorTempo = stream->readByte();
- _colorSound1 = stream->readByte();
- _colorSound2 = stream->readByte();
-
- _actionId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
-
- _colorScript = stream->readByte();
- _colorTrans = stream->readByte();
-
- // palette
- int16 paletteId = stream->readSint16();
- if (paletteId == 0) {
- _palette.paletteId = CastMemberID(0, 0);
- } else if (paletteId < 0) {
- _palette.paletteId = CastMemberID(paletteId, -1);
- } else {
- _palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
- }
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.lastColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.flags = stream->readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream->readByte();
- _palette.frameCount = stream->readUint16();
- _palette.cycleCount = stream->readUint16();
- _palette.fade = stream->readByte();
- _palette.delay = stream->readByte();
- _palette.style = stream->readByte();
-
-
- unk1 = stream->readByte();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk2: %d 0x%x", unk1, unk1);
- unk1 = stream->readUint16();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk3: %d 0x%x", unk1, unk1);
- unk1 = stream->readUint16();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk4: %d 0x%x", unk1, unk1);
-
- _palette.colorCode = stream->readByte();
-
- unk1 = stream->readByte();
- if (unk1)
- warning("Frame::readChannels(): STUB: unk5: %d 0x%x", unk1, unk1);
-
- } else if (version >= kFileVer500 && version < kFileVer600) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readChannels(): 48 byte header");
- stream->hexdump(48);
- }
- // Sound/Tempo/Transition channel
- uint16 actionCastLib = stream->readUint16();
- uint16 actionId = stream->readUint16();
- _actionId = CastMemberID(actionId, actionCastLib);
- uint16 sound1CastLib = stream->readUint16();
- uint16 sound1Id = stream->readUint16();
- _sound1 = CastMemberID(sound1Id, sound1CastLib);
- uint16 sound2CastLib = stream->readUint16();
- uint16 sound2Id = stream->readUint16();
- _sound2 = CastMemberID(sound2Id, sound2CastLib);
- uint16 transCastLib = stream->readUint16();
- uint16 transId = stream->readUint16();
- _trans = CastMemberID(transId, transCastLib);
-
- stream->read(unk, 5);
-
- _tempo = stream->readByte();
-
- stream->read(unk, 2);
-
- // palette
- int16 paletteCastLib = stream->readSint16();
- int16 paletteId = stream->readSint16();
- _palette.paletteId = CastMemberID(paletteId, paletteCastLib);
- _palette.speed = stream->readByte();
- _palette.flags = stream->readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.firstColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.lastColor = g_director->transformColor(stream->readByte() + 0x80);
- _palette.frameCount = stream->readUint16();
- _palette.cycleCount = stream->readUint16();
- stream->read(unk, 12);
- }
-
- _transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
- _transDuration = CLIP<uint16>(_transDuration, 0, 32000); // restrict to 32 secs
-
- for (int i = 0; i < _numChannels; i++) {
- Sprite &sprite = *_sprites[i + 1];
-
- if (version < kFileVer500) {
- if (debugChannelSet(8, kDebugLoading)) {
- debugC(8, kDebugLoading, "Frame::readChannels(): channel %d, 22 bytes", i);
- stream->hexdump(22);
- }
- sprite._scriptId = CastMemberID(stream->readByte(), DEFAULT_CAST_LIB);
- sprite._spriteType = (SpriteType)stream->readByte();
- sprite._enabled = sprite._spriteType != kInactiveSprite;
- if (version >= kFileVer400) {
- sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
- sprite._backColor = _vm->transformColor((uint8)stream->readByte());
- } else {
- // Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
- sprite._foreColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
- sprite._backColor = _vm->transformColor((128 + stream->readByte()) & 0xff);
- }
-
- sprite._thickness = stream->readByte();
- sprite._inkData = stream->readByte();
-
- if (sprite.isQDShape()) {
- sprite._pattern = stream->readUint16();
- } else {
- sprite._castId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- }
-
- sprite._startPoint.y = (int16)stream->readUint16();
- sprite._startPoint.x = (int16)stream->readUint16();
-
- sprite._height = (int16)stream->readUint16();
- sprite._width = (int16)stream->readUint16();
-
- if (version >= kFileVer400) {
- sprite._scriptId = CastMemberID(stream->readUint16(), DEFAULT_CAST_LIB);
- // & 0x0f scorecolor
- // 0x10 forecolor is rgb
- // 0x20 bgcolor is rgb
- // 0x40 editable
- // 0x80 moveable
- sprite._colorcode = stream->readByte();
- sprite._blendAmount = stream->readByte();
- }
- } else if (version >= kFileVer500 && version < kFileVer600) {
- sprite._spriteType = (SpriteType)stream->readByte();
- sprite._inkData = stream->readByte();
-
- uint16 castLib = stream->readUint16();
- uint16 memberID = stream->readUint16();
- sprite._castId = CastMemberID(memberID, castLib);
-
- uint16 scriptCastLib = stream->readUint16();
- uint16 scriptMemberID = stream->readUint16();
- sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
-
- sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
- sprite._backColor = _vm->transformColor((uint8)stream->readByte());
-
- sprite._startPoint.y = (int16)stream->readUint16();
- sprite._startPoint.x = (int16)stream->readUint16();
-
- sprite._height = (int16)stream->readUint16();
- sprite._width = (int16)stream->readUint16();
-
- sprite._colorcode = stream->readByte();
- sprite._blendAmount = stream->readByte();
- sprite._thickness = stream->readByte();
- stream->readByte(); // unused
- } else if (version >= kFileVer600 && version < kFileVer700) {
- sprite._spriteType = (SpriteType)stream->readByte();
- sprite._inkData = stream->readByte();
-
- sprite._foreColor = _vm->transformColor((uint8)stream->readByte());
- sprite._backColor = _vm->transformColor((uint8)stream->readByte());
-
- uint16 castLib = stream->readUint16();
- uint16 memberID = stream->readUint16();
- sprite._castId = CastMemberID(memberID, castLib);
-
- /* uint32 spriteId = */stream->readUint32();
-
- sprite._startPoint.y = (int16)stream->readUint16();
- sprite._startPoint.x = (int16)stream->readUint16();
-
- sprite._height = (int16)stream->readUint16();
- sprite._width = (int16)stream->readUint16();
-
- sprite._colorcode = stream->readByte();
- sprite._blendAmount = stream->readByte();
- sprite._thickness = stream->readByte();
- stream->readByte(); // unused
- }
-
- // Sometimes removed sprites leave garbage in the channel
- // We set it to zero, so then could skip
- if (sprite._width <= 0 || sprite._height <= 0)
- sprite._width = sprite._height = 0;
-
- sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
- sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
- sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
-
- if (sprite._inkData & 0x40)
- sprite._trails = 1;
- else
- sprite._trails = 0;
-
- sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
- }
-
- if (debugChannelSet(4, kDebugLoading)) {
- debugC(4, kDebugLoading, "%s", formatChannelInfo().c_str());
- }
-}
-
Common::String Frame::formatChannelInfo() {
Common::String result;
result += Common::String::format("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d\n",
diff --git a/engines/director/frame.h b/engines/director/frame.h
index b29d836c7a1..c14b953ab4a 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -94,7 +94,6 @@ public:
Score *getScore() const { return _score; }
- void readChannels(Common::SeekableReadStreamEndian *stream, uint16 version);
void readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size, uint16 version);
void executeImmediateScripts();
Commit: 00cacd4fdbfa3dcdf13ad7e230fb8af41faf8e4d
https://github.com/scummvm/scummvm/commit/00cacd4fdbfa3dcdf13ad7e230fb8af41faf8e4d
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Split more D4 channel loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 985670701a2..1205eb06277 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -521,24 +521,33 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
} else {
_palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
}
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
- _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
- _palette.flags = stream.readByte(); // 24
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream.readByte(); // 25
- _palette.frameCount = stream.readUint16(); // 26
- _palette.cycleCount = stream.readUint16(); // 28
- _palette.fade = stream.readByte(); // 30
- _palette.delay = stream.readByte(); // 31
- _palette.style = stream.readByte(); // 32
}
- offset += 13;
+ offset += 2;
+ break;
+ case 22:
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
+ _palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
+ offset += 2;
+ break;
+ case 24:
+ _palette.flags = stream.readByte(); // 24
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream.readByte(); // 25
+ _palette.frameCount = stream.readUint16(); // 26
+ _palette.cycleCount = stream.readUint16(); // 28
+ offset += 6;
+ break;
+ case 30:
+ _palette.fade = stream.readByte(); // 30
+ _palette.delay = stream.readByte(); // 31
+ _palette.style = stream.readByte(); // 32
+ offset += 3;
break;
case 33:
unk1 = stream.readByte();
Commit: 85c11d9b5a1d03a0913be21e7ad67f38af1c61e2
https://github.com/scummvm/scummvm/commit/85c11d9b5a1d03a0913be21e7ad67f38af1c61e2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: More channel loading split
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 1205eb06277..b6ae77cdf4e 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -243,27 +243,41 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
} else {
_palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
}
-
- // loop points for color cycling
- _palette.firstColor = g_director->transformColor(stream.readByte() ^ 0x80);
- _palette.lastColor = g_director->transformColor(stream.readByte() ^ 0x80);
- _palette.flags = stream.readByte();
- _palette.colorCycling = (_palette.flags & 0x80) != 0;
- _palette.normal = (_palette.flags & 0x60) == 0x00;
- _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
- _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
- _palette.autoReverse = (_palette.flags & 0x10) != 0;
- _palette.overTime = (_palette.flags & 0x04) != 0;
- _palette.speed = stream.readByte();
- _palette.frameCount = stream.readUint16();
- _palette.cycleCount = stream.readUint16();
-
- stream.read(unk, 6);
-
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
- unk[1], unk[2], unk[3], unk[4], unk[5]);
}
- offset += 16;
+ offset += 2;
+ break;
+ case 18:
+ // loop points for color cycling
+ _palette.firstColor = g_director->transformColor(stream.readByte() ^ 0x80);
+ _palette.lastColor = g_director->transformColor(stream.readByte() ^ 0x80);
+ offset += 2;
+ break;
+ case 20:
+ _palette.flags = stream.readByte();
+ _palette.colorCycling = (_palette.flags & 0x80) != 0;
+ _palette.normal = (_palette.flags & 0x60) == 0x00;
+ _palette.fadeToBlack = (_palette.flags & 0x60) == 0x60;
+ _palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
+ _palette.autoReverse = (_palette.flags & 0x10) != 0;
+ _palette.overTime = (_palette.flags & 0x04) != 0;
+ _palette.speed = stream.readByte();
+ offset += 2;
+ break;
+ case 22:
+ _palette.frameCount = stream.readUint16();
+ offset += 2;
+ break;
+ case 24:
+ _palette.cycleCount = stream.readUint16();
+ offset += 2;
+ break;
+ case 26:
+ stream.read(unk, 6);
+
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
+ unk[1], unk[2], unk[3], unk[4], unk[5]);
+
+ offset += 6;
break;
case 32:
break;
@@ -539,9 +553,15 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.autoReverse = (_palette.flags & 0x10) != 0;
_palette.overTime = (_palette.flags & 0x04) != 0;
_palette.speed = stream.readByte(); // 25
+ offset += 2;
+ break;
+ case 26:
_palette.frameCount = stream.readUint16(); // 26
+ offset += 2;
+ break;
+ case 28:
_palette.cycleCount = stream.readUint16(); // 28
- offset += 6;
+ offset += 2;
break;
case 30:
_palette.fade = stream.readByte(); // 30
@@ -572,10 +592,10 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
offset++;
break;
case 39:
- unk1 = stream.readUint16();
+ unk1 = stream.readByte();
if (unk1)
- warning("Frame::readMainChannelsD4(): STUB: unk5: %d 0x%x", unk1, unk1);
- offset += 2;
+ warning("Frame::readMainChannelsD4(): STUB: unk5: 0x%02x", unk1);
+ offset++;
break;
case 40:
break;
Commit: 7a4456785b528007dccd6f0e3ad0deb2818ff4f0
https://github.com/scummvm/scummvm/commit/7a4456785b528007dccd6f0e3ad0deb2818ff4f0
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Split D2 channel loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index b6ae77cdf4e..cf8ba3f2e72 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -224,14 +224,14 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
offset++;
break;
case 13:
- if (_vm->getPlatform() == Common::kPlatformWindows) {
- _sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- _soundType2 = stream.readByte();
- } else {
- stream.read(unk, 3);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x", unk[0], unk[1], unk[2]);
- }
- offset += 3;
+ stream.read(unk, 1);
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: 0x%02x", unk[0]);
+ offset++;
+ break;
+ case 14:
+ stream.read(unk, 2);
+ debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk2: 0x%02x 0x%02x", unk[0], unk[1]);
+ offset += 2;
break;
case 16: {
// palette
Commit: 582c6731932da18567570d32396a75d8d734e89c
https://github.com/scummvm/scummvm/commit/582c6731932da18567570d32396a75d8d734e89c
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Optimize frameOffsets calculation
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 9c0c87c73d2..0caf58d6c23 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1407,8 +1407,14 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Pre-computing number of frames, as sometimes the frameNumber in stream mismatches
debugC(1, kDebugLoading, "Score::loadFrames(): Precomputing total number of frames!");
- // Calculate number of frames beforehand
- for (_numFrames = 1; loadFrame(_numFrames); _numFrames++) { }
+ // Calculate number of frames and their positions
+ // numOfFrames in the header is often incorrect
+ for (_numFrames = 1; loadFrame(_numFrames); _numFrames++) {
+ if (_framesStream->pos() < _framesStreamSize) {
+ // Record the starting offset for next frame
+ _frameOffsets.push_back(_framesStream->pos());
+ }
+ }
debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
@@ -1529,11 +1535,6 @@ bool Score::readOneFrame() {
_currentFrame->_scoreCachedPaletteId = _currentPaletteId;
debugC(8, kDebugLoading, "Score::readOneFrame(): Frame %d actionId: %s", _curFrameNumber, _currentFrame->_actionId.asString().c_str());
-
- if (_curFrameNumber == _frameOffsets.size() - 1 && _framesStream->pos() < _framesStreamSize) {
- // Record the starting offset for next frame
- _frameOffsets.push_back(_framesStream->pos());
- }
return true;
} else {
warning("Score::readOneFrame(): Zero sized frame!? exiting loop until we know what to do with the tags that follow.");
Commit: e0648bd308e7f8d655fad6d40eef70ea0a2d66b2
https://github.com/scummvm/scummvm/commit/e0648bd308e7f8d655fad6d40eef70ea0a2d66b2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Confirmed behaviour of immediateSprite and puppetSprite built-ins
Changed paths:
engines/director/lingo/lingo-builtins.cpp
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index ecb9838e800..e675af4a5b0 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2561,17 +2561,7 @@ void LB::b_immediateSprite(int nargs) {
Datum state = g_lingo->pop();
Datum sprite = g_lingo->pop();
- Sprite *sp = sc->getSpriteById(sprite.asInt());
if ((uint)sprite.asInt() < sc->_channels.size()) {
- if (sc->getNextFrame() && !sp->_immediate) {
- // same as puppetSprite
- // Channel *channel = sc->getChannelById(sprite.asInt());
- // channel->replaceSprite(sc->_frames[sc->getNextFrame()]->_sprites[sprite.asInt()]);
- // channel->_dirty = true;
-
- warning("STUB: LB::b_immediateSprite(): Fix logic here for next sprite");
- }
-
sc->getSpriteById(sprite.asInt())->_immediate = (bool)state.asInt();
} else {
warning("b_immediateSprite: sprite index out of bounds");
@@ -2602,19 +2592,8 @@ void LB::b_puppetSprite(int nargs) {
Datum state = g_lingo->pop();
Datum sprite = g_lingo->pop();
- Sprite *sp = sc->getSpriteById(sprite.asInt());
if ((uint)sprite.asInt() < sc->_channels.size()) {
- if (sc->getNextFrame() && !sp->_puppet) {
- // WORKAROUND: If a frame update is queued, update the sprite to the
- // sprite in new frame before setting puppet (Majestic).
- // Channel *channel = sc->getChannelById(sprite.asInt());
- // channel->replaceSprite(sc->_frames[sc->getNextFrame()]->_sprites[sprite.asInt()]);
- // channel->_dirty = true;
-
- warning("STUB: LB::b_puppetSprite(): Fix logic here for next sprite");
- }
-
- sc->getSpriteById(sprite.asInt())->_puppet = (bool)state.asInt();
+ sc->getSpriteById(sprite.asInt())->_puppet = (bool)state.asInt();
} else {
warning("b_puppetSprite: sprite index out of bounds");
}
Commit: 18ab952dd4a0d7b6ed5759585f0aec2fc6c22113
https://github.com/scummvm/scummvm/commit/18ab952dd4a0d7b6ed5759585f0aec2fc6c22113
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Added another patch for warlock-win
Changed paths:
engines/director/lingo/lingo-patcher.cpp
diff --git a/engines/director/lingo/lingo-patcher.cpp b/engines/director/lingo/lingo-patcher.cpp
index 21ce90c8cc9..27c1bd05863 100644
--- a/engines/director/lingo/lingo-patcher.cpp
+++ b/engines/director/lingo/lingo-patcher.cpp
@@ -89,6 +89,8 @@ struct ScriptPatch {
// Garbage at end of script
{"warlock", nullptr, kPlatformMacintosh, "DATA:BELSHAZZAR:STELLA:ORIGIN", kScoreScript, 12, DEFAULT_CAST_LIB,
2, "Frames 1 to 1", ""},
+ {"warlock", nullptr, kPlatformMacintosh, "DATA:BELSHAZZAR:STELLA:ORIGIN", kScoreScript, 13, DEFAULT_CAST_LIB,
+ 2, "Frames 1 to 1", ""},
// Garbage at end of script
{"warlock", nullptr, kPlatformMacintosh, "DATA:WARLOCKSHIP:HangHallAft", kScoreScript, 7, DEFAULT_CAST_LIB,
Commit: 013b8c30688136ec276346cada783ba442a1b711
https://github.com/scummvm/scummvm/commit/013b8c30688136ec276346cada783ba442a1b711
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Simplified offset calculation in channel loading
Changed paths:
engines/director/frame.cpp
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index cf8ba3f2e72..d47d371d322 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -166,19 +166,18 @@ void Frame::readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
}
void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
- uint16 finishPosition = offset + size;
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
byte unk[6];
- while (offset < finishPosition) {
- switch (offset) {
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + offset) {
case 0: // Sound/Tempo/Transition
_actionId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
- offset++;
break;
case 1:
// type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
_soundType1 = stream.readByte();
- offset++;
break;
case 2: {
// 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
@@ -188,50 +187,39 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
else
_transArea = 0;
_transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
- offset++;
}
break;
case 3:
_transChunkSize = stream.readByte();
- offset++;
break;
case 4:
_tempo = stream.readByte();
- offset++;
break;
case 5:
_transType = static_cast<TransitionType>(stream.readByte());
- offset++;
break;
case 6:
_sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
break;
case 8:
_sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
break;
case 10:
_soundType2 = stream.readByte();
- offset++;
break;
case 11:
_skipFrameFlag = stream.readByte();
- offset++;
break;
case 12:
_blend = stream.readByte();
- offset++;
break;
case 13:
stream.read(unk, 1);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: 0x%02x", unk[0]);
- offset++;
+ debugC(8, kDebugLoading, "Frame::readMainChannelsD2(): STUB: unk1: 0x%02x", unk[0]);
break;
case 14:
stream.read(unk, 2);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk2: 0x%02x 0x%02x", unk[0], unk[1]);
- offset += 2;
+ debugC(8, kDebugLoading, "Frame::readMainChannelsD2(): STUB: unk2: 0x%02x 0x%02x", unk[0], unk[1]);
break;
case 16: {
// palette
@@ -244,13 +232,11 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
}
}
- offset += 2;
break;
case 18:
// loop points for color cycling
_palette.firstColor = g_director->transformColor(stream.readByte() ^ 0x80);
_palette.lastColor = g_director->transformColor(stream.readByte() ^ 0x80);
- offset += 2;
break;
case 20:
_palette.flags = stream.readByte();
@@ -261,36 +247,31 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.autoReverse = (_palette.flags & 0x10) != 0;
_palette.overTime = (_palette.flags & 0x04) != 0;
_palette.speed = stream.readByte();
- offset += 2;
break;
case 22:
_palette.frameCount = stream.readUint16();
- offset += 2;
break;
case 24:
_palette.cycleCount = stream.readUint16();
- offset += 2;
break;
case 26:
stream.read(unk, 6);
- debugC(8, kDebugLoading, "Frame::readChannels(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
+ debugC(8, kDebugLoading, "Frame::readMainChannelsD2(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
unk[1], unk[2], unk[3], unk[4], unk[5]);
-
- offset += 6;
break;
case 32:
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readMainChannelsD2(): Miscomputed field position: %d", offset);
+ error("Frame::readMainChannelsD2(): Miscomputed field position: %ld", stream.pos() - initPos + offset);
break;
}
}
- if (offset > finishPosition) {
+ if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readMainChannelsD2(): Read %d extra bytes", offset - finishPosition);
+ error("Frame::readMainChannelsD2(): Read %ld extra bytes", stream.pos() - finishPosition);
}
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
@@ -302,7 +283,6 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint16 spriteStart = spritePosition * kSprChannelSizeD2 + kMainChannelSizeD2;
uint16 fieldPosition = offset - spriteStart;
- uint16 finishPosition = fieldPosition + size;
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readSpriteD2(): channel %d, 16 bytes", spritePosition);
@@ -318,35 +298,32 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
return;
}
- while (fieldPosition < finishPosition) {
- switch (fieldPosition) {
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
+
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + fieldPosition) {
case 0:
sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
- fieldPosition++;
break;
case 1:
sprite._spriteType = (SpriteType)stream.readByte();
- fieldPosition++;
sprite._enabled = sprite._spriteType != kInactiveSprite;
break;
case 2:
// Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
sprite._foreColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
- fieldPosition++;
break;
case 3:
// Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
sprite._backColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
- fieldPosition++;
break;
case 4:
sprite._thickness = stream.readByte();
- fieldPosition++;
break;
case 5:
sprite._inkData = stream.readByte();
- fieldPosition++;
sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
if (sprite._inkData & 0x40)
@@ -361,38 +338,33 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
} else {
sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
}
- fieldPosition += 2;
break;
case 8:
sprite._startPoint.y = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 10:
sprite._startPoint.x = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 12:
sprite._height = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 14:
sprite._width = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 16:
// end of channel, go to next sprite channel
- readSpriteD2(stream, spriteStart + kSprChannelSizeD2, finishPosition - fieldPosition);
+ readSpriteD2(stream, spriteStart + kSprChannelSizeD2, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readSpriteD2(): Miscomputed field position: %d", fieldPosition);
+ error("Frame::readSpriteD2(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
}
}
- if (fieldPosition > finishPosition) {
+ if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readSpriteD2(): Read %d extra bytes", fieldPosition - finishPosition);
+ error("Frame::readSpriteD2(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
@@ -441,22 +413,21 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
stream.hexdump(kMainChannelSizeD4);
}
- uint16 finishPosition = offset + size;
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
int unk1;
- while (offset < finishPosition) {
- switch (offset) {
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + offset) {
case 0:
// Sound/Tempo/Transition
unk1 = stream.readByte();
if (unk1) {
warning("Frame::readMainChannelsD4(): STUB: unk1: %d 0x%x", unk1, unk1);
}
- offset++;
break;
case 1:
_soundType1 = stream.readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
- offset++;
break;
case 2: {
uint8 transFlags = stream.readByte();
@@ -466,64 +437,48 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
_transArea = 0;
_transDuration = (transFlags & 0x7f) * 250; // Duration is in 1/4 secs
}
-
- offset++;
break;
case 3:
_transChunkSize = stream.readByte();
- offset++;
break;
case 4:
_tempo = stream.readByte();
- offset++;
break;
case 5:
_transType = static_cast<TransitionType>(stream.readByte());
- offset++;
break;
case 6:
_sound1 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
break;
case 8:
_sound2 = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
break;
case 10:
_soundType2 = stream.readByte();
- offset++;
break;
case 11:
_skipFrameFlag = stream.readByte();
- offset++;
break;
case 12:
_blend = stream.readByte();
- offset++;
break;
case 13:
_colorTempo = stream.readByte();
- offset++;
break;
case 14:
_colorSound1 = stream.readByte();
- offset++;
break;
case 15:
_colorSound2 = stream.readByte();
- offset++;
break;
case 16:
_actionId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- offset += 2;
break;
case 18:
_colorScript = stream.readByte();
- offset++;
break;
case 19:
_colorTrans = stream.readByte();
- offset++;
break;
case 20: {
// palette, 13 bytes
@@ -536,13 +491,11 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.paletteId = CastMemberID(paletteId, DEFAULT_CAST_LIB);
}
}
- offset += 2;
break;
case 22:
// loop points for color cycling
_palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 22
_palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 23
- offset += 2;
break;
case 24:
_palette.flags = stream.readByte(); // 24
@@ -553,62 +506,53 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.autoReverse = (_palette.flags & 0x10) != 0;
_palette.overTime = (_palette.flags & 0x04) != 0;
_palette.speed = stream.readByte(); // 25
- offset += 2;
break;
case 26:
_palette.frameCount = stream.readUint16(); // 26
- offset += 2;
break;
case 28:
_palette.cycleCount = stream.readUint16(); // 28
- offset += 2;
break;
case 30:
_palette.fade = stream.readByte(); // 30
_palette.delay = stream.readByte(); // 31
_palette.style = stream.readByte(); // 32
- offset += 3;
break;
case 33:
unk1 = stream.readByte();
if (unk1)
warning("Frame::readMainChannelsD4(): STUB: unk2: %d 0x%x", unk1, unk1);
- offset += 1;
break;
case 34:
unk1 = stream.readUint16();
if (unk1)
warning("Frame::readMainChannelsD4(): STUB: unk3: %d 0x%x", unk1, unk1);
- offset += 2;
break;
case 36:
unk1 = stream.readUint16();
if (unk1)
warning("Frame::readMainChannelsD4(): STUB: unk4: %d 0x%x", unk1, unk1);
- offset += 2;
break;
case 38:
_palette.colorCode = stream.readByte();
- offset++;
break;
case 39:
unk1 = stream.readByte();
if (unk1)
warning("Frame::readMainChannelsD4(): STUB: unk5: 0x%02x", unk1);
- offset++;
break;
case 40:
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readMainChannelsD4(): Miscomputed field position: %d", offset);
+ error("Frame::readMainChannelsD4(): Miscomputed field position: %ld", stream.pos() - initPos + offset);
break;
}
}
- if (offset > finishPosition) {
+ if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readMainChannelsD4(): Read %d extra bytes", offset - finishPosition);
+ error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
@@ -620,7 +564,6 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint16 spriteStart = spritePosition * kSprChannelSizeD4 + kMainChannelSizeD4;
uint16 fieldPosition = offset - spriteStart;
- uint16 finishPosition = fieldPosition + size;
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readSpriteD4(): channel %d, 20 bytes", spritePosition);
@@ -636,33 +579,30 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
return;
}
- while (fieldPosition < finishPosition) {
- switch (fieldPosition) {
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
+
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + fieldPosition) {
case 0:
sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
- fieldPosition++;
break;
case 1:
sprite._spriteType = (SpriteType)stream.readByte();
- fieldPosition++;
sprite._enabled = sprite._spriteType != kInactiveSprite;
break;
case 2:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
break;
case 3:
sprite._backColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
break;
case 4:
sprite._thickness = stream.readByte();
- fieldPosition++;
break;
case 5:
sprite._inkData = stream.readByte();
- fieldPosition++;
sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
if (sprite._inkData & 0x40)
@@ -677,27 +617,21 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
} else {
sprite._castId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
}
- fieldPosition += 2;
break;
case 8:
sprite._startPoint.y = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 10:
sprite._startPoint.x = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 12:
sprite._height = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 14:
sprite._width = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 16:
sprite._scriptId = CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB);
- fieldPosition += 2;
break;
case 18:
// & 0x0f scorecolor
@@ -706,7 +640,6 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
// 0x40 editable
// 0x80 moveable
sprite._colorcode = stream.readByte();
- fieldPosition++;
sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
@@ -714,22 +647,21 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 19:
sprite._blendAmount = stream.readByte();
- fieldPosition++;
break;
case 20:
// end of channel, go to next sprite channel
- readSpriteD4(stream, spriteStart + kSprChannelSizeD4, finishPosition - fieldPosition);
+ readSpriteD4(stream, spriteStart + kSprChannelSizeD4, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readSpriteD4(): Miscomputed field position: %d", fieldPosition);
+ error("Frame::readSpriteD4(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
}
}
- if (fieldPosition > finishPosition) {
+ if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readSpriteD4(): Read %d extra bytes", fieldPosition - finishPosition);
+ error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
@@ -777,83 +709,72 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
stream.hexdump(kMainChannelSizeD4);
}
- uint16 finishPosition = offset + size;
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
byte unk[12];
- while (offset < finishPosition) {
- switch (offset) {
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + offset) {
case 0: {
// Sound/Tempo/Transition
uint16 actionCastLib = stream.readUint16();
uint16 actionId = stream.readUint16();
_actionId = CastMemberID(actionId, actionCastLib);
}
- offset += 4;
break;
case 2: {
uint16 actionId = stream.readUint16();
_actionId = CastMemberID(actionId, _actionId.castLib); // Inherit castLinb from previous frame
}
- offset += 2;
break;
case 4: {
uint16 sound1CastLib = stream.readUint16();
uint16 sound1Id = stream.readUint16();
_sound1 = CastMemberID(sound1Id, sound1CastLib);
}
- offset += 4;
break;
case 6: {
uint16 sound1Id = stream.readUint16();
_sound1 = CastMemberID(sound1Id, _sound1.castLib); // Inherit castLinb from previous frame
}
- offset += 2;
break;
case 8: {
uint16 sound2CastLib = stream.readUint16();
uint16 sound2Id = stream.readUint16();
_sound2 = CastMemberID(sound2Id, sound2CastLib);
}
- offset += 4;
break;
case 10: {
uint16 sound2Id = stream.readUint16();
_sound2 = CastMemberID(sound2Id, _sound2.castLib); // Inherit castLinb from previous frame
}
- offset += 2;
break;
case 12: {
uint16 transCastLib = stream.readUint16();
uint16 transId = stream.readUint16();
_trans = CastMemberID(transId, transCastLib);
}
- offset += 4;
break;
case 16:
stream.read(unk, 4);
warning("Frame::readMainChannelsD5(): STUB: unk1: 0x%02x 0x%02x 0x%02x 0x%02x", unk[0], unk[1], unk[2], unk[3]);
- offset += 4;
break;
case 20:
stream.read(unk, 1);
warning("Frame::readMainChannelsD5(): STUB: unk2: 0x%02x", unk[0]);
- offset++;
break;
case 21:
_tempo = stream.readByte();
- offset++;
break;
case 22:
stream.read(unk, 2);
warning("Frame::readMainChannelsD5(): STUB: unk3: 0x%02x 0x%02x", unk[0], unk[1]);
- offset += 2;
break;
case 24: {
int16 paletteCastLib = stream.readSint16();
int16 paletteId = stream.readSint16(); // 26
_palette.paletteId = CastMemberID(paletteId, paletteCastLib);
}
- offset += 4;
break;
case 28:
_palette.speed = stream.readByte(); // 28
@@ -864,20 +785,16 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
_palette.fadeToWhite = (_palette.flags & 0x60) == 0x40;
_palette.autoReverse = (_palette.flags & 0x10) != 0;
_palette.overTime = (_palette.flags & 0x04) != 0;
- offset += 2;
break;
case 30:
_palette.firstColor = g_director->transformColor(stream.readByte() + 0x80); // 30
_palette.lastColor = g_director->transformColor(stream.readByte() + 0x80); // 31
- offset += 2;
break;
case 32:
_palette.frameCount = stream.readUint16(); // 32
- offset += 2;
break;
case 34:
_palette.cycleCount = stream.readUint16(); // 34
- offset += 2;
break;
case 36: {
stream.read(unk, 12);
@@ -888,20 +805,19 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
warning("Frame::readMainChannelsD5(): STUB: unk4: %s", s.c_str());
}
- offset += 12;
break;
case 48:
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readMainChannelsD5(): Miscomputed field position: %d", offset);
+ error("Frame::readMainChannelsD5(): Miscomputed field position: %ld", stream.pos() - initPos + offset);
break;
}
}
- if (offset > finishPosition) {
+ if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readMainChannelsD5(): Read %d extra bytes", offset - finishPosition);
+ error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
@@ -913,7 +829,6 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint16 spriteStart = spritePosition * kSprChannelSizeD5 + kMainChannelSizeD5;
uint16 fieldPosition = offset - spriteStart;
- uint16 finishPosition = fieldPosition + size;
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readSpriteD5(): channel %d, 20 bytes", spritePosition);
@@ -929,15 +844,16 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
return;
}
- while (fieldPosition < finishPosition) {
- switch (fieldPosition) {
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
+
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + fieldPosition) {
case 0:
sprite._spriteType = (SpriteType)stream.readByte();
- fieldPosition++;
break;
case 1:
sprite._inkData = stream.readByte();
- fieldPosition++;
sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
if (sprite._inkData & 0x40)
@@ -951,50 +867,40 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint16 memberID = stream.readUint16();
sprite._castId = CastMemberID(memberID, castLib);
}
- fieldPosition += 4;
break;
case 4: {
uint16 memberID = stream.readUint16();
sprite._castId = CastMemberID(memberID, sprite._castId.castLib); // Inherit castLinb from previous frame
}
- fieldPosition += 2;
break;
case 6: {
uint16 scriptCastLib = stream.readUint16();
uint16 scriptMemberID = stream.readUint16();
sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
}
- fieldPosition += 4;
break;
case 8: {
uint16 scriptMemberID = stream.readUint16();
sprite._scriptId = CastMemberID(scriptMemberID, sprite._scriptId.castLib); // Inherit castLinb from previous frame
}
- fieldPosition += 2;
break;
case 10:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
break;
case 11:
sprite._backColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
break;
case 12:
sprite._startPoint.y = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 14:
sprite._startPoint.x = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 16:
sprite._height = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 18:
sprite._width = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 20:
// & 0x0f scorecolor
@@ -1003,7 +909,6 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
// 0x40 editable
// 0x80 moveable
sprite._colorcode = stream.readByte();
- fieldPosition++;
sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
@@ -1011,30 +916,27 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 21:
sprite._blendAmount = stream.readByte();
- fieldPosition++;
break;
case 22:
sprite._thickness = stream.readByte();
- fieldPosition++;
break;
case 23:
(void)stream.readByte(); // unused
- fieldPosition++;
break;
case 24:
// end of channel, go to next sprite channel
- readSpriteD4(stream, spriteStart + kSprChannelSizeD5, finishPosition - fieldPosition);
+ readSpriteD5(stream, spriteStart + kSprChannelSizeD5, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readSpriteD5(): Miscomputed field position: %d", fieldPosition);
+ error("Frame::readSpriteD2(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
}
}
if (fieldPosition > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readSpriteD5(): Read %d extra bytes", fieldPosition - finishPosition);
+ error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
@@ -1085,7 +987,6 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint16 spriteStart = spritePosition * kSprChannelSizeD6 + kMainChannelSizeD6;
uint16 fieldPosition = offset - spriteStart;
- uint16 finishPosition = fieldPosition + size;
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readSpriteD6(): channel %d, 20 bytes", spritePosition);
@@ -1101,15 +1002,16 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
return;
}
- while (fieldPosition < finishPosition) {
- switch (fieldPosition) {
+ uint32 initPos = stream.pos();
+ uint32 finishPosition = initPos + size;
+
+ while (stream.pos() < finishPosition) {
+ switch (stream.pos() - initPos + fieldPosition) {
case 0:
sprite._spriteType = (SpriteType)stream.readByte();
- fieldPosition++;
break;
case 1:
sprite._inkData = stream.readByte();
- fieldPosition++;
sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
if (sprite._inkData & 0x40)
@@ -1120,41 +1022,33 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 2:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
break;
case 3:
sprite._backColor = _vm->transformColor((uint8)stream.readByte());
- fieldPosition++;
break;
case 4: {
uint16 castLib = stream.readUint16();
uint16 memberID = stream.readUint16();
sprite._castId = CastMemberID(memberID, castLib);
}
- fieldPosition += 4;
break;
case 8: {
uint16 scriptCastLib = stream.readUint16();
uint16 scriptMemberID = stream.readUint16();
sprite._scriptId = CastMemberID(scriptMemberID, scriptCastLib);
}
- fieldPosition += 4;
break;
case 12:
sprite._startPoint.y = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 14:
sprite._startPoint.x = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 16:
sprite._height = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 18:
sprite._width = (int16)stream.readUint16();
- fieldPosition += 2;
break;
case 20:
// & 0x0f scorecolor
@@ -1163,7 +1057,6 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
// 0x40 editable
// 0x80 moveable
sprite._colorcode = stream.readByte();
- fieldPosition++;
sprite._editable = ((sprite._colorcode & 0x40) == 0x40);
sprite._moveable = ((sprite._colorcode & 0x80) == 0x80);
@@ -1171,30 +1064,27 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 21:
sprite._blendAmount = stream.readByte();
- fieldPosition++;
break;
case 22:
sprite._thickness = stream.readByte();
- fieldPosition++;
break;
case 23:
(void)stream.readByte(); // unused
- fieldPosition++;
break;
case 24:
// end of channel, go to next sprite channel
- readSpriteD4(stream, spriteStart + kSprChannelSizeD5, finishPosition - fieldPosition);
+ readSpriteD6(stream, spriteStart + kSprChannelSizeD6, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
- error("Frame::readSpriteD6(): Miscomputed field position: %d", fieldPosition);
+ error("Frame::readSpriteD2(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
}
}
- if (fieldPosition > finishPosition) {
+ if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
- error("Frame::readSpriteD6(): Read %d extra bytes", fieldPosition - finishPosition);
+ error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
Commit: 64b315982569521c9fa4ac081c60d74e3e8a2f12
https://github.com/scummvm/scummvm/commit/64b315982569521c9fa4ac081c60d74e3e8a2f12
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Added forceredraw debugger command
Changed paths:
engines/director/debugger.cpp
engines/director/debugger.h
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 51afd87065a..8f7869c746a 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -25,6 +25,7 @@
#include "director/debugger.h"
#include "director/archive.h"
#include "director/cast.h"
+#include "director/channel.h"
#include "director/frame.h"
#include "director/movie.h"
#include "director/score.h"
@@ -103,6 +104,7 @@ Debugger::Debugger(): GUI::Debugger() {
registerCmd("bplist", WRAP_METHOD(Debugger, cmdBpList));
registerCmd("draw", WRAP_METHOD(Debugger, cmdDraw));
+ registerCmd("forceredraw", WRAP_METHOD(Debugger, cmdForceRedraw));
_nextFrame = false;
_nextFrameCounter = 0;
@@ -896,6 +898,36 @@ bool Debugger::cmdDraw(int argc, const char **argv) {
return true;
}
+static void forceWindowRedraw(Window *window) {
+ if (!window->getCurrentMovie())
+ return;
+
+ Score *score = window->getCurrentMovie()->getScore();
+
+ if (!score)
+ return;
+
+ for (uint16 c = 0; c < score->_channels.size(); c++)
+ score->_channels[c]->_dirty = true;
+}
+
+bool Debugger::cmdForceRedraw(int argc, const char **argv) {
+ forceWindowRedraw(g_director->getStage());
+
+ FArray *windowList = g_lingo->_windowList.u.farr;
+ for (uint i = 0; i < windowList->arr.size(); i++) {
+ if (windowList->arr[i].type != OBJECT || windowList->arr[i].u.obj->getObjType() != kWindowObj)
+ continue;
+
+ Window *window = static_cast<Window *>(windowList->arr[i].u.obj);
+
+ forceWindowRedraw(window);
+ }
+
+ debugPrintf("Requested full refresh\n");
+
+ return true;
+}
void Debugger::bpUpdateState() {
_bpCheckFunc = false;
diff --git a/engines/director/debugger.h b/engines/director/debugger.h
index 3242213ddbe..776bca2ff07 100644
--- a/engines/director/debugger.h
+++ b/engines/director/debugger.h
@@ -157,6 +157,7 @@ private:
bool cmdBpList(int argc, const char **argv);
bool cmdDraw(int argc, const char **argv);
+ bool cmdForceRedraw(int argc, const char **argv);
void bpUpdateState();
void bpTest(bool forceCheck = false);
Commit: 4a535f6b52c87490bd0c3d85343e4014f608468a
https://github.com/scummvm/scummvm/commit/4a535f6b52c87490bd0c3d85343e4014f608468a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Copy sprites from the channel to the current frame
This allows Lingo-modified properties to be modified further by Score
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 0caf58d6c23..7880d6b0a0d 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -510,6 +510,9 @@ void Score::update() {
// TODO: Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
}
+ for (uint ch = 0; ch < _channels.size(); ch++)
+ *_currentFrame->_sprites[ch] = *_channels[ch]->_sprite;
+
loadFrame(_curFrameNumber);
// Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
renderFrame(_curFrameNumber);
Commit: 4c27273b6071d5347d901809452734312e966ad7
https://github.com/scummvm/scummvm/commit/4c27273b6071d5347d901809452734312e966ad7
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2023-07-10T16:03:11+02:00
Commit Message:
DIRECTOR: Disable frame copying code and added puppet check to it
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 7880d6b0a0d..94c147c3442 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -510,8 +510,12 @@ void Score::update() {
// TODO: Director 6 step: send prepareFrame event to all sprites and the script channel in upcoming frame
}
+#if 0
+ // FIXME: TODO: This so far brings more problems than fixes
for (uint ch = 0; ch < _channels.size(); ch++)
- *_currentFrame->_sprites[ch] = *_channels[ch]->_sprite;
+ if (_channels[ch]->_sprite->_puppet || _channels[ch]->_sprite->_autoPuppet)
+ *_currentFrame->_sprites[ch] = *_channels[ch]->_sprite;
+#endif
loadFrame(_curFrameNumber);
// Window is drawn between the prepareFrame and enterFrame events (Lingo in a Nutshell, p.100)
More information about the Scummvm-git-logs
mailing list