Implement palette fading
svn-id: r45455
This commit is contained in:
parent
4f5a99655c
commit
c781f01321
7 changed files with 101 additions and 22 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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> ¶ms) {
|
||||||
_vm->_game->schedulePalette(kBlackPalette);
|
_vm->_game->schedulePalette(kBlackPalette);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Script::fadePalette(Common::Queue<int> ¶ms) {
|
||||||
|
params.pop(); // unused first and last
|
||||||
|
params.pop();
|
||||||
|
int phases = params.pop();
|
||||||
|
_vm->_game->initializeFading(phases);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Script::fadePalettePlay(Common::Queue<int> ¶ms) {
|
||||||
|
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> ¶ms) {
|
void Script::setPalette(Common::Queue<int> ¶ms) {
|
||||||
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> ¶ms) {
|
void Script::quitGame(Common::Queue<int> ¶ms) {
|
||||||
|
|
|
@ -138,6 +138,8 @@ private:
|
||||||
void resetBlock(Common::Queue<int> ¶ms);
|
void resetBlock(Common::Queue<int> ¶ms);
|
||||||
void setPalette(Common::Queue<int> ¶ms);
|
void setPalette(Common::Queue<int> ¶ms);
|
||||||
void blackPalette(Common::Queue<int> ¶ms);
|
void blackPalette(Common::Queue<int> ¶ms);
|
||||||
|
void fadePalette(Common::Queue<int> ¶ms);
|
||||||
|
void fadePalettePlay(Common::Queue<int> ¶ms);
|
||||||
void loadPalette(Common::Queue<int> ¶ms);
|
void loadPalette(Common::Queue<int> ¶ms);
|
||||||
void quitGame(Common::Queue<int> ¶ms);
|
void quitGame(Common::Queue<int> ¶ms);
|
||||||
void pushNewRoom(Common::Queue<int> ¶ms);
|
void pushNewRoom(Common::Queue<int> ¶ms);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue