Skip to content

Commit

Permalink
DIRECTOR: Add more palette transition modes
Browse files Browse the repository at this point in the history
  • Loading branch information
moralrecordings committed Aug 30, 2022
1 parent cd578a7 commit f4b93ec
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 7 deletions.
121 changes: 117 additions & 4 deletions engines/director/score.cpp
Expand Up @@ -59,6 +59,8 @@ Score::Score(Movie *movie) {
_puppetTempo = 0x00;
_puppetPalette = false;
_lastPalette = 0;
_paletteTransitionIndex = 0;
memset(_paletteSnapshotBuffer, 0, 768);

_labels = nullptr;

Expand Down Expand Up @@ -584,12 +586,29 @@ void Score::renderSprites(uint16 frameId, RenderMode mode) {
}

void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
if (_puppetPalette)
return;

// If the palette is defined in the frame and doesn't match
// the current one, set it
int currentPalette = _frames[frameId]->_palette.paletteId;
if (!_puppetPalette && currentPalette != _lastPalette && currentPalette) {
if (!currentPalette)
return;

bool paletteChanged = currentPalette != _lastPalette && currentPalette;
if (paletteChanged) {
_lastPalette = currentPalette;
g_director->setPalette(resolvePaletteId(currentPalette));
_paletteTransitionIndex = 0;
}

// For palette cycling, the only thing that is checked is if
// the palette ID is the same. Different cycling configs with
// the same palette ID will persist any mutated state.
// e.g. if you use overTime to cycle the palette partially
// through a cycle, then switch to doing a full color cycle
// on the same palette, it will not reset and the weird
// offset will remain.

// Cycle speed in FPS
int speed = _frames[frameId]->_palette.speed;
if (speed == 0)
Expand All @@ -600,15 +619,24 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
int firstColor = _frames[frameId]->_palette.firstColor;
int lastColor = _frames[frameId]->_palette.lastColor;
if (_frames[frameId]->_palette.colorCycling) {
// Cycle the colors of a chosen palette

// If we've just chosen this palette, set it immediately
if (paletteChanged)
g_director->setPalette(resolvePaletteId(currentPalette));

if (_frames[frameId]->_palette.overTime) {
// do a single color step in one frame transition
// Do a single color step in one frame transition
g_director->shiftPalette(firstColor, lastColor, false);
g_director->draw();
} else {
// do a full color cycle in one frame transition
// Do a full color cycle in one frame transition
int steps = firstColor - lastColor + 1;
for (int i = 0; i < _frames[frameId]->_palette.cycleCount; i++) {
for (int j = 0; j < steps; j++) {
g_director->shiftPalette(firstColor, lastColor, false);
g_director->draw();
// On click, stop loop and reset palette
if (_vm->processEvents(true)) {
g_director->setPalette(resolvePaletteId(currentPalette));
return;
Expand All @@ -619,6 +647,7 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
for (int j = 0; j < steps; j++) {
g_director->shiftPalette(firstColor, lastColor, true);
g_director->draw();
// On click, stop loop and reset palette
if (_vm->processEvents(true)) {
g_director->setPalette(resolvePaletteId(currentPalette));
return;
Expand All @@ -628,6 +657,90 @@ void Score::renderPaletteCycle(uint16 frameId, RenderMode mode) {
}
}
}
} else {
// Transition from the current palette to a new palette
PaletteV4 *destPal = g_director->getPalette(resolvePaletteId(currentPalette));
int frameCount = _frames[frameId]->_palette.frameCount;

if (_frames[frameId]->_palette.overTime) {
// Transition over a series of frames
if (_paletteTransitionIndex == 0) {
// Copy the current palette into the snapshot buffer
memset(_paletteSnapshotBuffer, 0, 768);
memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
}

byte calcPal[768];

if (_frames[frameId]->_palette.normal) {
// Fade the palette directly to the new palette
for (int i = 0; i < 768; i++) {
calcPal[i] = lerpByte(
_paletteSnapshotBuffer[i],
i < destPal->length * 3 ? destPal->palette[i] : 0,
_paletteTransitionIndex + 1,
frameCount
);
}
} else {
// Fade the palette to an intermediary color (black or white),
// then to the new palette
int fadeCutoff = 0;
int halfway = frameCount / 2;

// Palette indexes are in reverse order thanks to transformColor
if (_frames[frameId]->_palette.fadeToBlack) {
// Fade everything except color index 0 to black
fadeCutoff = 3;
} else if (_frames[frameId]->_palette.fadeToWhite) {
// Fade everything except color index 255 to white
fadeCutoff = 765;
}

if (_paletteTransitionIndex < halfway) {
for (int i = 0; i < fadeCutoff; i++) {
calcPal[i] = lerpByte(
_paletteSnapshotBuffer[i],
0,
_paletteTransitionIndex + 1,
halfway
);
}
for (int i = fadeCutoff; i < 768; i++) {
calcPal[i] = lerpByte(
_paletteSnapshotBuffer[i],
255,
_paletteTransitionIndex + 1,
halfway
);
}
} else {
for (int i = 0; i < fadeCutoff; i++) {
calcPal[i] = lerpByte(
0,
i < destPal->length * 3 ? destPal->palette[i] : 0,
_paletteTransitionIndex - halfway + 1,
frameCount - halfway
);
}
for (int i = fadeCutoff; i < 768; i++) {
calcPal[i] = lerpByte(
255,
i < destPal->length * 3 ? destPal->palette[i] : 0,
_paletteTransitionIndex - halfway + 1,
frameCount - halfway
);
}
}
}
g_director->setPalette(calcPal, 256);
_paletteTransitionIndex++;
_paletteTransitionIndex %= frameCount;
} else {
// Do a full cycle in one frame transition

}

}

}
Expand Down
2 changes: 2 additions & 0 deletions engines/director/score.h
Expand Up @@ -139,6 +139,8 @@ class Score {
byte _puppetTempo;
bool _puppetPalette;
int _lastPalette;
int _paletteTransitionIndex;
byte _paletteSnapshotBuffer[768];

PlayState _playState;
uint32 _nextFrameTime;
Expand Down
7 changes: 4 additions & 3 deletions engines/director/transitions.cpp
Expand Up @@ -143,9 +143,10 @@ void Window::stepTransition(TransParams &t, int step) {

if (t.sourcePal != t.targetPal) {
for (int i = 0; i < 768; i++) {
int sourceCol = (i < t.sourcePalLength * 3 ? t.sourcePal[i] : 0);
int targetCol = (i < t.targetPalLength * 3 ? t.targetPal[i] : 0);
t.tempPal[i] = static_cast<byte>((targetCol * step + sourceCol * (t.steps - step)) / t.steps);
t.tempPal[i] = lerpByte(
(i < t.sourcePalLength * 3 ? t.sourcePal[i] : 0),
(i < t.targetPalLength * 3 ? t.targetPal[i] : 0),
step, t.steps);
}
g_director->setPalette(t.tempPal, 256);
}
Expand Down
8 changes: 8 additions & 0 deletions engines/director/util.h
Expand Up @@ -101,6 +101,14 @@ Common::String utf8ToPrintable(const Common::String &str);

Common::String decodePlatformEncoding(Common::String input);

inline byte lerpByte(byte a, byte b, int alpha, int span) {
int ai = static_cast<int>(a);
int bi = static_cast<int>(b);
span = CLIP<int>(span, 1, span);
alpha = CLIP<int>(alpha, 0, span);
return static_cast<byte>((bi * alpha + ai * (span - alpha)) / span);
}

} // End of namespace Director

#endif

0 comments on commit f4b93ec

Please sign in to comment.