/* 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. * * 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 "sherlock/screen.h" #include "sherlock/sherlock.h" #include "common/system.h" #include "graphics/palette.h" namespace Sherlock { Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _vm(vm), _backBuffer1(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT) { setFont(1); } void Screen::setFont(int fontNumber) { _fontNumber = fontNumber; Common::String fname = Common::String::format("FONT%d.VGS", fontNumber); Common::SeekableReadStream *stream = _vm->_res->load(fname); debug("TODO: Loading font %s, size - %d", fname.c_str(), stream->size()); delete stream; } void Screen::update() { // Merge the dirty rects mergeDirtyRects(); // Loop through copying dirty areas to the physical screen Common::List::iterator i; for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { const Common::Rect &r = *i; const byte *srcP = (const byte *)getBasePtr(r.left, r.top); g_system->copyRectToScreen(srcP, this->pitch, r.left, r.top, r.width(), r.height()); } // Signal the physical screen to update g_system->updateScreen(); _dirtyRects.clear(); } void Screen::getPalette(byte palette[PALETTE_SIZE]) { g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT); } void Screen::setPalette(const byte palette[PALETTE_SIZE]) { g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT); } int Screen::equalizePalette(const byte palette[PALETTE_SIZE]) { int total = 0; byte tempPalette[PALETTE_SIZE]; getPalette(tempPalette); // For any palette component that doesn't already match the given destination // palette, change by 1 towards the reference palette component for (int idx = 0; idx < PALETTE_SIZE; ++idx) { if (tempPalette[idx] > palette[idx]) { --tempPalette[idx]; ++total; } else if (tempPalette[idx] < palette[idx]) { ++tempPalette[idx]; ++total; } } if (total > 0) // Palette changed, so reload it setPalette(tempPalette); return total; } void Screen::fadeToBlack() { const int FADE_AMOUNT = 2; bool repeatFlag; byte *srcP; int count; byte tempPalette[PALETTE_SIZE]; getPalette(tempPalette); do { repeatFlag = false; for (srcP = &tempPalette[0], count = 0; count < PALETTE_SIZE; ++count, ++srcP) { int v = *srcP; if (v) { repeatFlag = true; *srcP = MAX(*srcP - FADE_AMOUNT, 0); } } setPalette(tempPalette); _vm->_events->pollEventsAndWait(); } while (repeatFlag && !_vm->shouldQuit()); } /** * Adds a rectangle to the list of modified areas of the screen during the * current frame */ void Screen::addDirtyRect(const Common::Rect &r) { _dirtyRects.push_back(r); assert(r.isValidRect() && r.width() > 0 && r.height() > 0); } /** * Merges together overlapping dirty areas of the screen */ void Screen::mergeDirtyRects() { Common::List::iterator rOuter, rInner; // Ensure dirty rect list has at least two entries rOuter = _dirtyRects.begin(); for (int i = 0; i < 2; ++i, ++rOuter) { if (rOuter == _dirtyRects.end()) return; } // Process the dirty rect list to find any rects to merge for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { rInner = rOuter; while (++rInner != _dirtyRects.end()) { if ((*rOuter).intersects(*rInner)) { // these two rectangles overlap or // are next to each other - merge them unionRectangle(*rOuter, *rOuter, *rInner); // remove the inner rect from the list _dirtyRects.erase(rInner); // move back to beginning of list rInner = rOuter; } } } } /** * Returns the union of two dirty area rectangles */ bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) { destRect = src1; destRect.extend(src2); return !destRect.isEmpty(); } } // End of namespace Sherlock