diff options
Diffstat (limited to 'engines/sci/engine/kgraphics32.cpp')
-rw-r--r-- | engines/sci/engine/kgraphics32.cpp | 1359 |
1 files changed, 754 insertions, 605 deletions
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 8953f45266..9cfe53255b 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -26,8 +26,6 @@ #include "graphics/cursorman.h" #include "graphics/surface.h" -#include "gui/message.h" - #include "sci/sci.h" #include "sci/event.h" #include "sci/resource.h" @@ -45,14 +43,19 @@ #include "sci/graphics/paint16.h" #include "sci/graphics/picture.h" #include "sci/graphics/ports.h" +#include "sci/graphics/remap.h" #include "sci/graphics/screen.h" #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/celobj32.h" #include "sci/graphics/controls32.h" #include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class -#include "sci/graphics/text32.h" #include "sci/graphics/frameout.h" +#include "sci/graphics/paint32.h" +#include "sci/graphics/palette32.h" +#include "sci/graphics/remap32.h" +#include "sci/graphics/text32.h" #endif namespace Sci { @@ -61,63 +64,67 @@ namespace Sci { extern void showScummVMDialog(const Common::String &message); reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { - // Returns 0 if the screen width or height is less than 640 or 400, - // respectively. - if (g_system->getWidth() < 640 || g_system->getHeight() < 400) + const Buffer &buffer = g_sci->_gfxFrameout->getCurrentBuffer(); + if (buffer.screenWidth < 640 || buffer.screenHeight < 400) return make_reg(0, 0); return make_reg(0, 1); } -// SCI32 variant, can't work like sci16 variants -reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { - // TODO -// reg_t curObject = argv[0]; -// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; - - return NULL_REG; -} - reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { - if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL) - g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); - else - g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + debugC(6, kDebugLevelGraphics, "kAddScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); + g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); return s->r_acc; } reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) { + debugC(7, kDebugLevelGraphics, "kUpdateScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); return s->r_acc; } reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) { + debugC(6, kDebugLevelGraphics, "kDeleteScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]); return s->r_acc; } reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { + debugC(6, kDebugLevelGraphics, "kAddPlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); g_sci->_gfxFrameout->kernelAddPlane(argv[0]); return s->r_acc; } +reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { + debugC(7, kDebugLevelGraphics, "kUpdatePlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); + g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); + return s->r_acc; +} + reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { + debugC(6, kDebugLevelGraphics, "kDeletePlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0])); g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); return s->r_acc; } -reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); +reg_t kMovePlaneItems(EngineState *s, int argc, reg_t *argv) { + const reg_t plane = argv[0]; + const int16 deltaX = argv[1].toSint16(); + const int16 deltaY = argv[2].toSint16(); + const bool scrollPics = argc > 3 ? argv[3].toUint16() : false; + + g_sci->_gfxFrameout->kernelMovePlaneItems(plane, deltaX, deltaY, scrollPics); return s->r_acc; } reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { reg_t planeObj = argv[0]; GuiResourceId pictureId = argv[1].toUint16(); - int16 pictureX = argv[2].toSint16(); - int16 pictureY = argv[3].toSint16(); + int16 x = argv[2].toSint16(); + int16 y = argv[3].toSint16(); + bool mirrorX = argc > 4 ? argv[4].toSint16() : false; - g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY); + g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX); return s->r_acc; } @@ -126,8 +133,14 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) { } reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelFrameout(); - return NULL_REG; + bool showBits = argc > 0 ? argv[0].toUint16() : true; + g_sci->_gfxFrameout->kernelFrameOut(showBits); + return s->r_acc; +} + +reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16()); + return s->r_acc; } reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { @@ -136,81 +149,95 @@ reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { return make_reg(0, objRect1.intersects(objRect2)); } -// Tests if the coordinate is on the passed object reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { - uint16 x = argv[0].toUint16(); - uint16 y = argv[1].toUint16(); - reg_t targetObject = argv[2]; - uint16 illegalBits = argv[3].getOffset(); - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject); - - uint16 itemX = readSelectorValue(s->_segMan, targetObject, SELECTOR(x)); - uint16 itemY = readSelectorValue(s->_segMan, targetObject, SELECTOR(y)); - // If top and left are negative, we need to adjust coordinates by the item's x and y - if (nsRect.left < 0) - nsRect.translate(itemX, 0); - if (nsRect.top < 0) - nsRect.translate(0, itemY); - - // we assume that x, y are local coordinates - - bool contained = nsRect.contains(x, y); - if (contained && illegalBits) { - // If illegalbits are set, we check the color of the pixel that got clicked on - // for now, we return false if the pixel is transparent - // although illegalBits may get differently set, don't know yet how this really works out - uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view)); - int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop)); - int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel)); - if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) - contained = false; - } - return make_reg(0, contained); + int16 x = argv[0].toSint16(); + int16 y = argv[1].toSint16(); + reg_t object = argv[2]; + bool checkPixel = argv[3].toSint16(); + + return g_sci->_gfxFrameout->kernelIsOnMe(object, Common::Point(x, y), checkPixel); } reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: { - if (argc != 4) { - warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[3]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", - PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - int16 maxWidth = argv[1].toUint16(); - int16 maxHeight = argv[2].toUint16(); - g_sci->_gfxCoordAdjuster->fromScriptToDisplay(maxHeight, maxWidth); - // These values can be larger than the screen in the SQ6 demo, room 100 - // TODO: Find out why. For now, don't show any text in that room. - if (g_sci->getGameId() == GID_SQ6 && g_sci->isDemo() && s->currentRoomNumber() == 100) - return NULL_REG; - return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); - } - case 1: { - if (argc != 2) { - warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[1]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - return g_sci->_gfxText32->createTextBitmap(object); - } - default: - warning("CreateTextBitmap(%d)", argv[0].toUint16()); + SegManager *segMan = s->_segMan; + + int16 subop = argv[0].toUint16(); + + int16 width = 0; + int16 height = 0; + reg_t object; + + if (subop == 0) { + width = argv[1].toUint16(); + height = argv[2].toUint16(); + object = argv[3]; + } else if (subop == 1) { + object = argv[1]; + } else { + warning("Invalid kCreateTextBitmap subop %d", subop); return NULL_REG; } + + Common::String text = segMan->getString(readSelector(segMan, object, SELECTOR(text))); + int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore)); + int16 backColor = readSelectorValue(segMan, object, SELECTOR(back)); + int16 skipColor = readSelectorValue(segMan, object, SELECTOR(skip)); + GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font)); + int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor)); + int16 dimmed = readSelectorValue(segMan, object, SELECTOR(dimmed)); + + Common::Rect rect( + readSelectorValue(segMan, object, SELECTOR(textLeft)), + readSelectorValue(segMan, object, SELECTOR(textTop)), + readSelectorValue(segMan, object, SELECTOR(textRight)) + 1, + readSelectorValue(segMan, object, SELECTOR(textBottom)) + 1 + ); + + if (subop == 0) { + TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode)); + return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true); + } else { + CelInfo32 celInfo; + celInfo.type = kCelTypeView; + celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view)); + celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); + celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel)); + return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed); + } } -reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxText32->disposeTextBitmap(argv[0]); +reg_t kText(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->setFont(argv[2].toUint16()); + + reg_t *rect = s->_segMan->derefRegPtr(argv[0], 4); + if (rect == nullptr) { + error("kTextSize: %04x:%04x cannot be dereferenced", PRINT_REG(argv[0])); + } + + Common::String text = s->_segMan->getString(argv[1]); + int16 maxWidth = argc > 3 ? argv[3].toSint16() : 0; + bool doScaling = argc > 4 ? argv[4].toSint16() : true; + + Common::Rect textRect = g_sci->_gfxText32->getTextSize(text, maxWidth, doScaling); + rect[0] = make_reg(0, textRect.left); + rect[1] = make_reg(0, textRect.top); + rect[2] = make_reg(0, textRect.right - 1); + rect[3] = make_reg(0, textRect.bottom - 1); return s->r_acc; } +reg_t kTextWidth(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->setFont(argv[1].toUint16()); + Common::String text = s->_segMan->getString(argv[0]); + return make_reg(0, g_sci->_gfxText32->getStringWidth(text)); +} + reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case 1: @@ -228,442 +255,508 @@ reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +reg_t kMessageBox(EngineState *s, int argc, reg_t *argv) { + return g_sci->_gfxControls32->kernelMessageBox(s->_segMan->getString(argv[0]), s->_segMan->getString(argv[1]), argv[2].toUint16()); +} + /** - * Used for scene transitions, replacing (but reusing parts of) the old - * transition code. + * Causes an immediate plane transition with an optional transition + * effect */ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { - // Can be called with 7 or 8 parameters - // The style defines which transition to perform. Related to the transition - // tables inside graphics/transitions.cpp - uint16 showStyle = argv[0].toUint16(); // 0 - 15 - reg_t planeObj = argv[1]; // the affected plane - Common::String planeObjName = s->_segMan->getObjectName(planeObj); - uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts - uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff - int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out - uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts - uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out + ShowStyleType type = (ShowStyleType)argv[0].toUint16(); + reg_t planeObj = argv[1]; + int16 seconds = argv[2].toSint16(); + // NOTE: This value seems to indicate whether the transition is an + // “exit” transition (0) or an “enter” transition (-1) for fade + // transitions. For other types of transitions, it indicates a palette + // index value to use when filling the screen. + int16 back = argv[3].toSint16(); + int16 priority = argv[4].toSint16(); + int16 animate = argv[5].toSint16(); + // TODO: Rename to frameOutNow? + int16 refFrame = argv[6].toSint16(); + int16 blackScreen; + reg_t pFadeArray; int16 divisions; - // If the game has the pFadeArray selector, another parameter is used here, - // before the optional last parameter - bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; - if (hasFadeArray) { - // argv[7] - divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) - } else { - divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) + // SCI 2–2.1early + if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) { + blackScreen = 0; + pFadeArray = NULL_REG; + divisions = argc > 7 ? argv[7].toSint16() : -1; } - - if (showStyle > 15) { - warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); - return s->r_acc; + // SCI 2.1mid–2.1late + else if (getSciVersion() < SCI_VERSION_3) { + blackScreen = 0; + pFadeArray = argc > 7 ? argv[7] : NULL_REG; + divisions = argc > 8 ? argv[8].toSint16() : -1; + } + // SCI 3 + else { + blackScreen = argv[7].toSint16(); + pFadeArray = argc > 8 ? argv[8] : NULL_REG; + divisions = argc > 9 ? argv[9].toSint16() : -1; } - // GK1 calls fadeout (13) / fadein (14) with the following parameters: - // seconds: 1 - // backColor: 0 / -1 - // fade: 200 - // animate: 0 - // refFrame: 0 - // divisions: 0 / 20 +// TODO: Reuse later for SCI2 and SCI3 implementation and then discard +// warning("kSetShowStyle: effect %d, plane: %04x:%04x (%s), sec: %d, " +// "dir: %d, prio: %d, animate: %d, ref frame: %d, black screen: %d, " +// "pFadeArray: %04x:%04x (%s), divisions: %d", +// type, PRINT_REG(planeObj), s->_segMan->getObjectName(planeObj), seconds, +// back, priority, animate, refFrame, blackScreen, +// PRINT_REG(pFadeArray), s->_segMan->getObjectName(pFadeArray), divisions); - // TODO: Check if the plane is in the list of planes to draw + // NOTE: The order of planeObj and showStyle are reversed + // because this is how SCI3 called the corresponding method + // on the KernelMgr + g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen); - Common::String effectName = "unknown"; + return s->r_acc; +} - switch (showStyle) { - case 0: // no transition / show - effectName = "show"; - break; - case 13: // fade out - effectName = "fade out"; - // TODO - break; - case 14: // fade in - effectName = "fade in"; - // TODO - break; - default: - // TODO - break; - } +reg_t kCelHigh32(EngineState *s, int argc, reg_t *argv) { + GuiResourceId resourceId = argv[0].toUint16(); + int16 loopNo = argv[1].toSint16(); + int16 celNo = argv[2].toSint16(); + CelObjView celObj(resourceId, loopNo, celNo); + return make_reg(0, mulru(celObj._height, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, celObj._scaledHeight))); +} - warning("kSetShowStyle: effect %d (%s) - plane: %04x:%04x (%s), sec: %d, " - "back: %d, prio: %d, animate: %d, ref frame: %d, divisions: %d", - showStyle, effectName.c_str(), PRINT_REG(planeObj), planeObjName.c_str(), - seconds, backColor, priority, animate, refFrame, divisions); - return s->r_acc; +reg_t kCelWide32(EngineState *s, int argc, reg_t *argv) { + GuiResourceId resourceId = argv[0].toUint16(); + int16 loopNo = argv[1].toSint16(); + int16 celNo = argv[2].toSint16(); + CelObjView celObj(resourceId, loopNo, celNo); + return make_reg(0, mulru(celObj._width, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, celObj._scaledWidth))); } reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) { // Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board // are occupied by pieces already - switch (argv[0].toUint16()) { // subops 0 - 4 - // 0 - return the view - // 1 - return the loop - // 2, 3 - nop - case 4: { - GuiResourceId viewId = argv[1].toSint16(); - int16 loopNo = argv[2].toSint16(); - int16 celNo = argv[3].toSint16(); - int16 x = argv[4].toUint16(); - int16 y = argv[5].toUint16(); - byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y); - return make_reg(0, color); - } - default: { - kStub(s, argc, argv); - return s->r_acc; - } - } -} + CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16()); -reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { - // Used by SQ6 and LSL6 hires for the text area in the bottom of the - // screen. The relevant scripts also exist in Phantasmagoria 1, but they're - // unused. This is always called by scripts 64906 (ScrollerWindow) and - // 64907 (ScrollableWindow). - - reg_t kWindow = argv[1]; - uint16 op = argv[0].toUint16(); - switch (op) { - case 0: // Init - // TODO: Init reads the nsLeft, nsTop, nsRight, nsBottom, - // borderColor, fore, back, mode, font, plane selectors - // from the window in argv[1]. - g_sci->_gfxFrameout->initScrollText(argv[2].toUint16()); // maxItems - g_sci->_gfxFrameout->clearScrollTexts(); - return argv[1]; // kWindow - case 1: // Show message, called by ScrollableWindow::addString - case 14: // Modify message, called by ScrollableWindow::modifyString - // TODO: The parameters in Modify are shifted by one: the first - // argument is the handle of the text to modify. The others - // are as Add. - { - Common::String text = s->_segMan->getString(argv[2]); - uint16 x = 0; - uint16 y = 0; - // TODO: argv[3] is font - // TODO: argv[4] is color - // TODO: argv[5] is alignment (0 = left, 1 = center, 2 = right) - // font,color,alignment may also be -1. (Maybe same as previous?) - // TODO: argv[6] is an optional bool, defaulting to true if not present. - // If true, the old contents are scrolled out of view. - // TODO: Return a handle of the inserted text. (Used for modify/insert) - // This handle looks like it should also be usable by kString. - g_sci->_gfxFrameout->addScrollTextEntry(text, kWindow, x, y, (op == 14)); - } - break; - case 2: // Clear, called by ScrollableWindow::erase - g_sci->_gfxFrameout->clearScrollTexts(); - break; - case 3: // Page up, called by ScrollableWindow::scrollTo - // TODO - kStub(s, argc, argv); - break; - case 4: // Page down, called by ScrollableWindow::scrollTo - // TODO - kStub(s, argc, argv); - break; - case 5: // Up arrow, called by ScrollableWindow::scrollTo - g_sci->_gfxFrameout->prevScrollText(); - break; - case 6: // Down arrow, called by ScrollableWindow::scrollTo - g_sci->_gfxFrameout->nextScrollText(); - break; - case 7: // Home, called by ScrollableWindow::scrollTo - g_sci->_gfxFrameout->firstScrollText(); - break; - case 8: // End, called by ScrollableWindow::scrollTo - g_sci->_gfxFrameout->lastScrollText(); - break; - case 9: // Resize, called by ScrollableWindow::resize and ScrollerWindow::resize - // TODO: This reads the nsLeft, nsTop, nsRight, nsBottom - // selectors from the SCI object passed in argv[2]. - kStub(s, argc, argv); - break; - case 10: // Where, called by ScrollableWindow::where - // TODO: - // Gives the current relative scroll location as a fraction - // with argv[2] as the denominator. (Return value is the numerator.) - // Silenced the warnings because of the high amount of console spam - //kStub(s, argc, argv); - break; - case 11: // Go, called by ScrollableWindow::scrollTo - // TODO: - // Two arguments provide a fraction: argv[2] is num., argv[3] is denom. - // Scrolls to the relative location given by the fraction. - kStub(s, argc, argv); - break; - case 12: // Insert, called by ScrollableWindow::insertString - // 5 extra parameters here: - // handle of insert location (new string takes that position). - // text, font, color, alignment - // TODO - kStub(s, argc, argv); - break; - // case 13 (Delete) is handled below - // case 14 (Modify) is handled above - case 15: // Hide, called by ScrollableWindow::hide - g_sci->_gfxFrameout->toggleScrollText(false); - break; - case 16: // Show, called by ScrollableWindow::show - g_sci->_gfxFrameout->toggleScrollText(true); + int16 result = 0; + + switch (argv[0].toUint16()) { + case 0: + result = view._displace.x; break; - case 17: // Destroy, called by ScrollableWindow::dispose - g_sci->_gfxFrameout->clearScrollTexts(); + case 1: + result = view._displace.y; break; - case 13: // Delete, unused - case 18: // Text, unused - case 19: // Reconstruct, unused - error("kScrollWindow: Unused subop %d invoked", op); + case 2: + case 3: + // null operation break; - default: - error("kScrollWindow: unknown subop %d", op); + case 4: + result = view.readPixel(argv[4].toSint16(), argv[5].toSint16(), view._mirrorX); break; } + return make_reg(0, result); +} + +reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv) { + const reg_t object = argv[0]; + const uint16 maxNumEntries = argv[1].toUint16(); + + SegManager *segMan = s->_segMan; + const int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor)); + const TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode)); + const GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font)); + const int16 backColor = readSelectorValue(segMan, object, SELECTOR(back)); + const int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore)); + const reg_t plane = readSelector(segMan, object, SELECTOR(plane)); + + Common::Rect rect; + rect.left = readSelectorValue(segMan, object, SELECTOR(nsLeft)); + rect.top = readSelectorValue(segMan, object, SELECTOR(nsTop)); + rect.right = readSelectorValue(segMan, object, SELECTOR(nsRight)) + 1; + rect.bottom = readSelectorValue(segMan, object, SELECTOR(nsBottom)) + 1; + const Common::Point position(rect.left, rect.top); + + return g_sci->_gfxControls32->makeScrollWindow(rect, position, plane, foreColor, backColor, fontId, alignment, borderColor, maxNumEntries); +} + +reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + const Common::String text = s->_segMan->getString(argv[1]); + const GuiResourceId fontId = argv[2].toSint16(); + const int16 color = argv[3].toSint16(); + const TextAlign alignment = (TextAlign)argv[4].toSint16(); + const bool scrollTo = argc > 5 ? (bool)argv[5].toUint16() : true; + + return scrollWindow->add(text, fontId, color, alignment, scrollTo); +} + +reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + const uint16 where = (argv[1].toUint16() * scrollWindow->where()).toInt(); + + return make_reg(0, where); +} + +reg_t kScrollWindowGo(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + const Ratio scrollTop(argv[1].toSint16(), argv[2].toSint16()); + scrollWindow->go(scrollTop); + return s->r_acc; } -reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { - // TODO: This defines the resolution that the fonts are supposed to be displayed - // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but - // should be extended to handle other font resolutions such as those +reg_t kScrollWindowModify(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); - int xResolution = argv[0].toUint16(); - //int yResolution = argv[1].toUint16(); + const reg_t entryId = argv[1]; + const Common::String newText = s->_segMan->getString(argv[2]); + const GuiResourceId fontId = argv[3].toSint16(); + const int16 color = argv[4].toSint16(); + const TextAlign alignment = (TextAlign)argv[5].toSint16(); + const bool scrollTo = argc > 6 ? (bool)argv[6].toUint16() : true; + + return scrollWindow->modify(entryId, newText, fontId, color, alignment, scrollTo); +} - g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && - g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); +reg_t kScrollWindowHide(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + scrollWindow->hide(); return s->r_acc; } -reg_t kFont(EngineState *s, int argc, reg_t *argv) { - // Handle font settings for SCI2.1 +reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); - switch (argv[0].toUint16()) { - case 1: - // Set font resolution - return kSetFontRes(s, argc - 1, argv + 1); - default: - warning("kFont: unknown subop %d", argv[0].toUint16()); - } + scrollWindow->show(); + + return s->r_acc; +} + +reg_t kScrollWindowPageUp(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + scrollWindow->pageUp(); + + return s->r_acc; +} + +reg_t kScrollWindowPageDown(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + scrollWindow->pageDown(); + + return s->r_acc; +} + +reg_t kScrollWindowUpArrow(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + scrollWindow->upArrow(); + + return s->r_acc; +} + +reg_t kScrollWindowDownArrow(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + scrollWindow->downArrow(); + + return s->r_acc; +} + +reg_t kScrollWindowHome(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); + + scrollWindow->home(); return s->r_acc; } -// TODO: Eventually, all of the kBitmap operations should be put -// in a separate class +reg_t kScrollWindowEnd(EngineState *s, int argc, reg_t *argv) { + ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]); -#define BITMAP_HEADER_SIZE 46 + scrollWindow->end(); + + return s->r_acc; +} + +reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxControls32->destroyScrollWindow(argv[0]); + + return s->r_acc; +} + +reg_t kFont(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kSetFontHeight(EngineState *s, int argc, reg_t *argv) { + // TODO: Setting font may have just been for side effect + // of setting the fontHeight on the font manager, in + // which case we could just get the font directly ourselves. + g_sci->_gfxText32->setFont(argv[0].toUint16()); + g_sci->_gfxText32->_scaledHeight = (g_sci->_gfxText32->_font->getHeight() * g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight + g_sci->_gfxText32->_scaledHeight - 1) / g_sci->_gfxText32->_scaledHeight; + return make_reg(0, g_sci->_gfxText32->_scaledHeight); +} + +reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->_scaledWidth = argv[0].toUint16(); + g_sci->_gfxText32->_scaledHeight = argv[1].toUint16(); + return s->r_acc; +} reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { - // Used for bitmap operations in SCI2.1 and SCI3. - // This is the SCI2.1 version, the functionality seems to have changed in SCI3. + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - switch (argv[0].toUint16()) { - case 0: // init bitmap surface - { - // 6 params, called e.g. from TextView::init() in Torin's Passage, - // script 64890 and TransView::init() in script 64884 - uint16 width = argv[1].toUint16(); - uint16 height = argv[2].toUint16(); - //uint16 skip = argv[3].toUint16(); - uint16 back = argv[4].toUint16(); // usually equals skip - //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0; - //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0; - //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0; - - // TODO: skip, width2, height2, transparentFlag - // (used for transparent bitmaps) - int entrySize = width * height + BITMAP_HEADER_SIZE; - reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize); - byte *memoryPtr = s->_segMan->getHunkPointer(memoryId); - memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header - memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); - // Save totalWidth, totalHeight - // TODO: Save the whole bitmap header, like SSCI does - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); - return memoryId; - } - break; - case 1: // dispose text bitmap surface - return kDisposeTextBitmap(s, argc - 1, argv + 1); - case 2: // dispose bitmap surface, with extra param - // 2 params, called e.g. from MenuItem::dispose in Torin's Passage, - // script 64893 - warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2])); - break; - case 3: // tiled surface - { - // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, - // script 64869 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - // The tiled view seems to always have 2 loops. - // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. - uint16 viewNum = argv[2].toUint16(); // vTiles selector - uint16 loop = argv[3].toUint16(); - uint16 cel = argv[4].toUint16(); - uint16 x = argv[5].toUint16(); - uint16 y = argv[6].toUint16(); - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxView *view = g_sci->_gfxCache->getView(viewNum); - uint16 tileWidth = view->getWidth(loop, cel); - uint16 tileHeight = view->getHeight(loop, cel); - const byte *tileBitmap = view->getBitmap(loop, cel); - uint16 width = MIN<uint16>(totalWidth - x, tileWidth); - uint16 height = MIN<uint16>(totalHeight - y, tileHeight); - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; - } - } - - } - break; - case 4: // add text to bitmap - { - // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage, - // script 64894 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - Common::String text = s->_segMan->getString(argv[2]); - uint16 textX = argv[3].toUint16(); - uint16 textY = argv[4].toUint16(); - //reg_t unk5 = argv[5]; - //reg_t unk6 = argv[6]; - //reg_t unk7 = argv[7]; // skip? - //reg_t unk8 = argv[8]; // back? - //reg_t unk9 = argv[9]; - uint16 fontId = argv[10].toUint16(); - //uint16 mode = argv[11].toUint16(); - uint16 dimmed = argv[12].toUint16(); - //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"", - // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str()); - uint16 foreColor = 255; // TODO - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxFont *font = g_sci->_gfxCache->getFont(fontId); - - int16 charCount = 0; - uint16 curX = textX, curY = textY; - const char *txt = text.c_str(); - - while (*txt) { - charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font); - if (charCount == 0) - break; - - for (int i = 0; i < charCount; i++) { - unsigned char curChar = txt[i]; - font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight); - curX += font->getCharWidth(curChar); - } - - curX = textX; - curY += font->getHeight(); - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces - } - - } - break; - case 5: // fill with color - { - // 6 params, called e.g. from TextView::init() and TextView::draw() - // in Torin's Passage, script 64890 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - uint16 x = argv[2].toUint16(); - uint16 y = argv[3].toUint16(); - uint16 fillWidth = argv[4].toUint16(); // width - 1 - uint16 fillHeight = argv[5].toUint16(); // height - 1 - uint16 back = argv[6].toUint16(); - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - uint16 width = MIN<uint16>(totalWidth - x, fillWidth); - uint16 height = MIN<uint16>(totalHeight - y, fillHeight); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = back; - } - } - - } - break; - default: - kStub(s, argc, argv); - break; - } +reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) { + int16 width = argv[0].toSint16(); + int16 height = argv[1].toSint16(); + int16 skipColor = argv[2].toSint16(); + int16 backColor = argv[3].toSint16(); + int16 scaledWidth = argc > 4 ? argv[4].toSint16() : g_sci->_gfxText32->_scaledWidth; + int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight; + bool useRemap = argc > 6 ? argv[6].toSint16() : false; + + BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap); + memset(bitmap.getPixels(), backColor, width * height); + return bitmap.getObject(); +} +reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) { + s->_segMan->freeHunkEntry(argv[0]); return s->r_acc; } -// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, -// but it handles events on its own, using an internal loop, instead of using SCI -// scripts for event management like kEditControl does. Called by script 64914, -// DEdit::hilite(). -reg_t kEditText(EngineState *s, int argc, reg_t *argv) { - reg_t controlObject = argv[0]; +reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) { + // bitmapMemId, (x1, y1, x2, y2) OR (x2, y2, x1, y1), line color, unknown int, unknown int + return kStubNull(s, argc + 1, argv - 1); +} - if (!controlObject.isNull()) { - g_sci->_gfxControls32->kernelTexteditChange(controlObject); - } +reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) { + BitmapResource bitmap(argv[0]); + CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16()); + + const int16 x = argc > 4 ? argv[4].toSint16() : 0; + const int16 y = argc > 5 ? argv[5].toSint16() : 0; + const int16 alignX = argc > 7 ? argv[7].toSint16() : -1; + const int16 alignY = argc > 8 ? argv[8].toSint16() : -1; + + Common::Point position( + x == -1 ? bitmap.getDisplace().x : x, + y == -1 ? bitmap.getDisplace().y : y + ); + + position.x -= alignX == -1 ? view._displace.x : alignX; + position.y -= alignY == -1 ? view._displace.y : alignY; + + Common::Rect drawRect( + position.x, + position.y, + position.x + view._width, + position.y + view._height + ); + drawRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight())); + view.draw(bitmap.getBuffer(), drawRect, position, view._mirrorX); + return s->r_acc; +} + +reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) { + // called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894 + + BitmapResource bitmap(argv[0]); + Common::String text = s->_segMan->getString(argv[1]); + Common::Rect textRect( + argv[2].toSint16(), + argv[3].toSint16(), + argv[4].toSint16() + 1, + argv[5].toSint16() + 1 + ); + int16 foreColor = argv[6].toSint16(); + int16 backColor = argv[7].toSint16(); + int16 skipColor = argv[8].toSint16(); + GuiResourceId fontId = (GuiResourceId)argv[9].toUint16(); + TextAlign alignment = (TextAlign)argv[10].toSint16(); + int16 borderColor = argv[11].toSint16(); + bool dimmed = argv[12].toUint16(); + + // NOTE: Technically the engine checks these things: + // textRect.bottom > 0 + // textRect.right > 0 + // textRect.left < bitmap.width + // textRect.top < bitmap.height + // Then clips. But this seems stupid. + textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight())); + + reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false); + CelObjMem textCel(textBitmapObject); + textCel.draw(bitmap.getBuffer(), textRect, Common::Point(textRect.left, textRect.top), false); + s->_segMan->freeHunkEntry(textBitmapObject); return s->r_acc; } +reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) { + // called e.g. from TextView::init() and TextView::draw() in Torin's Passage, script 64890 + + BitmapResource bitmap(argv[0]); + Common::Rect fillRect( + argv[1].toSint16(), + argv[2].toSint16(), + argv[3].toSint16() + 1, + argv[4].toSint16() + 1 + ); + + bitmap.getBuffer().fillRect(fillRect, argv[5].toSint16()); + return s->r_acc; +} + +reg_t kBitmapDrawBitmap(EngineState *s, int argc, reg_t *argv) { + // target bitmap, source bitmap, x, y, unknown boolean + + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv) { + // bitmap, left, top, right, bottom, foreColor, backColor + + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv) { + BitmapResource bitmap(argv[0]); + bitmap.setDisplace(Common::Point(argv[1].toSint16(), argv[2].toSint16())); + return s->r_acc; +} + +reg_t kBitmapCreateFromView(EngineState *s, int argc, reg_t *argv) { + // viewId, loopNo, celNo, skipColor, backColor, useRemap, source overlay bitmap + + return kStub(s, argc + 1, argv - 1); +} + +reg_t kBitmapCopyPixels(EngineState *s, int argc, reg_t *argv) { + // target bitmap, source bitmap + + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapClone(EngineState *s, int argc, reg_t *argv) { + // bitmap + + return kStub(s, argc + 1, argv - 1); +} + +reg_t kBitmapGetInfo(EngineState *s, int argc, reg_t *argv) { + // bitmap + + // argc 1 = get width + // argc 2 = pixel at row 0 col n + // argc 3 = pixel at row n col n + return kStub(s, argc + 1, argv - 1); +} + +reg_t kBitmapScale(EngineState *s, int argc, reg_t *argv) { + // TODO: SCI3 + return kStubNull(s, argc + 1, argv - 1); +} + +reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv) { + // TODO: SCI3 + return kStub(s, argc + 1, argv - 1); +} + +reg_t kEditText(EngineState *s, int argc, reg_t *argv) { + return g_sci->_gfxControls32->kernelEditText(argv[0]); +} + reg_t kAddLine(EngineState *s, int argc, reg_t *argv) { - reg_t plane = argv[0]; - Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16()); - Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16()); - // argv[5] is unknown (a number, usually 200) - byte color = (byte)argv[6].toUint16(); - byte priority = (byte)argv[7].toUint16(); - byte control = (byte)argv[8].toUint16(); - // argv[9] is unknown (usually a small number, 1 or 2). Thickness, perhaps? - return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, control); + const reg_t plane = argv[0]; + const Common::Point startPoint(argv[1].toSint16(), argv[2].toSint16()); + const Common::Point endPoint(argv[3].toSint16(), argv[4].toSint16()); + + int16 priority; + uint8 color; + LineStyle style; + uint16 pattern; + uint8 thickness; + + if (argc == 10) { + priority = argv[5].toSint16(); + color = (uint8)argv[6].toUint16(); + style = (LineStyle)argv[7].toSint16(); + pattern = argv[8].toUint16(); + thickness = (uint8)argv[9].toUint16(); + } else { + priority = 1000; + color = 255; + style = kLineStyleSolid; + pattern = 0; + thickness = 1; + } + + return g_sci->_gfxPaint32->kernelAddLine(plane, startPoint, endPoint, priority, color, style, pattern, thickness); } reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) { - reg_t hunkId = argv[0]; - reg_t plane = argv[1]; - Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16()); - Common::Point endPoint(argv[4].toUint16(), argv[5].toUint16()); - // argv[6] is unknown (a number, usually 200) - byte color = (byte)argv[7].toUint16(); - byte priority = (byte)argv[8].toUint16(); - byte control = (byte)argv[9].toUint16(); - // argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps? - g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control); + const reg_t screenItemObject = argv[0]; + const reg_t planeObject = argv[1]; + const Common::Point startPoint(argv[2].toSint16(), argv[3].toSint16()); + const Common::Point endPoint(argv[4].toSint16(), argv[5].toSint16()); + + int16 priority; + uint8 color; + LineStyle style; + uint16 pattern; + uint8 thickness; + + Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObject); + if (plane == nullptr) { + error("kUpdateLine: Plane %04x:%04x not found", PRINT_REG(planeObject)); + } + + ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject); + if (screenItem == nullptr) { + error("kUpdateLine: Screen item %04x:%04x not found", PRINT_REG(screenItemObject)); + } + + if (argc == 11) { + priority = argv[6].toSint16(); + color = (uint8)argv[7].toUint16(); + style = (LineStyle)argv[8].toSint16(); + pattern = argv[9].toUint16(); + thickness = (uint8)argv[10].toUint16(); + } else { + priority = screenItem->_priority; + color = screenItem->_celInfo.color; + style = kLineStyleSolid; + pattern = 0; + thickness = 1; + } + + g_sci->_gfxPaint32->kernelUpdateLine(screenItem, plane, startPoint, endPoint, priority, color, style, pattern, thickness); + return s->r_acc; } + reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) { - reg_t hunkId = argv[0]; - reg_t plane = argv[1]; - g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId); + g_sci->_gfxPaint32->kernelDeleteLine(argv[0], argv[1]); return s->r_acc; } @@ -691,158 +784,214 @@ reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) { return kStub(s, argc, argv); } -reg_t kPalVaryUnknown(EngineState *s, int argc, reg_t *argv) { - // TODO: Unknown (seems to be SCI32 exclusive) - return kStub(s, argc, argv); +// Used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270) +reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->_palMorphIsOn = true; + return s->r_acc; } -reg_t kPalVaryUnknown2(EngineState *s, int argc, reg_t *argv) { - // TODO: Unknown (seems to be SCI32 exclusive) - // It seems to be related to the day/night palette effects in QFG4, and - // accepts a palette resource ID. It is triggered right when the night - // effect is initially applied (when exiting the caves). - // In QFG4, there are two scene palettes: 790 for night, and 791 for day. - // Initially, the game starts at night time, but this is called with the - // ID of the day time palette (i.e. 791). - return kStub(s, argc, argv); +reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv) { + const GuiResourceId paletteId = argv[0].toUint16(); + g_sci->_gfxPalette32->loadPalette(paletteId); + return s->r_acc; +} + +reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv) { + const uint8 r = argv[0].toUint16(); + const uint8 g = argv[1].toUint16(); + const uint8 b = argv[2].toUint16(); + return make_reg(0, g_sci->_gfxPalette32->matchColor(r, g, b)); +} + +reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) { + uint16 fromColor = argv[0].toUint16(); + uint16 toColor = argv[1].toUint16(); + uint16 percent = argv[2].toUint16(); + g_sci->_gfxPalette32->setFade(percent, fromColor, toColor); + return s->r_acc; +} + +reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) { + GuiResourceId paletteId = argv[0].toUint16(); + int time = argc > 1 ? argv[1].toSint16() * 60 : 0; + int16 percent = argc > 2 ? argv[2].toSint16() : 100; + int16 fromColor; + int16 toColor; + + if (argc > 4) { + fromColor = argv[3].toSint16(); + toColor = argv[4].toSint16(); + } else { + fromColor = toColor = -1; + } + + g_sci->_gfxPalette32->kernelPalVarySet(paletteId, percent, time, fromColor, toColor); + return s->r_acc; +} + +reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv) { + int time = argc > 0 ? argv[0].toSint16() * 60 : 0; + int16 percent = argc > 1 ? argv[1].toSint16() : 0; + g_sci->_gfxPalette32->setVaryPercent(percent, time, -1, -1); + return s->r_acc; +} + +reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); +} + +reg_t kPalVaryOff(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxPalette32->varyOff(); + return s->r_acc; +} + +reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) { + GuiResourceId paletteId = argv[0].toUint16(); + g_sci->_gfxPalette32->kernelPalVaryMergeTarget(paletteId); + return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); +} + +reg_t kPalVarySetTime(EngineState *s, int argc, reg_t *argv) { + int time = argv[0].toSint16() * 60; + g_sci->_gfxPalette32->setVaryTime(time); + return s->r_acc; +} + +reg_t kPalVarySetTarget(EngineState *s, int argc, reg_t *argv) { + GuiResourceId paletteId = argv[0].toUint16(); + g_sci->_gfxPalette32->kernelPalVarySetTarget(paletteId); + return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); +} + +reg_t kPalVarySetStart(EngineState *s, int argc, reg_t *argv) { + GuiResourceId paletteId = argv[0].toUint16(); + g_sci->_gfxPalette32->kernelPalVarySetStart(paletteId); + return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); +} + +reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv) { + GuiResourceId paletteId = argv[0].toUint16(); + g_sci->_gfxPalette32->kernelPalVaryMergeStart(paletteId); + return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); } reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) { - // Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen) + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} - switch (argv[0].toUint16()) { - case 0: { // Palette animation initialization - // 3 or 4 extra params - // Case 1 sends fromColor and speed again, so we don't need them here. - // Only toColor is stored - //uint16 fromColor = argv[1].toUint16(); - s->_palCycleToColor = argv[2].toUint16(); - //uint16 speed = argv[3].toUint16(); - - // Invalidate the picture, so that the palette steps calls (case 1 - // below) can update its palette without it being overwritten by the - // view/picture palettes. - g_sci->_gfxScreen->_picNotValid = 1; - - // TODO: The fourth optional parameter is an unknown integer, and is 0 by default - if (argc == 5) { - // When this variant is used, picNotValid doesn't seem to be set - // (e.g. GK1 room 480). In this case, the animation step calls are - // not made, so perhaps this signifies the palette cycling steps - // to make. - // GK1 sets this to 6 (6 palette steps?) - g_sci->_gfxScreen->_picNotValid = 0; - } - kStub(s, argc, argv); - } - break; - case 1: { // Palette animation step - // This is the same as the old kPaletteAnimate call, with 1 set of colors. - // The end color is set up during initialization in case 0 above. - - // 1 or 2 extra params - uint16 fromColor = argv[1].toUint16(); - uint16 speed = (argc == 2) ? 1 : argv[2].toUint16(); - // TODO: For some reason, this doesn't set the color correctly - // (e.g. LSL6 intro, room 100, Sierra logo) - if (g_sci->_gfxPalette->kernelAnimate(fromColor, s->_palCycleToColor, speed)) - g_sci->_gfxPalette->kernelAnimateSet(); - } - // No kStub() call here, as this gets called loads of times, like kPaletteAnimate - break; - // case 2 hasn't been encountered - // case 3 hasn't been encountered - case 4: // reset any palette cycling and make the picture valid again - // Gets called when changing rooms and after palette cycling animations finish - // 0 or 1 extra params - if (argc == 1) { - g_sci->_gfxScreen->_picNotValid = 0; - // TODO: This also seems to perform more steps - } else { - // The variant with the 1 extra param resets remapping to base - // TODO - } - kStub(s, argc, argv); - break; - default: - // TODO - kStub(s, argc, argv); - break; +reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv) { + const uint16 fromColor = argv[0].toUint16(); + const uint16 toColor = argv[1].toUint16(); + const int16 direction = argv[2].toSint16(); + const uint16 delay = argc > 3 ? argv[3].toUint16() : 0; + + g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay); + return s->r_acc; +} + +reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv) { + const uint16 fromColor = argv[0].toUint16(); + const int16 speed = argc > 1 ? argv[1].toSint16() : 1; + + g_sci->_gfxPalette32->doCycle(fromColor, speed); + return s->r_acc; +} + +reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxPalette32->cycleAllPause(); + } else { + const uint16 fromColor = argv[0].toUint16(); + g_sci->_gfxPalette32->cyclePause(fromColor); } + return s->r_acc; +} + +reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxPalette32->cycleAllOn(); + } else { + const uint16 fromColor = argv[0].toUint16(); + g_sci->_gfxPalette32->cycleOn(fromColor); + } + return s->r_acc; +} +reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxPalette32->cycleAllOff(); + } else { + const uint16 fromColor = argv[0].toUint16(); + g_sci->_gfxPalette32->cycleOff(fromColor); + } return s->r_acc; } reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { - uint16 operation = argv[0].toUint16(); - - switch (operation) { - case 0: { // turn remapping off - // WORKAROUND: Game scripts in QFG4 erroneously turn remapping off in room - // 140 (the character point allocation screen) and never turn it back on, - // even if it's clearly used in that screen. - if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140) - return s->r_acc; - - int16 base = (argc >= 2) ? argv[1].toSint16() : 0; - if (base > 0) - warning("kRemapColors(0) called with base %d", base); - g_sci->_gfxPalette->resetRemapping(); - } - break; - case 1: { // remap by range - uint16 color = argv[1].toUint16(); - uint16 from = argv[2].toUint16(); - uint16 to = argv[3].toUint16(); - uint16 base = argv[4].toUint16(); - uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0; - if (unk5 > 0) - warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5); - g_sci->_gfxPalette->setRemappingRange(color, from, to, base); - } - break; - case 2: { // remap by percent - uint16 color = argv[1].toUint16(); - uint16 percent = argv[2].toUint16(); // 0 - 100 - if (argc >= 4) - warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - g_sci->_gfxPalette->setRemappingPercent(color, percent); - } - break; - case 3: { // remap to gray - // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0. - // In this room, it's used for the cloud before Baba Yaga appears. - int16 color = argv[1].toSint16(); - int16 percent = argv[2].toSint16(); // 0 - 100 - if (argc >= 4) - warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); - g_sci->_gfxPalette->setRemappingPercentGray(color, percent); - } - break; - case 4: { // remap to percent gray - // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200 - int16 color = argv[1].toSint16(); - int16 percent = argv[2].toSint16(); // 0 - 100 - // argv[3] is unknown (a number, e.g. 200) - start color, perhaps? - if (argc >= 5) - warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); - g_sci->_gfxPalette->setRemappingPercentGray(color, percent); - } - break; - case 5: { // don't map to range - //int16 mapping = argv[1].toSint16(); - uint16 intensity = argv[2].toUint16(); - // HACK for PQ4 - if (g_sci->getGameId() == GID_PQ4) - g_sci->_gfxPalette->kernelSetIntensity(0, 255, intensity, true); - - kStub(s, argc, argv); - } - break; - default: - break; + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv) { + if (argc == 0) { + g_sci->_gfxRemap32->remapAllOff(); + } else { + const uint8 color = argv[0].toUint16(); + g_sci->_gfxRemap32->remapOff(color); } + return s->r_acc; +} + +reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv) { + const uint8 color = argv[0].toUint16(); + const int16 from = argv[1].toSint16(); + const int16 to = argv[2].toSint16(); + const int16 base = argv[3].toSint16(); + // NOTE: There is an optional last parameter after `base` + // which was only used by the priority map debugger, which + // does not exist in release versions of SSCI + g_sci->_gfxRemap32->remapByRange(color, from, to, base); + return s->r_acc; +} + +reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv) { + const uint8 color = argv[0].toUint16(); + const int16 percent = argv[1].toSint16(); + // NOTE: There is an optional last parameter after `percent` + // which was only used by the priority map debugger, which + // does not exist in release versions of SSCI + g_sci->_gfxRemap32->remapByPercent(color, percent); + return s->r_acc; +} + +reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv) { + const uint8 color = argv[0].toUint16(); + const int16 gray = argv[1].toSint16(); + // NOTE: There is an optional last parameter after `gray` + // which was only used by the priority map debugger, which + // does not exist in release versions of SSCI + g_sci->_gfxRemap32->remapToGray(color, gray); + return s->r_acc; +} + +reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv) { + const uint8 color = argv[0].toUint16(); + const int16 gray = argv[1].toSint16(); + const int16 percent = argv[2].toSint16(); + // NOTE: There is an optional last parameter after `percent` + // which was only used by the priority map debugger, which + // does not exist in release versions of SSCI + g_sci->_gfxRemap32->remapToPercentGray(color, gray, percent); + return s->r_acc; +} +reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv) { + const uint8 from = argv[0].toUint16(); + const uint8 count = argv[1].toUint16(); + g_sci->_gfxRemap32->blockRange(from, count); return s->r_acc; } |