diff options
Diffstat (limited to 'engines/sci/graphics/frameout.cpp')
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 138 |
1 files changed, 93 insertions, 45 deletions
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index cb56e24de9..e251bd3dc0 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -28,6 +28,7 @@ #include "common/system.h" #include "common/textconsole.h" #include "engines/engine.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "sci/sci.h" @@ -125,23 +126,17 @@ void GfxFrameout::kernelAddPlane(reg_t object) { if (_planes.empty()) { // There has to be another way for sierra sci to do this or maybe script resolution is compiled into // interpreter (TODO) - uint16 tmpRunningWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); - uint16 tmpRunningHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); + uint16 scriptWidth = readSelectorValue(_segMan, object, SELECTOR(resX)); + uint16 scriptHeight = readSelectorValue(_segMan, object, SELECTOR(resY)); - // The above can be 0 in SCI3 (e.g. Phantasmagoria 2) - if (tmpRunningWidth == 0 && tmpRunningHeight == 0) { - tmpRunningWidth = 320; - tmpRunningHeight = 200; - } - - // HACK: Phantasmagoria 1 sets a window size of 630x450. - // We can't set a width of 630, as that messes up the pitch, so we hack - // the internal script width here - if (g_sci->getGameId() == GID_PHANTASMAGORIA) { - tmpRunningWidth = 325; + // Phantasmagoria 2 doesn't specify a script width/height + if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { + scriptWidth = 640; + scriptHeight = 480; } - _coordAdjuster->setScriptsResolution(tmpRunningWidth, tmpRunningHeight); + assert(scriptWidth > 0 && scriptHeight > 0); + _coordAdjuster->setScriptsResolution(scriptWidth, scriptHeight); } // Import of QfG character files dialog is shown in QFG4. @@ -159,7 +154,7 @@ void GfxFrameout::kernelAddPlane(reg_t object) { newPlane.object = object; newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); - newPlane.lastPriority = 0xFFFF; // hidden + newPlane.lastPriority = -1; // hidden newPlane.planeOffsetX = 0; newPlane.planeOffsetY = 0; newPlane.pictureId = kPlanePlainColored; @@ -202,7 +197,7 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { } else { it->planeOffsetX = 0; } - + if (it->planeRect.top < 0) { it->planeOffsetY = -it->planeRect.top; it->planeRect.top = 0; @@ -354,6 +349,36 @@ void GfxFrameout::deletePlaneLine(reg_t object, reg_t hunkId) { } } +// Adapted from GfxAnimate::applyGlobalScaling() +void GfxFrameout::applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight) { + // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY + int16 maxScale = readSelectorValue(_segMan, itemEntry->object, SELECTOR(maxScale)); + int16 maxCelHeight = (maxScale * celHeight) >> 7; + reg_t globalVar2 = g_sci->getEngineState()->variables[VAR_GLOBAL][2]; // current room object + int16 vanishingY = readSelectorValue(_segMan, globalVar2, SELECTOR(vanishingY)); + + int16 fixedPortY = planeRect.bottom - vanishingY; + int16 fixedEntryY = itemEntry->y - vanishingY; + if (!fixedEntryY) + fixedEntryY = 1; + + if ((celHeight == 0) || (fixedPortY == 0)) + error("global scaling panic"); + + itemEntry->scaleY = (maxCelHeight * fixedEntryY) / fixedPortY; + itemEntry->scaleY = (itemEntry->scaleY * maxScale) / celHeight; + + // Make sure that the calculated value is sane + if (itemEntry->scaleY < 1 /*|| itemEntry->scaleY > 128*/) + itemEntry->scaleY = 128; + + itemEntry->scaleX = itemEntry->scaleY; + + // and set objects scale selectors + //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleX), itemEntry->scaleX); + //writeSelectorValue(_segMan, itemEntry->object, SELECTOR(scaleY), itemEntry->scaleY); +} + void GfxFrameout::kernelAddScreenItem(reg_t object) { // Ignore invalid items if (!_segMan->isObject(object)) { @@ -395,8 +420,15 @@ void GfxFrameout::kernelUpdateScreenItem(reg_t object) { itemEntry->priority = itemEntry->y; itemEntry->signal = readSelectorValue(_segMan, object, SELECTOR(signal)); - itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); - itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); + itemEntry->scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)); + + if (itemEntry->scaleSignal & kScaleSignalDoScaling32) { + itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); + itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); + } else { + itemEntry->scaleX = 128; + itemEntry->scaleY = 128; + } itemEntry->visible = true; // Check if the entry can be hidden @@ -425,7 +457,7 @@ void GfxFrameout::deletePlaneItems(reg_t planeObject) { } else { objectMatches = true; } - + if (objectMatches) { FrameoutEntry *itemEntry = *listIterator; listIterator = _screenItems.erase(listIterator); @@ -465,15 +497,10 @@ bool sortHelper(const FrameoutEntry* entry1, const FrameoutEntry* entry2) { } bool planeSortHelper(const PlaneEntry &entry1, const PlaneEntry &entry2) { -// SegManager *segMan = g_sci->getEngineState()->_segMan; - -// uint16 plane1Priority = readSelectorValue(segMan, entry1, SELECTOR(priority)); -// uint16 plane2Priority = readSelectorValue(segMan, entry2, SELECTOR(priority)); - - if (entry1.priority == 0xffff) + if (entry1.priority < 0) return true; - if (entry2.priority == 0xffff) + if (entry2.priority < 0) return false; return entry1.priority < entry2.priority; @@ -499,7 +526,7 @@ void GfxFrameout::showVideo() { uint16 y = videoDecoder->getPos().y; if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { @@ -508,7 +535,7 @@ void GfxFrameout::showVideo() { g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); g_system->updateScreen(); } @@ -639,13 +666,13 @@ void GfxFrameout::kernelFrameout() { _screen->drawLine(startPoint, endPoint, it2->color, it2->priority, it2->control); } - uint16 planeLastPriority = it->lastPriority; + int16 planeLastPriority = it->lastPriority; // Update priority here, sq6 sets it w/o UpdatePlane - uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); + int16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); it->lastPriority = planePriority; - if (planePriority == 0xffff) { // Plane currently not meant to be shown + if (planePriority < 0) { // Plane currently not meant to be shown // If plane was shown before, delete plane rect if (planePriority != planeLastPriority) _paint32->fillRect(it->planeRect, 0); @@ -660,7 +687,13 @@ void GfxFrameout::kernelFrameout() { _paint32->fillRect(it->planeRect, it->planeBack); _coordAdjuster->pictureSetDisplayArea(it->planeRect); - _palette->drewPicture(it->pictureId); + // Invoking drewPicture() with an invalid picture ID in SCI32 results in + // invalidating the palVary palette when a palVary effect is active. This + // is quite obvious in QFG4, where the day time palette is incorrectly + // shown when exiting the caves, and the correct night time palette + // flashes briefly each time that kPalVaryInit is called. + if (it->pictureId != 0xFFFF) + _palette->drewPicture(it->pictureId); FrameoutList itemList; @@ -671,7 +704,7 @@ void GfxFrameout::kernelFrameout() { if (!itemEntry->visible) continue; - + if (itemEntry->object.isNull()) { // Picture cel data _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x); @@ -709,13 +742,21 @@ void GfxFrameout::kernelFrameout() { // TODO: maybe we should clip the cels rect with this, i'm not sure // the only currently known usage is game menu of gk1 } else if (view) { - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->getCelRect(itemEntry->loopNo, itemEntry->celNo, - itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); - else - view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, - itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, - itemEntry->scaleY, itemEntry->celRect); + // Process global scaling, if needed. + // TODO: Seems like SCI32 always processes global scaling for scaled objects + // TODO: We can only process symmetrical scaling for now (i.e. same value for scaleX/scaleY) + if ((itemEntry->scaleSignal & kScaleSignalDoScaling32) && + !(itemEntry->scaleSignal & kScaleSignalDisableGlobalScaling32) && + (itemEntry->scaleX == itemEntry->scaleY)) + applyGlobalScaling(itemEntry, it->planeRect, view->getHeight(itemEntry->loopNo, itemEntry->celNo)); + + if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) + view->getCelRect(itemEntry->loopNo, itemEntry->celNo, + itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); + else + view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, + itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, + itemEntry->scaleY, itemEntry->celRect); Common::Rect nsRect = itemEntry->celRect; // Translate back to actual coordinate within scrollable plane @@ -736,10 +777,17 @@ void GfxFrameout::kernelFrameout() { continue; } - g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); + // FIXME: We should not update the object's NS rect here. + // This breaks the sliders in the control panel screen in + // QFG4, but disabling it does not change any functionality, + // as the object(s) will be drawn on screen with the + // calculated coordinates. + //g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } - // FIXME: When does this happen, and why? + // Don't attempt to draw sprites that are outside the visible + // screen area. An example is the random people walking in + // Jackson Square in GK1. if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() || itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth()) continue; @@ -763,10 +811,10 @@ void GfxFrameout::kernelFrameout() { if (view) { if (!clipRect.isEmpty()) { if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->draw(itemEntry->celRect, clipRect, translatedClipRect, + view->draw(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); else - view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, + view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); } } @@ -825,7 +873,7 @@ void GfxFrameout::printPlaneItemList(Console *con, reg_t planeObject) { for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { FrameoutEntry *e = *listIterator; reg_t itemPlane = readSelector(_segMan, e->object, SELECTOR(plane)); - + if (planeObject == itemPlane) { Common::String curItemName = _segMan->getObjectName(e->object); Common::Rect icr = e->celRect; |