From 4a16ebc970bfe1eae948b5d59accc321b092db8c Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Thu, 10 Mar 2016 14:05:27 -0600 Subject: SCI32: Implement kSetNowSeen --- engines/sci/engine/kernel.h | 1 - engines/sci/engine/kernel_tables.h | 5 +- engines/sci/engine/kgraphics.cpp | 14 ++++- engines/sci/graphics/compare.cpp | 21 ------- engines/sci/graphics/frameout.cpp | 20 +++++++ engines/sci/graphics/frameout.h | 1 + engines/sci/graphics/screen_item32.cpp | 103 +++++++++++++++++++++++++++++++++ engines/sci/graphics/screen_item32.h | 7 +++ 8 files changed, 146 insertions(+), 26 deletions(-) (limited to 'engines/sci') diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index d521d4f057..6feaeb865b 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -452,7 +452,6 @@ reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv); reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv); reg_t kMulDiv(EngineState *s, int argc, reg_t *argv); -reg_t kSetNowSeen32(EngineState *s, int argc, reg_t *argv); reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv); reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index ad07072aea..1cb02d4e33 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -568,7 +568,10 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL }, { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL }, { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, - { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL }, + { MAP_CALL(SetNowSeen), SIG_SCI16, SIGFOR_ALL, "o(i)", NULL, NULL }, +#ifdef ENABLE_SCI32 + { MAP_CALL(SetNowSeen), SIG_SCI32, SIGFOR_ALL, "o", NULL, NULL }, +#endif { MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds }, { MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL }, { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL }, diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 93d0d91b65..c79ffa9dd5 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -572,9 +572,17 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) { } reg_t kSetNowSeen(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxCompare->kernelSetNowSeen(argv[0]); - - return s->r_acc; +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2) { + g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]); + return NULL_REG; + } else { +#endif + g_sci->_gfxCompare->kernelSetNowSeen(argv[0]); + return s->r_acc; +#ifdef ENABLE_SCI32 + } +#endif } reg_t kPalette(EngineState *s, int argc, reg_t *argv) { diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp index 698ad1baf1..2f83017915 100644 --- a/engines/sci/graphics/compare.cpp +++ b/engines/sci/graphics/compare.cpp @@ -122,9 +122,6 @@ uint16 GfxCompare::kernelOnControl(byte screenMask, const Common::Rect &rect) { void GfxCompare::kernelSetNowSeen(reg_t objectReference) { GfxView *view = NULL; Common::Rect celRect(0, 0); - // TODO/FIXME: Torin's menu code tries to draw special views with an ID of 0xFFFF, which - // are not currently handled properly and cause a crash. These might be text views that - // are not properly implemented. GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view)); int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop)); int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel)); @@ -135,26 +132,8 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) { z = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(z)); view = _cache->getView(viewId); - -#ifdef ENABLE_SCI32 - if (view->isSci2Hires()) - view->adjustToUpscaledCoordinates(y, x); - else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) - _coordAdjuster->fromScriptToDisplay(y, x); -#endif - view->getCelRect(loopNo, celNo, x, y, z, celRect); -#ifdef ENABLE_SCI32 - if (view->isSci2Hires()) { - view->adjustBackUpscaledCoordinates(celRect.top, celRect.left); - view->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); - } else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) { - _coordAdjuster->fromDisplayToScript(celRect.top, celRect.left); - _coordAdjuster->fromDisplayToScript(celRect.bottom, celRect.right); - } -#endif - if (lookupSelector(_segMan, objectReference, SELECTOR(nsTop), NULL, NULL) == kSelectorVariable) { setNSRect(objectReference, celRect); } diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 655e59de00..78e61b9e34 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -2028,6 +2028,26 @@ bool GfxFrameout::isOnMe(const ScreenItem &screenItem, const Plane &plane, const return true; } +void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const { + const reg_t planeObject = readSelector(_segMan, screenItemObject, SELECTOR(plane)); + + Plane *plane = _planes.findByObject(planeObject); + if (plane == nullptr) { + error("Plane %04x:%04x not found", PRINT_REG(planeObject)); + } + + ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject); + if (screenItem == nullptr) { + error("Screen item %04x:%04x not found", PRINT_REG(screenItemObject)); + } + + Common::Rect result = screenItem->getNowSeenRect(*plane); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsLeft), result.left); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsTop), result.top); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsRight), result.right - 1); + writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsBottom), result.bottom - 1); +} + #pragma mark - #pragma mark Debugging diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index f864abc5bc..969123f4d3 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -245,6 +245,7 @@ public: void kernelAddScreenItem(const reg_t object); void kernelUpdateScreenItem(const reg_t object); void kernelDeleteScreenItem(const reg_t object); + void kernelSetNowSeen(const reg_t screenItemObject) const; #pragma mark - #pragma mark Planes diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp index 4a42221875..9f6dc7a2a2 100644 --- a/engines/sci/graphics/screen_item32.cpp +++ b/engines/sci/graphics/screen_item32.cpp @@ -495,6 +495,109 @@ void ScreenItem::update(const reg_t object) { _deleted = 0; } +// TODO: This code is quite similar to calcRects, so try to deduplicate +// if possible +Common::Rect ScreenItem::getNowSeenRect(const Plane &plane) const { + CelObj &celObj = getCelObj(); + + Common::Rect celObjRect(celObj._width, celObj._height); + Common::Rect nsRect; + + if (_useInsetRect) { + // TODO: This is weird. Checking to see if the inset rect is + // fully inside the bounds of the celObjRect, and then + // clipping to the celObjRect, is pretty useless. + if (_insetRect.right > 0 && _insetRect.bottom > 0 && _insetRect.left < celObj._width && _insetRect.top < celObj._height) { + nsRect = _insetRect; + nsRect.clip(celObjRect); + } else { + nsRect = Common::Rect(); + } + } else { + nsRect = celObjRect; + } + + const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + Ratio scaleX, scaleY; + if (_scale.signal & kScaleSignalDoScaling32) { + if (_scale.signal & kScaleSignalUseVanishingPoint) { + int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y); + scaleX = Ratio(num, 128); + scaleY = Ratio(num, 128); + } else { + scaleX = Ratio(_scale.x, 128); + scaleY = Ratio(_scale.y, 128); + } + } + + if (scaleX.getNumerator() == 0 || scaleY.getNumerator() == 0) { + return Common::Rect(); + } + + int16 displaceX = celObj._displace.x; + int16 displaceY = celObj._displace.y; + + if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { + displaceX = celObj._width - displaceX - 1; + } + + if (celObj._scaledWidth != scriptWidth || celObj._scaledHeight != scriptHeight) { + if (_useInsetRect) { + Ratio scriptToScaledX(celObj._scaledWidth, scriptWidth); + Ratio scriptToScaledY(celObj._scaledHeight, scriptHeight); + mulru(nsRect, scriptToScaledX, scriptToScaledY, 0); + + // TODO: This is weird. Checking to see if the inset rect is + // fully inside the bounds of the celObjRect, and then + // clipping to the celObjRect, is pretty useless. + if (nsRect.right > 0 && nsRect.bottom > 0 && nsRect.left < celObj._width && nsRect.top < celObj._height) { + nsRect.clip(celObjRect); + } else { + nsRect = Common::Rect(); + } + } + + if (!scaleX.isOne() || !scaleY.isOne()) { + mulinc(nsRect, scaleX, scaleY); + // TODO: This was in the original code, baked into the + // multiplication though it is not immediately clear + // why this is the only one that reduces the BR corner + nsRect.right -= 1; + nsRect.bottom -= 1; + } + + Ratio scaledToScriptX(scriptWidth, celObj._scaledWidth); + Ratio scaledToScriptY(scriptHeight, celObj._scaledHeight); + + displaceX = (displaceX * scaleX * scaledToScriptX).toInt(); + displaceY = (displaceY * scaleY * scaledToScriptY).toInt(); + + mulinc(nsRect, scaledToScriptX, scaledToScriptY); + nsRect.translate(_position.x - displaceX, _position.y - displaceY); + } else { + if (!scaleX.isOne() || !scaleY.isOne()) { + mulinc(nsRect, scaleX, scaleY); + // TODO: This was in the original code, baked into the + // multiplication though it is not immediately clear + // why this is the only one that reduces the BR corner + nsRect.right -= 1; + nsRect.bottom -= 1; + } + + displaceX = (displaceX * scaleX).toInt(); + displaceY = (displaceY * scaleY).toInt(); + nsRect.translate(_position.x - displaceX, _position.y - displaceY); + + if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { + nsRect.translate(plane._gameRect.width() - nsRect.width(), 0); + } + } + + return nsRect; +} + #pragma mark - #pragma mark ScreenItemList ScreenItem *ScreenItemList::findByObject(const reg_t object) const { diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h index 52782acc56..977d80ebad 100644 --- a/engines/sci/graphics/screen_item32.h +++ b/engines/sci/graphics/screen_item32.h @@ -259,6 +259,13 @@ public: * VM object. */ void update(const reg_t object); + + /** + * Gets the "now seen" rect for the screen item, which + * represents the current size and position of the + * screen item on the screen in script coordinates. + */ + Common::Rect getNowSeenRect(const Plane &plane) const; }; #pragma mark - -- cgit v1.2.3