/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * Additional copyright for this file: * Copyright (C) 1994-1998 Revolution Software Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "common/system.h" #include "common/textconsole.h" #include "graphics/palette.h" #include "sword2/sword2.h" #include "sword2/defs.h" #include "sword2/header.h" #include "sword2/logic.h" #include "sword2/resman.h" #include "sword2/screen.h" namespace Sword2 { /** * Start layer palette fading up */ void Screen::startNewPalette() { // If the screen is still fading down then wait for black - could // happen when everythings cached into a large memory model waitForFade(); byte *screenFile = _vm->_resman->openResource(_thisScreen.background_layer_id); // Don't fetch palette match table while using PSX version, // because it is not present. if (!Sword2Engine::isPsx()) memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(screenFile), PALTABLESIZE); _vm->fetchPalette(screenFile, _palette); setPalette(0, 256, _palette, RDPAL_FADE); // Indicating that it's a screen palette _lastPaletteRes = 0; _vm->_resman->closeResource(_thisScreen.background_layer_id); fadeUp(); _thisScreen.new_palette = 0; } void Screen::setFullPalette(int32 palRes) { // fudge for hut interior // - unpausing should restore last palette as normal (could be screen // palette or 'dark_palette_13') // - but restoring the screen palette after 'dark_palette_13' should // now work properly too! // "Hut interior" refers to the watchman's hut in Marseille, and this // is apparently needed for the palette to be restored properly when // you turn the light off. (I didn't even notice the light switch!) if (_vm->_logic->readVar(LOCATION) == 13) { // unpausing if (palRes == -1) { // restore whatever palette was last set (screen // palette or 'dark_palette_13') palRes = _lastPaletteRes; } } else { // check if we're just restoring the current screen palette // because we might actually need to use a separate palette // file anyway eg. for pausing & unpausing during the eclipse // unpausing (fudged for location 13) if (palRes == -1) { // we really meant '0' palRes = 0; } if (palRes == 0 && _lastPaletteRes) palRes = _lastPaletteRes; } // If non-zero, set palette to this separate palette file. Otherwise, // set palette to current screen palette. if (palRes) { byte *pal = _vm->_resman->openResource(palRes); assert(_vm->_resman->fetchType(pal) == PALETTE_FILE); pal += ResHeader::size(); // always set color 0 to black because most background screen // palettes have a bright color 0 although it should come out // as black in the game! _palette[0] = 0; _palette[1] = 0; _palette[2] = 0; for (uint i = 4, j = 3; i < 4 * 256; i += 4, j += 3) { _palette[j + 0] = pal[i + 0]; _palette[j + 1] = pal[i + 1]; _palette[j + 2] = pal[i + 2]; } setPalette(0, 256, _palette, RDPAL_INSTANT); _vm->_resman->closeResource(palRes); } else { if (_thisScreen.background_layer_id) { byte *data = _vm->_resman->openResource(_thisScreen.background_layer_id); // Do not fetch palette match table when using PSX version, // because it is not present. if (!Sword2Engine::isPsx()) memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(data), PALTABLESIZE); _vm->fetchPalette(data, _palette); setPalette(0, 256, _palette, RDPAL_INSTANT); _vm->_resman->closeResource(_thisScreen.background_layer_id); } else error("setFullPalette(0) called, but no current screen available"); } if (palRes != CONTROL_PANEL_PALETTE) _lastPaletteRes = palRes; } /** * Matches a color triplet to a palette index. * @param r red color component * @param g green color component * @param b blue color component * @return the palette index of the closest matching color in the palette */ // FIXME: This used to be inlined - probably a good idea - but the // linker complained when I tried to use it in sprite.cpp. uint8 Screen::quickMatch(uint8 r, uint8 g, uint8 b) { return _paletteMatch[((int32)(r >> 2) << 12) + ((int32)(g >> 2) << 6) + (b >> 2)]; } /** * Sets the palette. * @param startEntry the first color entry to set * @param noEntries the number of color entries to set * @param colorTable the new color entries * @param fadeNow whether to perform the change immediately or delayed */ void Screen::setPalette(int16 startEntry, int16 noEntries, byte *colorTable, uint8 fadeNow) { assert(noEntries > 0); memmove(&_palette[3 * startEntry], colorTable, noEntries * 3); if (fadeNow == RDPAL_INSTANT) { setSystemPalette(_palette, startEntry, noEntries); setNeedFullRedraw(); } } void Screen::dimPalette(bool dim) { if (getFadeStatus() != RDFADE_NONE) return; if (dim != _dimPalette) { _dimPalette = dim; setSystemPalette(_palette, 0, 256); setNeedFullRedraw(); } } /** * Fades the palette up from black to the current palette. * @param time the time it will take the palette to fade up */ int32 Screen::fadeUp(float time) { if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) return RDERR_FADEINCOMPLETE; _fadeTotalTime = (int32)(time * 1000); _fadeStatus = RDFADE_UP; _fadeStartTime = getTick(); return RD_OK; } /** * Fades the palette down to black from the current palette. * @param time the time it will take the palette to fade down */ int32 Screen::fadeDown(float time) { if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) return RDERR_FADEINCOMPLETE; _fadeTotalTime = (int32)(time * 1000); _fadeStatus = RDFADE_DOWN; _fadeStartTime = getTick(); return RD_OK; } /** * Get the current fade status * @return RDFADE_UP (fading up), RDFADE_DOWN (fading down), RDFADE_NONE * (not faded), or RDFADE_BLACK (completely faded down) */ uint8 Screen::getFadeStatus() { return _fadeStatus; } void Screen::waitForFade() { while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->shouldQuit()) { updateDisplay(); _vm->_system->delayMillis(20); } } void Screen::fadeServer() { static int32 previousTime = 0; byte fadePalette[256 * 3]; byte *newPalette = fadePalette; int32 currentTime; int16 fadeMultiplier; int16 i; // If we're not in the process of fading, do nothing. if (getFadeStatus() != RDFADE_UP && getFadeStatus() != RDFADE_DOWN) return; // I don't know if this is necessary, but let's limit how often the // palette is updated, just to be safe. currentTime = getTick(); if (currentTime - previousTime <= 25) return; previousTime = currentTime; if (getFadeStatus() == RDFADE_UP) { if (currentTime >= _fadeStartTime + _fadeTotalTime) { _fadeStatus = RDFADE_NONE; newPalette = _palette; } else { fadeMultiplier = (int16)(((int32)(currentTime - _fadeStartTime) * 256) / _fadeTotalTime); for (i = 0; i < 256; i++) { newPalette[i * 3 + 0] = (_palette[i * 3 + 0] * fadeMultiplier) >> 8; newPalette[i * 3 + 1] = (_palette[i * 3 + 1] * fadeMultiplier) >> 8; newPalette[i * 3 + 2] = (_palette[i * 3 + 2] * fadeMultiplier) >> 8; } } } else { if (currentTime >= _fadeStartTime + _fadeTotalTime) { _fadeStatus = RDFADE_BLACK; memset(newPalette, 0, sizeof(fadePalette)); } else { fadeMultiplier = (int16)(((int32)(_fadeTotalTime - (currentTime - _fadeStartTime)) * 256) / _fadeTotalTime); for (i = 0; i < 256; i++) { newPalette[i * 3 + 0] = (_palette[i * 3 + 0] * fadeMultiplier) >> 8; newPalette[i * 3 + 1] = (_palette[i * 3 + 1] * fadeMultiplier) >> 8; newPalette[i * 3 + 2] = (_palette[i * 3 + 2] * fadeMultiplier) >> 8; } } } setSystemPalette(newPalette, 0, 256); setNeedFullRedraw(); } void Screen::setSystemPalette(const byte *colors, uint start, uint num) { if (_dimPalette) { byte pal[256 * 3]; for (uint i = start * 3; i < 3 * (start + num); i++) pal[i] = colors[i] / 2; _vm->_system->getPaletteManager()->setPalette(pal, start, num); } else { _vm->_system->getPaletteManager()->setPalette(colors, start, num); } } } // End of namespace Sword2