diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index d33bf4c64ea..dca6441e856 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -349,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)) { @@ -390,8 +420,14 @@ 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 == 1) { + 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 @@ -699,6 +735,14 @@ 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) { + // Process global scaling, if needed. + // TODO: Seems like SCI32 always processes global scaling for scaled objects + if (itemEntry->scaleSignal != 0 && itemEntry->scaleSignal != 1) + error("Unknown scale signal: %d", itemEntry->scaleSignal); + // TODO: We can only process symmetrical scaling for now (i.e. same value for scaleX/scaleY) + if (itemEntry->scaleSignal == 1 && 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); diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index 5fd28242242..5dadca674dd 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -113,6 +113,7 @@ public: void kernelAddPlane(reg_t object); void kernelUpdatePlane(reg_t object); void kernelDeletePlane(reg_t object); + void applyGlobalScaling(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 celHeight); void kernelAddScreenItem(reg_t object); void kernelUpdateScreenItem(reg_t object); void kernelDeleteScreenItem(reg_t object);