diff options
Diffstat (limited to 'engines/sci/graphics/frameout.cpp')
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 444 |
1 files changed, 251 insertions, 193 deletions
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 6bd310f1a0..7bb4162020 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -37,6 +37,7 @@ #include "sci/engine/vm.h" #include "sci/graphics/cache.h" #include "sci/graphics/coordadjuster.h" +#include "sci/graphics/compare.h" #include "sci/graphics/font.h" #include "sci/graphics/view.h" #include "sci/graphics/screen.h" @@ -55,8 +56,8 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd : _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) { _coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster; - scriptsRunningWidth = 320; - scriptsRunningHeight = 200; + _scriptsRunningWidth = 320; + _scriptsRunningHeight = 200; } GfxFrameout::~GfxFrameout() { @@ -79,17 +80,18 @@ void GfxFrameout::kernelAddPlane(reg_t object) { // The above can be 0 in SCI3 (e.g. Phantasmagoria 2) if (tmpRunningWidth > 0 && tmpRunningHeight > 0) { - scriptsRunningWidth = tmpRunningWidth; - scriptsRunningHeight = tmpRunningHeight; + _scriptsRunningWidth = tmpRunningWidth; + _scriptsRunningHeight = tmpRunningHeight; } - _coordAdjuster->setScriptsResolution(scriptsRunningWidth, scriptsRunningHeight); + _coordAdjuster->setScriptsResolution(_scriptsRunningWidth, _scriptsRunningHeight); } newPlane.object = object; newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); newPlane.lastPriority = 0xFFFF; // hidden newPlane.planeOffsetX = 0; + newPlane.planeOffsetY = 0; newPlane.pictureId = 0xFFFF; newPlane.planePictureMirrored = false; newPlane.planeBack = 0; @@ -116,14 +118,14 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { } it->planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); it->planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); - it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1; - it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1; + it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); + it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); - it->planeRect.top = (it->planeRect.top * screenRect.height()) / scriptsRunningHeight; - it->planeRect.left = (it->planeRect.left * screenRect.width()) / scriptsRunningWidth; - it->planeRect.bottom = (it->planeRect.bottom * screenRect.height()) / scriptsRunningHeight; - it->planeRect.right = (it->planeRect.right * screenRect.width()) / scriptsRunningWidth; + it->planeRect.top = (it->planeRect.top * screenRect.height()) / _scriptsRunningHeight; + it->planeRect.left = (it->planeRect.left * screenRect.width()) / _scriptsRunningWidth; + it->planeRect.bottom = (it->planeRect.bottom * screenRect.height()) / _scriptsRunningHeight; + it->planeRect.right = (it->planeRect.right * screenRect.width()) / _scriptsRunningWidth; // We get negative left in kq7 in scrolling rooms if (it->planeRect.left < 0) { @@ -132,9 +134,14 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { } else { it->planeOffsetX = 0; } - - if (it->planeRect.top < 0) + + if (it->planeRect.top < 0) { + it->planeOffsetY = -it->planeRect.top; it->planeRect.top = 0; + } else { + it->planeOffsetY = 0; + } + // We get bad plane-bottom in sq6 if (it->planeRect.right > _screen->getWidth()) it->planeRect.right = _screen->getWidth(); @@ -170,10 +177,6 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { error("kUpdatePlane called on plane that wasn't added before"); } -void GfxFrameout::kernelRepaintPlane(reg_t object) { - // TODO -} - void GfxFrameout::kernelDeletePlane(reg_t object) { deletePlanePictures(object); for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { @@ -182,15 +185,18 @@ void GfxFrameout::kernelDeletePlane(reg_t object) { Common::Rect planeRect; planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); - planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1; - planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1; + planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); + planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); - planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight; - planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth; - planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight; - planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth; + planeRect.top = (planeRect.top * screenRect.height()) / _scriptsRunningHeight; + planeRect.left = (planeRect.left * screenRect.width()) / _scriptsRunningWidth; + planeRect.bottom = (planeRect.bottom * screenRect.height()) / _scriptsRunningHeight; + planeRect.right = (planeRect.right * screenRect.width()) / _scriptsRunningWidth; planeRect.clip(screenRect); // we need to do this, at least in gk1 on cemetary we get bottom right -> 201, 321 + // FIXME: The code above incorrectly added 1 pixel to the plane's + // bottom and right, so probably the plane clipping code is no + // longer necessary // Blackout removed plane rect _paint32->fillRect(planeRect, 0); return; @@ -239,36 +245,45 @@ void GfxFrameout::kernelUpdateScreenItem(reg_t object) { if (!_segMan->isObject(object)) return; - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - FrameoutEntry *itemEntry = *listIterator; - - if (itemEntry->object == object) { - itemEntry->viewId = readSelectorValue(_segMan, object, SELECTOR(view)); - itemEntry->loopNo = readSelectorValue(_segMan, object, SELECTOR(loop)); - itemEntry->celNo = readSelectorValue(_segMan, object, SELECTOR(cel)); - itemEntry->x = readSelectorValue(_segMan, object, SELECTOR(x)); - itemEntry->y = readSelectorValue(_segMan, object, SELECTOR(y)); - itemEntry->z = readSelectorValue(_segMan, object, SELECTOR(z)); - itemEntry->priority = readSelectorValue(_segMan, object, SELECTOR(priority)); - if (readSelectorValue(_segMan, object, SELECTOR(fixPriority)) == 0) - 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)); - return; - } + FrameoutEntry *itemEntry = findScreenItem(object); + if (!itemEntry) { + warning("kernelUpdateScreenItem: invalid object %04x:%04x", PRINT_REG(object)); + return; } + + itemEntry->viewId = readSelectorValue(_segMan, object, SELECTOR(view)); + itemEntry->loopNo = readSelectorValue(_segMan, object, SELECTOR(loop)); + itemEntry->celNo = readSelectorValue(_segMan, object, SELECTOR(cel)); + itemEntry->x = readSelectorValue(_segMan, object, SELECTOR(x)); + itemEntry->y = readSelectorValue(_segMan, object, SELECTOR(y)); + itemEntry->z = readSelectorValue(_segMan, object, SELECTOR(z)); + itemEntry->priority = readSelectorValue(_segMan, object, SELECTOR(priority)); + if (readSelectorValue(_segMan, object, SELECTOR(fixPriority)) == 0) + 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)); } void GfxFrameout::kernelDeleteScreenItem(reg_t object) { + FrameoutEntry *itemEntry = findScreenItem(object); + if (!itemEntry) { + warning("kernelDeleteScreenItem: invalid object %04x:%04x", PRINT_REG(object)); + return; + } + + _screenItems.remove(itemEntry); +} + +FrameoutEntry *GfxFrameout::findScreenItem(reg_t object) { for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { FrameoutEntry *itemEntry = *listIterator; - if (itemEntry->object == object) { - _screenItems.remove(itemEntry); - return; - } + if (itemEntry->object == object) + return itemEntry; } + + return NULL; } int16 GfxFrameout::kernelGetHighPlanePri() { @@ -317,37 +332,149 @@ void GfxFrameout::sortPlanes() { Common::sort(_planes.begin(), _planes.end(), planeSortHelper); } -void GfxFrameout::kernelFrameout() { - if (g_sci->_robotDecoder->isVideoLoaded()) { - bool skipVideo = false; - RobotDecoder *videoDecoder = g_sci->_robotDecoder; - uint16 x = videoDecoder->getPos().x; - uint16 y = videoDecoder->getPos().y; +int16 GfxFrameout::upscaleHorizontalCoordinate(int16 coordinate) { + return ((coordinate * _screen->getWidth()) / _scriptsRunningWidth); +} + +int16 GfxFrameout::upscaleVerticalCoordinate(int16 coordinate) { + return ((coordinate * _screen->getHeight()) / _scriptsRunningHeight); +} - if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); +Common::Rect GfxFrameout::upscaleRect(Common::Rect &rect) { + rect.top = (rect.top * _scriptsRunningHeight) / _screen->getHeight(); + rect.left = (rect.left * _scriptsRunningWidth) / _screen->getWidth(); + rect.bottom = (rect.bottom * _scriptsRunningHeight) / _screen->getHeight(); + rect.right = (rect.right * _scriptsRunningWidth) / _screen->getWidth(); - while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { - if (videoDecoder->needsUpdate()) { - const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); - if (frame) { - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + return rect; +} - if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); +void GfxFrameout::showVideo() { + bool skipVideo = false; + RobotDecoder *videoDecoder = g_sci->_robotDecoder; + uint16 x = videoDecoder->getPos().x; + uint16 y = videoDecoder->getPos().y; - g_system->updateScreen(); - } + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + + while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { + if (videoDecoder->needsUpdate()) { + const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); + if (frame) { + g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + + g_system->updateScreen(); } + } + + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } - Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { - if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) - skipVideo = true; + g_system->delayMillis(10); + } +} + +void GfxFrameout::createPlaneItemList(reg_t planeObject, FrameoutList &itemList) { + // Copy screen items of the current frame to the list of items to be drawn + for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { + reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); + if (planeObject == itemPlane) { + kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? + itemList.push_back(*listIterator); + } + } + + for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { + if (pictureIt->object == planeObject) { + GfxPicture *planePicture = pictureIt->picture; + // Allocate memory for picture cels + pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()]; + + // Add following cels to the itemlist + FrameoutEntry *picEntry = pictureIt->pictureCels; + int planePictureCels = planePicture->getSci32celCount(); + for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) { + picEntry->celNo = pictureCelNr; + picEntry->object = NULL_REG; + picEntry->picture = planePicture; + picEntry->y = planePicture->getSci32celY(pictureCelNr); + picEntry->x = planePicture->getSci32celX(pictureCelNr); + picEntry->picStartX = pictureIt->startX; + picEntry->picStartY = pictureIt->startY; + + picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); + + itemList.push_back(picEntry); + picEntry++; } + } + } + + // Now sort our itemlist + Common::sort(itemList.begin(), itemList.end(), sortHelper); +} - g_system->delayMillis(10); +bool GfxFrameout::isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY) { + // Out of view horizontally (sanity checks) + int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; + int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); + int16 planeStartX = planeOffsetX; + int16 planeEndX = planeStartX + planeRect.width(); + if (pictureCelEndX < planeStartX) + return true; + if (pictureCelStartX > planeEndX) + return true; + + // Out of view vertically (sanity checks) + int16 pictureCelStartY = itemEntry->picStartY + itemEntry->y; + int16 pictureCelEndY = pictureCelStartY + itemEntry->picture->getSci32celHeight(itemEntry->celNo); + int16 planeStartY = planeOffsetY; + int16 planeEndY = planeStartY + planeRect.height(); + if (pictureCelEndY < planeStartY) + return true; + if (pictureCelStartY > planeEndY) + return true; + + return false; +} + +void GfxFrameout::drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored) { + int16 pictureOffsetX = planeOffsetX; + int16 pictureX = itemEntry->x; + if ((planeOffsetX) || (itemEntry->picStartX)) { + if (planeOffsetX <= itemEntry->picStartX) { + pictureX += itemEntry->picStartX - planeOffsetX; + pictureOffsetX = 0; + } else { + pictureOffsetX = planeOffsetX - itemEntry->picStartX; + } + } + + int16 pictureOffsetY = planeOffsetY; + int16 pictureY = itemEntry->y; + if ((planeOffsetY) || (itemEntry->picStartY)) { + if (planeOffsetY <= itemEntry->picStartY) { + pictureY += itemEntry->picStartY - planeOffsetY; + pictureOffsetY = 0; + } else { + pictureOffsetY = planeOffsetY - itemEntry->picStartY; } + } + + itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, pictureOffsetY, planePictureMirrored); + // warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority); +} + +void GfxFrameout::kernelFrameout() { + if (g_sci->_robotDecoder->isVideoLoaded()) { + showVideo(); return; } @@ -368,7 +495,10 @@ void GfxFrameout::kernelFrameout() { continue; } - if (it->planeBack) + // There is a race condition lurking in SQ6, which causes the game to hang in the intro, when teleporting to Polysorbate LX. + // Since I first wrote the patch, the race has stopped occurring for me though. + // I'll leave this for investigation later, when someone can reproduce. + if (it->pictureId == 0xffff) _paint32->fillRect(it->planeRect, it->planeBack); GuiResourceId planeMainPictureId = it->pictureId; @@ -378,43 +508,7 @@ void GfxFrameout::kernelFrameout() { FrameoutList itemList; - // Copy screen items of the current frame to the list of items to be drawn - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); - if (planeObject == itemPlane) { - kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? - itemList.push_back(*listIterator); - } - } - - for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { - if (pictureIt->object == planeObject) { - GfxPicture *planePicture = pictureIt->picture; - // Allocate memory for picture cels - pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()]; - - // Add following cels to the itemlist - FrameoutEntry *picEntry = pictureIt->pictureCels; - int planePictureCels = planePicture->getSci32celCount(); - for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) { - picEntry->celNo = pictureCelNr; - picEntry->object = NULL_REG; - picEntry->picture = planePicture; - picEntry->y = planePicture->getSci32celY(pictureCelNr); - picEntry->x = planePicture->getSci32celX(pictureCelNr); - picEntry->picStartX = pictureIt->startX; - picEntry->picStartY = pictureIt->startY; - - picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); - - itemList.push_back(picEntry); - picEntry++; - } - } - } - - // Now sort our itemlist - Common::sort(itemList.begin(), itemList.end(), sortHelper); + createPlaneItemList(planeObject, itemList); // warning("Plane %s", _segMan->getObjectName(planeObject)); @@ -423,100 +517,76 @@ void GfxFrameout::kernelFrameout() { if (itemEntry->object.isNull()) { // Picture cel data - itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight); - itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth); - itemEntry->picStartX = ((itemEntry->picStartX * _screen->getWidth()) / scriptsRunningWidth); - itemEntry->picStartY = ((itemEntry->picStartY * _screen->getHeight()) / scriptsRunningHeight); - - // Out of view horizontally (sanity checks) - int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; - int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); - int16 planeStartX = it->planeOffsetX; - int16 planeEndX = planeStartX + it->planeRect.width(); - if (pictureCelEndX < planeStartX) - continue; - if (pictureCelStartX > planeEndX) - continue; - - // Out of view vertically (sanity checks) - // TODO - - int16 pictureOffsetX = it->planeOffsetX; - int16 pictureX = itemEntry->x; - if ((it->planeOffsetX) || (itemEntry->picStartX)) { - if (it->planeOffsetX <= itemEntry->picStartX) { - pictureX += itemEntry->picStartX - it->planeOffsetX; - pictureOffsetX = 0; - } else { - pictureOffsetX = it->planeOffsetX - itemEntry->picStartX; - } - } - - // TODO: pictureOffsetY - itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, it->planePictureMirrored); -// warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority); - - } else if (itemEntry->viewId != 0xFFFF) { - GfxView *view = _cache->getView(itemEntry->viewId); - -// warning("view %s %04x:%04x", _segMan->getObjectName(itemEntry->object), PRINT_REG(itemEntry->object)); + itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); + itemEntry->y = upscaleVerticalCoordinate(itemEntry->y); + itemEntry->picStartX = upscaleHorizontalCoordinate(itemEntry->picStartX); + itemEntry->picStartY = upscaleVerticalCoordinate(itemEntry->picStartY); - - if (view->isSci2Hires()) { + if (!isPictureOutOfView(itemEntry, it->planeRect, it->planeOffsetX, it->planeOffsetY)) + drawPicture(itemEntry, it->planeOffsetX, it->planeOffsetY, it->planePictureMirrored); + } else { + GfxView *view = (itemEntry->viewId != 0xFFFF) ? _cache->getView(itemEntry->viewId) : NULL; + + if (view && view->isSci2Hires()) { int16 dummyX = 0; view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x); view->adjustToUpscaledCoordinates(itemEntry->z, dummyX); } else if (getSciVersion() == SCI_VERSION_2_1) { - itemEntry->y = (itemEntry->y * _screen->getHeight()) / scriptsRunningHeight; - itemEntry->x = (itemEntry->x * _screen->getWidth()) / scriptsRunningWidth; - itemEntry->z = (itemEntry->z * _screen->getHeight()) / scriptsRunningHeight; + itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); + itemEntry->y = upscaleVerticalCoordinate(itemEntry->y); + itemEntry->z = upscaleVerticalCoordinate(itemEntry->z); } // Adjust according to current scroll position itemEntry->x -= it->planeOffsetX; + itemEntry->y -= it->planeOffsetY; uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect)); if (useInsetRect) { itemEntry->celRect.top = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inTop)); itemEntry->celRect.left = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inLeft)); - itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)) + 1; - itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)) + 1; - if (view->isSci2Hires()) { + itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)); + itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)); + if (view && view->isSci2Hires()) { view->adjustToUpscaledCoordinates(itemEntry->celRect.top, itemEntry->celRect.left); view->adjustToUpscaledCoordinates(itemEntry->celRect.bottom, itemEntry->celRect.right); } itemEntry->celRect.translate(itemEntry->x, itemEntry->y); // 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 ((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); + } 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); Common::Rect nsRect = itemEntry->celRect; // Translate back to actual coordinate within scrollable plane - nsRect.translate(it->planeOffsetX, 0); + nsRect.translate(it->planeOffsetX, it->planeOffsetY); - if (view->isSci2Hires()) { + if (view && view->isSci2Hires()) { view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left); view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right); } else if (getSciVersion() == SCI_VERSION_2_1) { - nsRect.top = (nsRect.top * scriptsRunningHeight) / _screen->getHeight(); - nsRect.left = (nsRect.left * scriptsRunningWidth) / _screen->getWidth(); - nsRect.bottom = (nsRect.bottom * scriptsRunningHeight) / _screen->getHeight(); - nsRect.right = (nsRect.right * scriptsRunningWidth) / _screen->getWidth(); + nsRect = upscaleRect(nsRect); } - writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsLeft), nsRect.left); - writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsTop), nsRect.top); - writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsRight), nsRect.right); - writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsBottom), nsRect.bottom); + if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { + // HACK: Some (?) objects in Phantasmagoria 2 have no NS rect. Skip them for now. + // TODO: Remove once we figure out how Phantasmagoria 2 draws objects on screen. + if (lookupSelector(_segMan, itemEntry->object, SELECTOR(nsLeft), NULL, NULL) != kSelectorVariable) + continue; + } + + g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } int16 screenHeight = _screen->getHeight(); int16 screenWidth = _screen->getWidth(); - if (view->isSci2Hires()) { + if (view && view->isSci2Hires()) { screenHeight = _screen->getDisplayHeight(); screenWidth = _screen->getDisplayWidth(); } @@ -529,7 +599,8 @@ void GfxFrameout::kernelFrameout() { Common::Rect clipRect, translatedClipRect; clipRect = itemEntry->celRect; - if (view->isSci2Hires()) { + + if (view && view->isSci2Hires()) { clipRect.clip(it->upscaledPlaneClipRect); translatedClipRect = clipRect; translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top); @@ -539,33 +610,20 @@ void GfxFrameout::kernelFrameout() { translatedClipRect.translate(it->planeRect.left, it->planeRect.top); } - if (!clipRect.isEmpty()) { - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->draw(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); - else - view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); - } - } else { - // Most likely a text entry - if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) { - TextEntry *textEntry = g_sci->_gfxText32->getTextEntry(itemEntry->object); - uint16 startX = ((textEntry->x * _screen->getWidth()) / scriptsRunningWidth) + it->planeRect.left; - uint16 startY = ((textEntry->y * _screen->getHeight()) / scriptsRunningHeight) + it->planeRect.top; - // HACK. The plane sometimes doesn't contain the correct width. This - // hack breaks the dialog options when speaking with Grace, but it's - // the best we got up to now. This happens because of the unimplemented - // kTextWidth function in SCI32. - // TODO: Remove this once kTextWidth has been implemented. - uint16 w = it->planeRect.width() >= 20 ? it->planeRect.width() : _screen->getWidth() - 10; - - // Upscale the coordinates/width if the fonts are already upscaled - if (_screen->fontIsUpscaled()) { - startX = startX * _screen->getDisplayWidth() / _screen->getWidth(); - startY = startY * _screen->getDisplayHeight() / _screen->getHeight(); - w = w * _screen->getDisplayWidth() / _screen->getWidth(); + if (view) { + if (!clipRect.isEmpty()) { + if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) + view->draw(itemEntry->celRect, clipRect, translatedClipRect, + itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); + else + view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, + itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); } + } - g_sci->_gfxText32->drawTextBitmap(itemEntry->object, startX, startY, w); + // Draw text, if it exists + if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) { + g_sci->_gfxText32->drawTextBitmap(itemEntry->x, itemEntry->y, it->planeRect, itemEntry->object); } } } |