Implement palette fading

svn-id: r45455
This commit is contained in:
Robert Špalek 2009-10-28 07:34:17 +00:00
parent 4f5a99655c
commit c781f01321
7 changed files with 101 additions and 22 deletions

View file

@ -365,7 +365,7 @@ void DraciEngine::pauseEngineIntern(bool pause) {
// Adjust engine start time // Adjust engine start time
const int delta = _system->getMillis() - _pauseStartTime; const int delta = _system->getMillis() - _pauseStartTime;
_engineStartTime += delta / 1000; _engineStartTime += delta / 1000;
_game->shiftSpeechTick(delta); _game->shiftSpeechAndFadeTick(delta);
_pauseStartTime = 0; _pauseStartTime = 0;
} }
} }

View file

@ -165,6 +165,7 @@ void Game::init() {
setQuit(false); setQuit(false);
setExitLoop(false); setExitLoop(false);
_scheduledPalette = 0; _scheduledPalette = 0;
_fadePhases = _fadePhase = 0;
setLoopStatus(kStatusGate); setLoopStatus(kStatusGate);
setLoopSubstatus(kSubstatusOrdinary); setLoopSubstatus(kSubstatusOrdinary);
@ -239,6 +240,22 @@ void Game::loop() {
if (shouldExitLoop() > 1) // after loading if (shouldExitLoop() > 1) // after loading
break; break;
if (_fadePhase > 0 && (_vm->_system->getMillis() - _fadeTick) >= kFadingTimeUnit) {
_fadeTick = _vm->_system->getMillis();
--_fadePhase;
const BAFile *startPal = _vm->_paletteArchive->getFile(_currentRoom._palette);
const BAFile *endPal = getScheduledPalette() >= 0 ? _vm->_paletteArchive->getFile(getScheduledPalette()) : NULL;
_vm->_screen->interpolatePalettes(startPal->_data, endPal->_data, 0, kNumColours, _fadePhases - _fadePhase, _fadePhases);
if (_loopSubstatus == kSubstatusFade && _fadePhase == 0) {
setExitLoop(true);
// Rewrite the palette index of the current
// room. This is necessary when two fadings
// are called after each other, such as in the
// intro. We rely on that getScheduledPalette() >= 0.
_currentRoom._palette = getScheduledPalette();
}
}
// Fetch mouse coordinates // Fetch mouse coordinates
int x = _vm->_mouse->getPosX(); int x = _vm->_mouse->getPosX();
int y = _vm->_mouse->getPosY(); int y = _vm->_mouse->getPosY();
@ -1530,8 +1547,9 @@ void Game::setSpeechTiming(uint tick, uint duration) {
_speechDuration = duration; _speechDuration = duration;
} }
void Game::shiftSpeechTick(int delta) { void Game::shiftSpeechAndFadeTick(int delta) {
_speechTick += delta; _speechTick += delta;
_fadeTick += delta;
} }
int Game::getEscRoom() const { int Game::getEscRoom() const {
@ -1550,6 +1568,11 @@ int Game::getScheduledPalette() const {
return _scheduledPalette; return _scheduledPalette;
} }
void Game::initializeFading(int phases) {
_fadePhases = _fadePhase = phases;
_fadeTick = _vm->_system->getMillis();
}
/** /**
* The GPL command Mark sets the animation index (which specifies the order in which * The GPL command Mark sets the animation index (which specifies the order in which
* animations were loaded in) which is then used by the Release command to delete * animations were loaded in) which is then used by the Release command to delete

View file

@ -87,6 +87,11 @@ enum SpeechConstants {
kSpeechTimeUnit = 2640 kSpeechTimeUnit = 2640
}; };
// One fading phase is 50ms.
enum FadeConstants {
kFadingTimeUnit = 50
};
/** Inventory related magical constants */ /** Inventory related magical constants */
enum InventoryConstants { enum InventoryConstants {
kInventoryItemWidth = 25, kInventoryItemWidth = 25,
@ -330,7 +335,7 @@ public:
void setExitLoop(int exit) { _shouldExitLoop = exit; } void setExitLoop(int exit) { _shouldExitLoop = exit; }
void setSpeechTiming(uint tick, uint duration); void setSpeechTiming(uint tick, uint duration);
void shiftSpeechTick(int delta); void shiftSpeechAndFadeTick(int delta);
void updateTitle(); void updateTitle();
void updateCursor(); void updateCursor();
@ -360,6 +365,7 @@ public:
void schedulePalette(int paletteID); void schedulePalette(int paletteID);
int getScheduledPalette() const; int getScheduledPalette() const;
void initializeFading(int phases);
void DoSync(Common::Serializer &s); void DoSync(Common::Serializer &s);
@ -423,6 +429,9 @@ private:
int _markedAnimationIndex; ///< Used by the Mark GPL command int _markedAnimationIndex; ///< Used by the Mark GPL command
int _scheduledPalette; int _scheduledPalette;
int _fadePhases;
int _fadePhase;
uint _fadeTick;
}; };
} // End of namespace Draci } // End of namespace Draci

View file

@ -33,25 +33,18 @@ namespace Draci {
Screen::Screen(DraciEngine *vm) : _vm(vm) { Screen::Screen(DraciEngine *vm) : _vm(vm) {
_surface = new Surface(kScreenWidth, kScreenHeight); _surface = new Surface(kScreenWidth, kScreenHeight);
_palette = new byte[4 * kNumColours]; _palette = new byte[4 * kNumColours];
setPaletteEmpty(); _blackPalette = new byte[3 * kNumColours];
for (int i = 0; i < 3 * kNumColours; ++i) {
_blackPalette[i] = 0;
}
setPalette(NULL, 0, kNumColours);
this->clearScreen(); this->clearScreen();
} }
Screen::~Screen() { Screen::~Screen() {
delete _surface; delete _surface;
delete[] _palette; delete[] _palette;
} delete[] _blackPalette;
/**
* @brief Sets the first numEntries of palette to zero
* @param numEntries The number of entries to set to zero (from start)
*/
void Screen::setPaletteEmpty(uint numEntries) {
for (uint i = 0; i < 4 * numEntries; ++i) {
_palette[i] = 0;
}
_vm->_system->setPalette(_palette, 0, numEntries);
} }
/** /**
@ -61,7 +54,7 @@ void Screen::setPaletteEmpty(uint numEntries) {
* num Number of colours to replace * num Number of colours to replace
*/ */
void Screen::setPalette(const byte *data, uint16 start, uint16 num) { void Screen::setPalette(const byte *data, uint16 start, uint16 num) {
Common::MemoryReadStream pal(data, 3 * kNumColours); Common::MemoryReadStream pal(data ? data : _blackPalette, 3 * kNumColours);
pal.seek(start * 4); pal.seek(start * 4);
// Copy the palette // Copy the palette
@ -74,13 +67,40 @@ void Screen::setPalette(const byte *data, uint16 start, uint16 num) {
// TODO: Investigate why this is needed // TODO: Investigate why this is needed
// Shift the palette two bits to the left to make it brighter // Shift the palette two bits to the left to make it brighter
for (uint i = 0; i < 4 * kNumColours; ++i) { for (int i = start * 4; i < (start + num) * 4; ++i) {
_palette[i] <<= 2; _palette[i] <<= 2;
} }
_vm->_system->setPalette(_palette, start, num); _vm->_system->setPalette(_palette, start, num);
} }
void Screen::interpolatePalettes(const byte *first, const byte *second, uint16 start, uint16 num, int index, int number) {
Common::MemoryReadStream firstPal(first ? first : _blackPalette, 3 * kNumColours);
Common::MemoryReadStream secondPal(second ? second : _blackPalette, 3 * kNumColours);
firstPal.seek(start * 4);
secondPal.seek(start * 4);
// Interpolate the palettes
for (uint16 i = start; i < start + num; ++i) {
_palette[i * 4] = interpolate(firstPal.readByte(), secondPal.readByte(), index, number);
_palette[i * 4 + 1] = interpolate(firstPal.readByte(), secondPal.readByte(), index, number);
_palette[i * 4 + 2] = interpolate(firstPal.readByte(), secondPal.readByte(), index, number);
_palette[i * 4 + 3] = 0;
}
// TODO: Investigate why this is needed
// Shift the palette two bits to the left to make it brighter
for (int i = start * 4; i < (start + num) * 4; ++i) {
_palette[i] <<= 2;
}
_vm->_system->setPalette(_palette, start, num);
}
int Screen::interpolate(int first, int second, int index, int number) {
return (second * index + first * (number - index)) / number;
}
/** /**
* @brief Copies the current memory screen buffer to the real screen * @brief Copies the current memory screen buffer to the real screen
*/ */

View file

@ -46,8 +46,8 @@ public:
Screen(DraciEngine *vm); Screen(DraciEngine *vm);
~Screen(); ~Screen();
void setPaletteEmpty(uint numEntries = kNumColours);
void setPalette(const byte *data, uint16 start, uint16 num); void setPalette(const byte *data, uint16 start, uint16 num);
void interpolatePalettes(const byte *first, const byte *second, uint16 start, uint16 num, int index, int number);
const byte *getPalette() const; const byte *getPalette() const;
void copyToScreen(); void copyToScreen();
void clearScreen(); void clearScreen();
@ -56,8 +56,11 @@ public:
void drawRect(Common::Rect r, uint8 colour); void drawRect(Common::Rect r, uint8 colour);
private: private:
int interpolate(int first, int second, int index, int number);
Surface *_surface; Surface *_surface;
byte *_palette; byte *_palette;
byte *_blackPalette;
DraciEngine *_vm; DraciEngine *_vm;
}; };

View file

@ -64,8 +64,8 @@ void Script::setupCommandList() {
{ 11, 1, "LoadPalette", 1, { 2 }, &Script::loadPalette }, { 11, 1, "LoadPalette", 1, { 2 }, &Script::loadPalette },
{ 12, 1, "SetPalette", 0, { 0 }, &Script::setPalette }, { 12, 1, "SetPalette", 0, { 0 }, &Script::setPalette },
{ 12, 2, "BlackPalette", 0, { 0 }, &Script::blackPalette }, { 12, 2, "BlackPalette", 0, { 0 }, &Script::blackPalette },
{ 13, 1, "FadePalette", 3, { 1, 1, 1 }, NULL }, { 13, 1, "FadePalette", 3, { 1, 1, 1 }, &Script::fadePalette },
{ 13, 2, "FadePalettePlay", 3, { 1, 1, 1 }, NULL }, { 13, 2, "FadePalettePlay", 3, { 1, 1, 1 }, &Script::fadePalettePlay },
{ 14, 1, "NewRoom", 2, { 3, 1 }, &Script::newRoom }, { 14, 1, "NewRoom", 2, { 3, 1 }, &Script::newRoom },
{ 15, 1, "ExecInit", 1, { 3 }, &Script::execInit }, { 15, 1, "ExecInit", 1, { 3 }, &Script::execInit },
{ 15, 2, "ExecLook", 1, { 3 }, &Script::execLook }, { 15, 2, "ExecLook", 1, { 3 }, &Script::execLook },
@ -840,14 +840,36 @@ void Script::blackPalette(Common::Queue<int> &params) {
_vm->_game->schedulePalette(kBlackPalette); _vm->_game->schedulePalette(kBlackPalette);
} }
void Script::fadePalette(Common::Queue<int> &params) {
params.pop(); // unused first and last
params.pop();
int phases = params.pop();
_vm->_game->initializeFading(phases);
}
void Script::fadePalettePlay(Common::Queue<int> &params) {
params.pop(); // unused first and last
params.pop();
int phases = params.pop();
_vm->_game->initializeFading(phases);
_vm->_game->setLoopSubstatus(kSubstatusFade);
_vm->_game->loop();
_vm->_game->setExitLoop(false);
_vm->_game->setLoopSubstatus(kSubstatusOrdinary);
}
void Script::setPalette(Common::Queue<int> &params) { void Script::setPalette(Common::Queue<int> &params) {
if (_vm->_game->getScheduledPalette() == -1) { if (_vm->_game->getScheduledPalette() == -1) {
_vm->_screen->setPaletteEmpty(); _vm->_screen->setPalette(NULL, 0, kNumColours);
} else { } else {
const BAFile *f; const BAFile *f;
f = _vm->_paletteArchive->getFile(_vm->_game->getScheduledPalette()); f = _vm->_paletteArchive->getFile(_vm->_game->getScheduledPalette());
_vm->_screen->setPalette(f->_data, 0, kNumColours); _vm->_screen->setPalette(f->_data, 0, kNumColours);
} }
// Immediately update the palette
_vm->_screen->copyToScreen();
_vm->_system->delayMillis(100);
} }
void Script::quitGame(Common::Queue<int> &params) { void Script::quitGame(Common::Queue<int> &params) {

View file

@ -138,6 +138,8 @@ private:
void resetBlock(Common::Queue<int> &params); void resetBlock(Common::Queue<int> &params);
void setPalette(Common::Queue<int> &params); void setPalette(Common::Queue<int> &params);
void blackPalette(Common::Queue<int> &params); void blackPalette(Common::Queue<int> &params);
void fadePalette(Common::Queue<int> &params);
void fadePalettePlay(Common::Queue<int> &params);
void loadPalette(Common::Queue<int> &params); void loadPalette(Common::Queue<int> &params);
void quitGame(Common::Queue<int> &params); void quitGame(Common::Queue<int> &params);
void pushNewRoom(Common::Queue<int> &params); void pushNewRoom(Common::Queue<int> &params);