aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/frameout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics/frameout.cpp')
-rw-r--r--engines/sci/graphics/frameout.cpp138
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;