/* 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. * * $URL$ * $Id$ * */ // Main rendering loop #include "saga/saga.h" #include "saga/actor.h" #include "saga/font.h" #include "saga/gfx.h" #include "saga/interface.h" #include "saga/objectmap.h" #include "saga/puzzle.h" #include "saga/render.h" #include "saga/scene.h" #include "common/timer.h" #include "common/system.h" namespace Saga { const char *test_txt = "The quick brown fox jumped over the lazy dog. She sells sea shells down by the sea shore."; const char *pauseStringITE = "PAWS GAME"; const char *pauseStringIHNM = "Game Paused"; Render::Render(SagaEngine *vm, OSystem *system) { _vm = vm; _system = system; _initialized = false; #ifdef SAGA_DEBUG // Initialize FPS timer callback _vm->_timer->installTimerProc(&fpsTimerCallback, 1000000, this); #endif _backGroundSurface.create(_vm->getDisplayWidth(), _vm->getDisplayHeight(), 1); _flags = 0; _initialized = true; } Render::~Render(void) { #ifdef SAGA_DEBUG _vm->_timer->removeTimerProc(&fpsTimerCallback); #endif _backGroundSurface.free(); _initialized = false; } bool Render::initialized() { return _initialized; } void Render::drawScene() { Point mousePoint; Point textPoint; int curMode = _vm->_interface->getMode(); assert(_initialized); // TODO: Remove this _fullRefresh = true; #ifdef SAGA_DEBUG _renderedFrameCount++; #endif // Get mouse coordinates mousePoint = _vm->mousePos(); restoreChangedRects(); if (!(_flags & (RF_DEMO_SUBST | RF_MAP) || curMode == kPanelPlacard)) { if (_vm->_interface->getFadeMode() != kFadeOut) { // Display scene background if (!(_flags & RF_DISABLE_ACTORS) || _vm->getGameType() == GType_ITE) _vm->_scene->draw(); if (_vm->_puzzle->isActive()) { _vm->_puzzle->movePiece(mousePoint); _vm->_actor->drawSpeech(); } else { // Draw queued actors if (!(_flags & RF_DISABLE_ACTORS)) _vm->_actor->drawActors(); } #ifdef SAGA_DEBUG if (getFlags() & RF_OBJECTMAP_TEST) { if (_vm->_scene->_objectMap) _vm->_scene->_objectMap->draw(mousePoint, kITEColorBrightWhite, kITEColorBlack); if (_vm->_scene->_actionMap) _vm->_scene->_actionMap->draw(mousePoint, kITEColorRed, kITEColorBlack); } #endif #ifdef ACTOR_DEBUG if (getFlags() & RF_ACTOR_PATH_TEST) { _vm->_actor->drawPathTest(); } #endif } } if (_flags & RF_MAP) _vm->_interface->mapPanelDrawCrossHair(); if ((curMode == kPanelOption) || (curMode == kPanelQuit) || (curMode == kPanelLoad) || (curMode == kPanelSave)) { _vm->_interface->drawOption(); if (curMode == kPanelQuit) { _vm->_interface->drawQuit(); } if (curMode == kPanelLoad) { _vm->_interface->drawLoad(); } if (curMode == kPanelSave) { _vm->_interface->drawSave(); } } if (curMode == kPanelProtect) { _vm->_interface->drawProtect(); } // Draw queued text strings _vm->_scene->drawTextList(); // Handle user input _vm->processInput(); #ifdef SAGA_DEBUG // Display rendering information if (_flags & RF_SHOW_FPS) { char txtBuffer[20]; sprintf(txtBuffer, "%d", _fps); textPoint.x = _vm->_gfx->getBackBufferWidth() - _vm->_font->getStringWidth(kKnownFontSmall, txtBuffer, 0, kFontOutline); textPoint.y = 2; _vm->_font->textDraw(kKnownFontSmall, txtBuffer, textPoint, kITEColorBrightWhite, kITEColorBlack, kFontOutline); } #endif // Display "paused game" message, if applicable if (_flags & RF_RENDERPAUSE) { const char *pauseString = (_vm->getGameType() == GType_ITE) ? pauseStringITE : pauseStringIHNM; textPoint.x = (_vm->_gfx->getBackBufferWidth() - _vm->_font->getStringWidth(kKnownFontPause, pauseString, 0, kFontOutline)) / 2; textPoint.y = 90; _vm->_font->textDraw(kKnownFontPause, pauseString, textPoint, _vm->KnownColor2ColorId(kKnownColorBrightWhite), _vm->KnownColor2ColorId(kKnownColorBlack), kFontOutline); } // Update user interface _vm->_interface->update(mousePoint, UPDATE_MOUSEMOVE); #ifdef SAGA_DEBUG // Display text formatting test, if applicable if (_flags & RF_TEXT_TEST) { Rect rect(mousePoint.x, mousePoint.y, mousePoint.x + 100, mousePoint.y + 50); _vm->_font->textDrawRect(kKnownFontMedium, test_txt, rect, kITEColorBrightWhite, kITEColorBlack, (FontEffectFlags)(kFontOutline | kFontCentered)); } // Display palette test, if applicable if (_flags & RF_PALETTE_TEST) { _vm->_gfx->drawPalette(); } #endif drawDirtyRects(); _system->updateScreen(); _fullRefresh = false; } void Render::addDirtyRect(Common::Rect rect) { // Clip rectangle int x1 = MAX(rect.left, 0); int y1 = MAX(rect.top, 0); int x2 = MIN(rect.right, _backGroundSurface.w); int y2 = MIN(rect.bottom, _backGroundSurface.h); if (x2 > x1 && y2 > y1) { Common::Rect rectClipped(x1, y1, x2, y2); // Check if the new rectangle is contained within another in the list Common::List::const_iterator it; for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { if (it->contains(rectClipped)) return; if (rectClipped.contains(*it)) { _dirtyRects.erase(it); break; // we need to break now, as the list is changed } } _dirtyRects.push_back(rectClipped); } } void Render::restoreChangedRects() { if (!_fullRefresh) { Common::List::const_iterator it; for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { //_backGroundSurface.frameRect(*it, 1); // DEBUG g_system->copyRectToScreen((byte *)_backGroundSurface.pixels, _backGroundSurface.w, it->left, it->top, it->width(), it->height()); } } _dirtyRects.clear(); } void Render::drawDirtyRects() { if (!_fullRefresh) { Common::List::const_iterator it; for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { //_backGroundSurface.frameRect(*it, 2); // DEBUG g_system->copyRectToScreen(_vm->_gfx->getBackBufferPixels(), _backGroundSurface.w, it->left, it->top, it->width(), it->height()); } } else { _system->copyRectToScreen(_vm->_gfx->getBackBufferPixels(), _vm->_gfx->getBackBufferWidth(), 0, 0, _vm->_gfx->getBackBufferWidth(), _vm->_gfx->getBackBufferHeight()); } } #ifdef SAGA_DEBUG void Render::fpsTimerCallback(void *refCon) { ((Render *)refCon)->fpsTimer(); } void Render::fpsTimer(void) { _fps = _renderedFrameCount; _renderedFrameCount = 0; } #endif } // End of namespace Saga