diff options
Diffstat (limited to 'engines/sci/graphics')
-rw-r--r-- | engines/sci/graphics/animate.cpp | 118 | ||||
-rw-r--r-- | engines/sci/graphics/animate.h | 12 | ||||
-rw-r--r-- | engines/sci/graphics/compare.cpp | 22 | ||||
-rw-r--r-- | engines/sci/graphics/controls.cpp | 23 | ||||
-rw-r--r-- | engines/sci/graphics/cursor.cpp | 106 | ||||
-rw-r--r-- | engines/sci/graphics/cursor.h | 13 | ||||
-rw-r--r-- | engines/sci/graphics/font.cpp | 2 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 231 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.h | 11 | ||||
-rw-r--r-- | engines/sci/graphics/menu.cpp | 2 | ||||
-rw-r--r-- | engines/sci/graphics/paint16.cpp | 8 | ||||
-rw-r--r-- | engines/sci/graphics/picture.cpp | 6 | ||||
-rw-r--r-- | engines/sci/graphics/ports.cpp | 2 | ||||
-rw-r--r-- | engines/sci/graphics/robot.cpp | 169 | ||||
-rw-r--r-- | engines/sci/graphics/robot.h | 1 | ||||
-rw-r--r-- | engines/sci/graphics/screen.cpp | 12 | ||||
-rw-r--r-- | engines/sci/graphics/text16.cpp | 79 | ||||
-rw-r--r-- | engines/sci/graphics/text16.h | 10 | ||||
-rw-r--r-- | engines/sci/graphics/transitions.cpp | 6 | ||||
-rw-r--r-- | engines/sci/graphics/view.cpp | 33 | ||||
-rw-r--r-- | engines/sci/graphics/view.h | 1 |
21 files changed, 545 insertions, 322 deletions
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index 75fbb3e097..92bdbd30c3 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -141,6 +141,7 @@ void GfxAnimate::makeSortedList(List *list) { AnimateEntry listEntry; const reg_t curObject = curNode->value; listEntry.object = curObject; + listEntry.castHandle = NULL_REG; // Get data from current object listEntry.givenOrderNo = listNr; @@ -190,7 +191,35 @@ void GfxAnimate::makeSortedList(List *list) { Common::sort(_list.begin(), _list.end(), sortHelper); } -void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) { +void GfxAnimate::applyGlobalScaling(AnimateList::iterator entry, GfxView *view) { + reg_t curObject = entry->object; + + // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY + int16 maxScale = readSelectorValue(_s->_segMan, curObject, SELECTOR(maxScale)); + int16 celHeight = view->getHeight(entry->loopNo, entry->celNo); + int16 maxCelHeight = (maxScale * celHeight) >> 7; + reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object + int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY)); + + int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY; + int16 fixedEntryY = entry->y - vanishingY; + if (!fixedEntryY) + fixedEntryY = 1; + + if ((celHeight == 0) || (fixedPortY == 0)) + error("global scaling panic"); + + entry->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY; + entry->scaleY = (entry->scaleY * 128) / celHeight; + + entry->scaleX = entry->scaleY; + + // and set objects scale selectors + writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX), entry->scaleX); + writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), entry->scaleY); +} + +void GfxAnimate::fill(byte &old_picNotValid) { reg_t curObject; uint16 signal; GfxView *view = NULL; @@ -238,36 +267,14 @@ void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) { // Process global scaling, if needed if (it->scaleSignal & kScaleSignalDoScaling) { if (it->scaleSignal & kScaleSignalGlobalScaling) { - // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY - int16 maxScale = readSelectorValue(_s->_segMan, curObject, SELECTOR(maxScale)); - int16 celHeight = view->getHeight(it->loopNo, it->celNo); - int16 maxCelHeight = (maxScale * celHeight) >> 7; - reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object - int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY)); - - int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY; - int16 fixedEntryY = it->y - vanishingY; - if (!fixedEntryY) - fixedEntryY = 1; - - if ((celHeight == 0) || (fixedPortY == 0)) - error("global scaling panic"); - - it->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY; - it->scaleY = (it->scaleY * 128) / celHeight; - - it->scaleX = it->scaleY; - - // and set objects scale selectors - writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX), it->scaleX); - writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), it->scaleY); + applyGlobalScaling(it, view); } } } - //warning("%s view %d, loop %d, cel %d", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo); + //warning("%s view %d, loop %d, cel %d, signal %x", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo, it->signal); - bool setNsRect = maySetNsRect; + bool setNsRect = true; // Create rect according to coordinates and given cel if (it->scaleSignal & kScaleSignalDoScaling) { @@ -276,8 +283,20 @@ void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) { if ((signal & kSignalHidden) && !(signal & kSignalAlwaysUpdate)) setNsRect = false; } else { - view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect); + // This special handling is not included in the other SCI1.1 interpreters and MUST NOT be + // checked in those cases, otherwise we will break games (e.g. EcoQuest 2, room 200) + if ((g_sci->getGameId() == GID_HOYLE4) && (it->scaleSignal & kScaleSignalHoyle4SpecialHandling)) { + it->celRect.left = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft)); + it->celRect.top = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop)); + it->celRect.right = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight)); + it->celRect.bottom = readSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom)); + view->getCelSpecialHoyle4Rect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect); + setNsRect = false; + } else { + view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect); + } } + if (setNsRect) { writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left); writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top); @@ -533,19 +552,6 @@ void GfxAnimate::reAnimate(Common::Rect rect) { } } -void GfxAnimate::preprocessAddToPicList() { - AnimateList::iterator it; - const AnimateList::iterator end = _list.end(); - - for (it = _list.begin(); it != end; ++it) { - if (it->priority == -1) - it->priority = _ports->kernelCoordinateToPriority(it->y); - - // Do not allow priority to get changed by fill() - it->signal |= kSignalFixedPriority; - } -} - void GfxAnimate::addToPicDrawCels() { reg_t curObject; GfxView *view = NULL; @@ -558,8 +564,33 @@ void GfxAnimate::addToPicDrawCels() { // Get the corresponding view view = _cache->getView(it->viewId); + // kAddToPic does not do loop/cel-number fixups + + if (it->priority == -1) + it->priority = _ports->kernelCoordinateToPriority(it->y); + + if (!view->isScaleable()) { + // Laura Bow 2 specific - ffs. fill() + it->scaleSignal = 0; + it->scaleY = it->scaleX = 128; + } + + // Create rect according to coordinates and given cel + if (it->scaleSignal & kScaleSignalDoScaling) { + if (it->scaleSignal & kScaleSignalGlobalScaling) { + applyGlobalScaling(it, view); + } + view->getCelScaledRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->scaleX, it->scaleY, it->celRect); + writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left); + writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top); + writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), it->celRect.right); + writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), it->celRect.bottom); + } else { + view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect); + } + // draw corresponding cel - _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY); + _paint16->drawCel(view, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY); if ((it->signal & kSignalIgnoreActor) == 0) { it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1); _paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15); @@ -628,7 +659,7 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t disposeLastCast(); makeSortedList(list); - fill(old_picNotValid, true); + fill(old_picNotValid); if (old_picNotValid) { // beginUpdate()/endUpdate() were introduced SCI1. @@ -704,7 +735,6 @@ void GfxAnimate::addToPicSetPicNotValid() { void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) { List *list; - byte tempPicNotValid = 0; _ports->setPort((Port *)_ports->_picWind); @@ -713,8 +743,6 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) error("kAddToPic called with non-list as parameter"); makeSortedList(list); - preprocessAddToPicList(); - fill(tempPicNotValid, getSciVersion() >= SCI_VERSION_1_1 ? true : false); addToPicDrawCels(); addToPicSetPicNotValid(); diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h index f25e54915e..7b5ec8ee9b 100644 --- a/engines/sci/graphics/animate.h +++ b/engines/sci/graphics/animate.h @@ -51,9 +51,10 @@ enum ViewSignals { }; enum ViewScaleSignals { - kScaleSignalDoScaling = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY) - kScaleSignalGlobalScaling = 0x0002, // means that global scaling shall get applied on that cel (sets scaleX/scaleY) - kScaleSignalUnknown2 = 0x0004 // really unknown + kScaleSignalDoScaling = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY) + kScaleSignalGlobalScaling = 0x0002, // means that global scaling shall get applied on that cel (sets scaleX/scaleY) + kScaleSignalHoyle4SpecialHandling = 0x0004 // HOYLE4-exclusive: special handling inside kAnimate, is used when giving out cards + }; struct AnimateEntry { @@ -83,6 +84,7 @@ class GfxPaint16; class GfxScreen; class GfxPalette; class GfxTransitions; +class GfxView; /** * Animate class, kAnimate and relevant functions for SCI16 (SCI0-SCI1.1) games */ @@ -94,13 +96,13 @@ public: void disposeLastCast(); bool invoke(List *list, int argc, reg_t *argv); void makeSortedList(List *list); - void fill(byte &oldPicNotValid, bool maySetNsRect); + void applyGlobalScaling(AnimateList::iterator entry, GfxView *view); + void fill(byte &oldPicNotValid); void update(); void drawCels(); void updateScreen(byte oldPicNotValid); void restoreAndDelete(int argc, reg_t *argv); void reAnimate(Common::Rect rect); - void preprocessAddToPicList(); void addToPicDrawCels(); void addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp index 1991837102..6a99d2384e 100644 --- a/engines/sci/graphics/compare.cpp +++ b/engines/sci/graphics/compare.cpp @@ -237,20 +237,24 @@ void GfxCompare::kernelBaseSetter(reg_t object) { Common::Rect celRect; GfxView *tmpView = _cache->getView(viewId); - if (tmpView->isSci2Hires()) - _screen->adjustToUpscaledCoordinates(y, x); + if (!tmpView->isScaleable()) + scaleSignal = 0; if (scaleSignal & kScaleSignalDoScaling) { - int16 scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); - int16 scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); - tmpView->getCelScaledRect(loopNo, celNo, x, y, z, scaleX, scaleY, celRect); + celRect.left = readSelectorValue(_segMan, object, SELECTOR(nsLeft)); + celRect.right = readSelectorValue(_segMan, object, SELECTOR(nsRight)); + celRect.top = readSelectorValue(_segMan, object, SELECTOR(nsTop)); + celRect.bottom = readSelectorValue(_segMan, object, SELECTOR(nsBottom)); } else { + if (tmpView->isSci2Hires()) + _screen->adjustToUpscaledCoordinates(y, x); + tmpView->getCelRect(loopNo, celNo, x, y, z, celRect); - } - if (tmpView->isSci2Hires()) { - _screen->adjustBackUpscaledCoordinates(celRect.top, celRect.left); - _screen->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); + if (tmpView->isSci2Hires()) { + _screen->adjustBackUpscaledCoordinates(celRect.top, celRect.left); + _screen->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); + } } celRect.bottom = y + 1; diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls.cpp index 1abb8478a1..66376a793c 100644 --- a/engines/sci/graphics/controls.cpp +++ b/engines/sci/graphics/controls.cpp @@ -159,6 +159,8 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) { error("kEditControl called on object that doesnt have a text reference"); text = _segMan->getString(textReference); + uint16 oldCursorPos = cursorPos; + if (!eventObject.isNull()) { textSize = text.size(); eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type)); @@ -223,6 +225,11 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) { } } + if (g_sci->getVocabulary() && !textChanged && oldCursorPos != cursorPos) { + assert(!textAddChar); + textChanged = g_sci->getVocabulary()->checkAltInput(text, cursorPos); + } + if (textChanged) { GuiResourceId oldFontId = _text16->GetFontId(); GuiResourceId fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font)); @@ -230,18 +237,28 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) { readSelectorValue(_segMan, controlObject, SELECTOR(nsRight)), readSelectorValue(_segMan, controlObject, SELECTOR(nsBottom))); _text16->SetFont(fontId); if (textAddChar) { - // We check, if we are really able to add the new char - uint16 textWidth = 0; + const char *textPtr = text.c_str(); + + // We check if we are really able to add the new char + uint16 textWidth = 0; while (*textPtr) - textWidth += _text16->_font->getCharWidth(*textPtr++); + textWidth += _text16->_font->getCharWidth((byte)*textPtr++); textWidth += _text16->_font->getCharWidth(eventKey); + + // Does it fit? if (textWidth >= rect.width()) { _text16->SetFont(oldFontId); return; } + text.insertChar(eventKey, cursorPos++); + + // Note: the following checkAltInput call might make the text + // too wide to fit, but SSCI fails to check that too. } + if (g_sci->getVocabulary()) + g_sci->getVocabulary()->checkAltInput(text, cursorPos); texteditCursorErase(); _paint16->eraseRect(rect); _text16->Box(text.c_str(), 0, rect, SCI_TEXT16_ALIGNMENT_LEFT, -1); diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index 8e69d034c8..8de9ced57c 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -49,10 +49,21 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc // center mouse cursor setPosition(Common::Point(_screen->getWidth() / 2, _screen->getHeight() / 2)); _moveZoneActive = false; + + _zoomZoneActive = false; + _zoomZone = Common::Rect(); + _zoomCursorView = 0; + _zoomCursorLoop = 0; + _zoomCursorCel = 0; + _zoomPicView = 0; + _zoomColor = 0; + _zoomMultiplier = 0; + _cursorSurface = 0; } GfxCursor::~GfxCursor() { purgeCache(); + kernelClearZoomZone(); } void GfxCursor::init(GfxCoordAdjuster *coordAdjuster, EventManager *event) { @@ -270,10 +281,10 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu // ffs. GfxCursor::setPosition (below) // Game, newPosition, validRect static const SciCursorSetPositionWorkarounds setPositionWorkarounds[] = { - { GID_ISLANDBRAIN, 84, 109, 46, 76, 174, 243 }, // island of dr. brain / game menu - { GID_LSL5, 23, 171, 0, 0, 26, 320 }, // larry 5 / skip forward helper - { GID_QFG1VGA, 64, 174, 40, 37, 74, 284 }, // Quest For Glory 1 VGA / run/walk/sleep sub-menu - { (SciGameId)0, -1, -1, -1, -1, -1, -1 } + { GID_ISLANDBRAIN, 84, 109, 46, 76, 174, 243 }, // island of dr. brain / game menu + { GID_LSL5, 23, 171, 0, 0, 26, 320 }, // larry 5 / skip forward helper + { GID_QFG1VGA, 64, 174, 40, 37, 74, 284 }, // Quest For Glory 1 VGA / run/walk/sleep sub-menu + { (SciGameId)0, -1, -1, -1, -1, -1, -1 } }; void GfxCursor::setPosition(Common::Point pos) { @@ -329,9 +340,10 @@ Common::Point GfxCursor::getPosition() { } void GfxCursor::refreshPosition() { + Common::Point mousePoint = getPosition(); + if (_moveZoneActive) { bool clipped = false; - Common::Point mousePoint = getPosition(); if (mousePoint.x < _moveZone.left) { mousePoint.x = _moveZone.left; @@ -353,6 +365,52 @@ void GfxCursor::refreshPosition() { if (clipped) setPosition(mousePoint); } + + if (_zoomZoneActive) { + // Cursor + const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel); + const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel); + // Pic + const CelInfo *picCelInfo = _zoomPicView->getCelInfo(0, 0); + const byte *rawPicBitmap = _zoomPicView->getBitmap(0, 0); + + // Compute hotspot of cursor + Common::Point cursorHotspot = Common::Point((cursorCelInfo->width >> 1) - cursorCelInfo->displaceX, cursorCelInfo->height - cursorCelInfo->displaceY - 1); + + int16 targetX = ((mousePoint.x - _moveZone.left) * _zoomMultiplier); + int16 targetY = ((mousePoint.y - _moveZone.top) * _zoomMultiplier); + if (targetX < 0) + targetX = 0; + if (targetY < 0) + targetY = 0; + + targetX -= cursorHotspot.x; + targetY -= cursorHotspot.y; + + // Sierra SCI actually drew only within zoom area, thus removing the need to fill any other pixels with upmost/left + // color of the picture cel. This also made the cursor not appear on top of everything. They actually drew the + // cursor manually within kAnimate processing and used a hidden cursor for moving. + // TODO: we should also do this + + // Replace the special magnifier color with the associated magnified pixels + for (int x = 0; x < cursorCelInfo->width; x++) { + for (int y = 0; y < cursorCelInfo->height; y++) { + int curPos = cursorCelInfo->width * y + x; + if (cursorBitmap[curPos] == _zoomColor) { + int16 rawY = targetY + y; + int16 rawX = targetX + x; + if ((rawY >= 0) && (rawY < picCelInfo->height) && (rawX >= 0) && (rawX < picCelInfo->width)) { + int rawPos = picCelInfo->width * rawY + rawX; + _cursorSurface[curPos] = rawPicBitmap[rawPos]; + } else { + _cursorSurface[curPos] = rawPicBitmap[0]; // use left and upmost pixel color + } + } + } + } + + CursorMan.replaceCursor((const byte *)_cursorSurface, cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey); + } } void GfxCursor::kernelResetMoveZone() { @@ -364,6 +422,44 @@ void GfxCursor::kernelSetMoveZone(Common::Rect zone) { _moveZoneActive = true; } +void GfxCursor::kernelClearZoomZone() { + kernelResetMoveZone(); + _zoomZone = Common::Rect(); + _zoomColor = 0; + _zoomMultiplier = 0; + _zoomZoneActive = false; + delete _zoomCursorView; + _zoomCursorView = 0; + delete _zoomPicView; + _zoomPicView = 0; + delete[] _cursorSurface; + _cursorSurface = 0; +} + +void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor) { + kernelClearZoomZone(); + + _zoomMultiplier = multiplier; + + if (_zoomMultiplier != 1 && _zoomMultiplier != 2 && _zoomMultiplier != 4) + error("Unexpected zoom multiplier (expected 1, 2 or 4)"); + + _zoomCursorView = new GfxView(_resMan, _screen, _palette, viewNum); + _zoomCursorLoop = (byte)loopNum; + _zoomCursorCel = (byte)celNum; + _zoomPicView = new GfxView(_resMan, _screen, _palette, picNum); + const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel); + const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel); + _cursorSurface = new byte[cursorCelInfo->width * cursorCelInfo->height]; + memcpy(_cursorSurface, cursorBitmap, cursorCelInfo->width * cursorCelInfo->height); + + _zoomZone = zone; + kernelSetMoveZone(_zoomZone); + + _zoomColor = zoomColor; + _zoomZoneActive = true; +} + void GfxCursor::kernelSetPos(Common::Point pos) { _coordAdjuster->setCursorPos(pos); kernelMoveCursor(pos); diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h index 10cd5d8a85..ae3b51e26a 100644 --- a/engines/sci/graphics/cursor.h +++ b/engines/sci/graphics/cursor.h @@ -79,6 +79,9 @@ public: */ void kernelSetMoveZone(Common::Rect zone); + void kernelClearZoomZone(); + void kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor); + void kernelSetPos(Common::Point pos); void kernelMoveCursor(Common::Point pos); @@ -96,6 +99,16 @@ private: bool _moveZoneActive; Common::Rect _moveZone; // Rectangle in which the pointer can move + bool _zoomZoneActive; + Common::Rect _zoomZone; + GfxView *_zoomCursorView; + byte _zoomCursorLoop; + byte _zoomCursorCel; + GfxView *_zoomPicView; + byte _zoomColor; + byte _zoomMultiplier; + byte *_cursorSurface; + CursorCache _cachedCursors; bool _isVisible; diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp index 852771d081..f06dbea05e 100644 --- a/engines/sci/graphics/font.cpp +++ b/engines/sci/graphics/font.cpp @@ -88,7 +88,7 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo byte *pIn = getCharData(chr); for (int i = 0; i < charHeight; i++, y++) { if (greyedOutput) - mask = greyedTop++ % 2 ? 0xAA : 0x55; + mask = ((greyedTop++) % 2) ? 0xAA : 0x55; for (int done = 0; done < charWidth; done++) { if ((done & 7) == 0) // fetching next data byte b = *(pIn++) & mask; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index a433b26ef2..b0d1315d2e 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -44,6 +44,8 @@ namespace Sci { +// TODO/FIXME: This is all guesswork + GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette *palette, GfxPaint32 *paint32) : _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) { @@ -70,6 +72,7 @@ void GfxFrameout::kernelAddPlane(reg_t object) { newPlane.pictureId = 0xFFFF; newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority)); newPlane.lastPriority = 0xFFFF; // hidden + newPlane.planeOffsetX = 0; _planes.push_back(newPlane); kernelUpdatePlane(object); @@ -91,13 +94,63 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { addPlanePicture(object, it->pictureId, 0); } } + 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; + + 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; + + // We get negative left in kq7 in scrolling rooms + if (it->planeRect.left < 0) { + it->planeOffsetX = -it->planeRect.left; + it->planeRect.left = 0; + } + if (it->planeRect.top < 0) + it->planeRect.top = 0; + // We get bad plane-bottom in sq6 + if (it->planeRect.right > _screen->getWidth()) + it->planeRect.right = _screen->getWidth(); + if (it->planeRect.bottom > _screen->getHeight()) + it->planeRect.bottom = _screen->getHeight(); + + it->planeClipRect = Common::Rect(it->planeRect.width(), it->planeRect.height()); + it->upscaledPlaneRect = it->planeRect; + it->upscaledPlaneClipRect = it->planeClipRect; + if (_screen->getUpscaledHires()) { + _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.top, it->upscaledPlaneRect.left); + _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.bottom, it->upscaledPlaneRect.right); + _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.top, it->upscaledPlaneClipRect.left); + _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.bottom, it->upscaledPlaneClipRect.right); + } + + it->planePictureMirrored = readSelectorValue(_segMan, object, SELECTOR(mirrored)); + it->planeBack = readSelectorValue(_segMan, object, SELECTOR(back)); + sortPlanes(); + + // Update the items in the plane + for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { + reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); + if (object == itemPlane) { + kernelUpdateScreenItem((*listIterator)->object); + } + } + return; } } 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++) { @@ -144,13 +197,50 @@ void GfxFrameout::deletePlanePictures(reg_t object) { } void GfxFrameout::kernelAddScreenItem(reg_t object) { - _screenItems.push_back(object); + // Ignore invalid items + if (!_segMan->isObject(object)) + return; + + FrameoutEntry *itemEntry = new FrameoutEntry(); + itemEntry->object = object; + itemEntry->givenOrderNr = _screenItems.size(); + _screenItems.push_back(itemEntry); + + kernelUpdateScreenItem(object); +} + +void GfxFrameout::kernelUpdateScreenItem(reg_t object) { + // Ignore invalid items + 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; + } + } } void GfxFrameout::kernelDeleteScreenItem(reg_t object) { - for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) { - if (_screenItems[itemNr] == object) { - _screenItems.remove_at(itemNr); + for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { + FrameoutEntry *itemEntry = *listIterator; + if (itemEntry->object == object) { + _screenItems.remove(itemEntry); return; } } @@ -161,7 +251,7 @@ int16 GfxFrameout::kernelGetHighPlanePri() { return readSelectorValue(g_sci->getEngineState()->_segMan, _planes.back().object, SELECTOR(priority)); } -// No idea yet how to implement this +// TODO: No idea yet how to implement this void GfxFrameout::kernelAddPicAt(reg_t planeObj, int16 forWidth, GuiResourceId pictureId) { addPlanePicture(planeObj, pictureId, forWidth); } @@ -206,112 +296,37 @@ void GfxFrameout::sortPlanes() { void GfxFrameout::kernelFrameout() { _palette->palVaryUpdate(); - // Allocate enough space for all screen items - FrameoutEntry *itemData = new FrameoutEntry[_screenItems.size()]; - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { reg_t planeObject = it->object; uint16 planeLastPriority = it->lastPriority; - Common::Rect planeRect; - planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top)); - planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left)); - planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom)) + 1; - planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right)) + 1; - // Update priority here, sq6 sets it w/o UpdatePlane uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority)); - 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; - - int16 planeOffsetX = 0; - - // We get negative left in kq7 in scrolling rooms - if (planeRect.left < 0) { - planeOffsetX = -planeRect.left; - planeRect.left = 0; - } - if (planeRect.top < 0) - planeRect.top = 0; - // We get bad plane-bottom in sq6 - if (planeRect.right > _screen->getWidth()) - planeRect.right = _screen->getWidth(); - if (planeRect.bottom > _screen->getHeight()) - planeRect.bottom = _screen->getHeight(); - it->lastPriority = planePriority; if (planePriority == 0xffff) { // Plane currently not meant to be shown // If plane was shown before, delete plane rect if (planePriority != planeLastPriority) - _paint32->fillRect(planeRect, 0); + _paint32->fillRect(it->planeRect, 0); continue; } - Common::Rect planeClipRect(planeRect.width(), planeRect.height()); - - Common::Rect upscaledPlaneRect = planeRect; - Common::Rect upscaledPlaneClipRect = planeClipRect; - if (_screen->getUpscaledHires()) { - _screen->adjustToUpscaledCoordinates(upscaledPlaneRect.top, upscaledPlaneRect.left); - _screen->adjustToUpscaledCoordinates(upscaledPlaneRect.bottom, upscaledPlaneRect.right); - _screen->adjustToUpscaledCoordinates(upscaledPlaneClipRect.top, upscaledPlaneClipRect.left); - _screen->adjustToUpscaledCoordinates(upscaledPlaneClipRect.bottom, upscaledPlaneClipRect.right); - } - - byte planeBack = readSelectorValue(_segMan, planeObject, SELECTOR(back)); - if (planeBack) - _paint32->fillRect(planeRect, planeBack); + if (it->planeBack) + _paint32->fillRect(it->planeRect, it->planeBack); GuiResourceId planeMainPictureId = it->pictureId; - bool planePictureMirrored = false; - if (readSelectorValue(_segMan, planeObject, SELECTOR(mirrored))) - planePictureMirrored = true; - - _coordAdjuster->pictureSetDisplayArea(planeRect); + _coordAdjuster->pictureSetDisplayArea(it->planeRect); _palette->drewPicture(planeMainPictureId); - // Fill our itemlist for this plane - int16 itemCount = 0; - FrameoutEntry *itemEntry = itemData; FrameoutList itemList; - for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) { - reg_t itemObject = _screenItems[itemNr]; - - // Remove any invalid items - if (!_segMan->isObject(itemObject)) { - _screenItems.remove_at(itemNr); - itemNr--; - continue; - } - - reg_t itemPlane = readSelector(_segMan, itemObject, SELECTOR(plane)); + // 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) { - // Found an item on current plane - itemEntry->viewId = readSelectorValue(_segMan, itemObject, SELECTOR(view)); - itemEntry->loopNo = readSelectorValue(_segMan, itemObject, SELECTOR(loop)); - itemEntry->celNo = readSelectorValue(_segMan, itemObject, SELECTOR(cel)); - itemEntry->x = readSelectorValue(_segMan, itemObject, SELECTOR(x)); - itemEntry->y = readSelectorValue(_segMan, itemObject, SELECTOR(y)); - itemEntry->z = readSelectorValue(_segMan, itemObject, SELECTOR(z)); - itemEntry->priority = readSelectorValue(_segMan, itemObject, SELECTOR(priority)); - if (readSelectorValue(_segMan, itemObject, SELECTOR(fixPriority)) == 0) - itemEntry->priority = itemEntry->y; - - itemEntry->signal = readSelectorValue(_segMan, itemObject, SELECTOR(signal)); - itemEntry->scaleX = readSelectorValue(_segMan, itemObject, SELECTOR(scaleX)); - itemEntry->scaleY = readSelectorValue(_segMan, itemObject, SELECTOR(scaleY)); - itemEntry->object = itemObject; - itemEntry->givenOrderNr = itemNr; - - itemList.push_back(itemEntry); - itemEntry++; - itemCount++; + kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? + itemList.push_back(*listIterator); } } @@ -343,13 +358,10 @@ void GfxFrameout::kernelFrameout() { // Now sort our itemlist Common::sort(itemList.begin(), itemList.end(), sortHelper); - // Now display itemlist - itemEntry = itemData; - // warning("Plane %s", _segMan->getObjectName(planeObject)); for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) { - itemEntry = *listIterator; + FrameoutEntry *itemEntry = *listIterator; if (itemEntry->object.isNull()) { // Picture cel data @@ -360,25 +372,25 @@ void GfxFrameout::kernelFrameout() { // Out of view int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); - int16 planeStartX = planeOffsetX; - int16 planeEndX = planeStartX + planeRect.width(); + int16 planeStartX = it->planeOffsetX; + int16 planeEndX = planeStartX + it->planeRect.width(); if (pictureCelEndX < planeStartX) continue; if (pictureCelStartX > planeEndX) continue; - int16 pictureOffsetX = planeOffsetX; + int16 pictureOffsetX = it->planeOffsetX; int16 pictureX = itemEntry->x; - if ((planeOffsetX) || (itemEntry->picStartX)) { - if (planeOffsetX <= itemEntry->picStartX) { - pictureX += itemEntry->picStartX - planeOffsetX; + if ((it->planeOffsetX) || (itemEntry->picStartX)) { + if (it->planeOffsetX <= itemEntry->picStartX) { + pictureX += itemEntry->picStartX - it->planeOffsetX; pictureOffsetX = 0; } else { - pictureOffsetX = planeOffsetX - itemEntry->picStartX; + pictureOffsetX = it->planeOffsetX - itemEntry->picStartX; } } - itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, planePictureMirrored); + 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) { @@ -403,7 +415,7 @@ void GfxFrameout::kernelFrameout() { break; } // Adjust according to current scroll position - itemEntry->x -= planeOffsetX; + itemEntry->x -= it->planeOffsetX; uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect)); if (useInsetRect) { @@ -426,7 +438,7 @@ void GfxFrameout::kernelFrameout() { Common::Rect nsRect = itemEntry->celRect; // Translate back to actual coordinate within scrollable plane - nsRect.translate(planeOffsetX, 0); + nsRect.translate(it->planeOffsetX, 0); switch (getSciVersion()) { case SCI_VERSION_2: if (view->isSci2Hires()) { @@ -465,13 +477,13 @@ void GfxFrameout::kernelFrameout() { Common::Rect clipRect, translatedClipRect; clipRect = itemEntry->celRect; if (view->isSci2Hires()) { - clipRect.clip(upscaledPlaneClipRect); + clipRect.clip(it->upscaledPlaneClipRect); translatedClipRect = clipRect; - translatedClipRect.translate(upscaledPlaneRect.left, upscaledPlaneRect.top); + translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top); } else { - clipRect.clip(planeClipRect); + clipRect.clip(it->planeClipRect); translatedClipRect = clipRect; - translatedClipRect.translate(planeRect.left, planeRect.top); + translatedClipRect.translate(it->planeRect.left, it->planeRect.top); } if (!clipRect.isEmpty()) { @@ -501,8 +513,8 @@ void GfxFrameout::kernelFrameout() { itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight); itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth); - uint16 curX = itemEntry->x + planeRect.left; - uint16 curY = itemEntry->y + planeRect.top; + uint16 curX = itemEntry->x + it->planeRect.left; + uint16 curY = itemEntry->y + it->planeRect.top; for (uint32 i = 0; i < text.size(); i++) { unsigned char curChar = text[i]; // TODO: proper text splitting... this is a hack @@ -525,7 +537,6 @@ void GfxFrameout::kernelFrameout() { } } - delete[] itemData; _screen->copyToScreen(); g_sci->getEngineState()->_throttleTrigger = true; diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index f8f7e54a27..bd708dbc79 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -32,7 +32,14 @@ struct PlaneEntry { reg_t object; uint16 priority; uint16 lastPriority; + int16 planeOffsetX; GuiResourceId pictureId; + Common::Rect planeRect; + Common::Rect planeClipRect; + Common::Rect upscaledPlaneRect; + Common::Rect upscaledPlaneClipRect; + bool planePictureMirrored; + byte planeBack; }; typedef Common::List<PlaneEntry> PlaneList; @@ -81,8 +88,10 @@ public: void kernelAddPlane(reg_t object); void kernelUpdatePlane(reg_t object); + void kernelRepaintPlane(reg_t object); void kernelDeletePlane(reg_t object); void kernelAddScreenItem(reg_t object); + void kernelUpdateScreenItem(reg_t object); void kernelDeleteScreenItem(reg_t object); int16 kernelGetHighPlanePri(); void kernelAddPicAt(reg_t planeObj, int16 forWidth, GuiResourceId pictureId); @@ -100,7 +109,7 @@ private: GfxScreen *_screen; GfxPaint32 *_paint32; - Common::Array<reg_t> _screenItems; + Common::List<FrameoutEntry *> _screenItems; PlaneList _planes; PlanePictureList _planePictures; diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp index 630626c128..06470bc560 100644 --- a/engines/sci/graphics/menu.cpp +++ b/engines/sci/graphics/menu.cpp @@ -905,7 +905,7 @@ void GfxMenu::kernelDrawStatus(const char *text, int16 colorPen, int16 colorBack _paint16->fillRect(_ports->_menuBarRect, 1, colorBack); _ports->penColor(colorPen); _ports->moveTo(0, 1); - _text16->Draw_String(text); + _text16->Draw_Status(text); _paint16->bitsShow(_ports->_menuBarRect); _ports->setPort(oldPort); } diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp index dbc738e2f7..3c115f0c8e 100644 --- a/engines/sci/graphics/paint16.cpp +++ b/engines/sci/graphics/paint16.cpp @@ -380,6 +380,14 @@ void GfxPaint16::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, b drawPicture(pictureId, animationNr, mirroredFlag, addToFlag, EGApaletteNo); _transitions->setup(animationNr, animationBlackoutFlag); } else { + // We need to set it for SCI1EARLY+ (sierra sci also did so), otherwise we get at least the following issues: + // LSL5 (english) - last wakeup (taj mahal flute dream) + // SQ5 (english v1.03) - during the scene following the scrubbing + // in both situations a window is shown when kDrawPic is called, which would result otherwise in + // no showpic getting called from kAnimate and we would get graphic corruption + // XMAS1990 EGA did not set it in this case, VGA did + if (getSciVersion() >= SCI_VERSION_1_EARLY) + _screen->_picNotValid = 1; _ports->beginUpdate(_ports->_picWind); drawPicture(pictureId, animationNr, mirroredFlag, addToFlag, EGApaletteNo); _ports->endUpdate(_ports->_picWind); diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 2765663381..39666b82cb 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -853,11 +853,11 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by // Now remove screens, that already got the right color/priority/control if ((screenMask & GFX_SCREEN_MASK_VISUAL) && (searchColor == color)) - screenMask ^= GFX_SCREEN_MASK_VISUAL; + screenMask &= ~GFX_SCREEN_MASK_VISUAL; if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && (searchPriority == priority)) - screenMask ^= GFX_SCREEN_MASK_PRIORITY; + screenMask &= ~GFX_SCREEN_MASK_PRIORITY; if ((screenMask & GFX_SCREEN_MASK_CONTROL) && (searchControl == control)) - screenMask ^= GFX_SCREEN_MASK_CONTROL; + screenMask &= ~GFX_SCREEN_MASK_CONTROL; // Exit, if no screens left if (!screenMask) diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 12ac1d2025..e7f319a25c 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -301,7 +301,7 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor Common::Rect r; if (!pwnd) { - error("Can't open window!"); + error("Can't open window"); return 0; } diff --git a/engines/sci/graphics/robot.cpp b/engines/sci/graphics/robot.cpp index 1572a0a9ec..0792c6596e 100644 --- a/engines/sci/graphics/robot.cpp +++ b/engines/sci/graphics/robot.cpp @@ -37,7 +37,6 @@ GfxRobot::GfxRobot(ResourceManager *resMan, GfxScreen *screen, GuiResourceId res : _resMan(resMan), _screen(screen), _resourceId(resourceId) { assert(resourceId != -1); initData(resourceId); - _resourceData = 0; } GfxRobot::~GfxRobot() { @@ -57,119 +56,13 @@ void GfxRobot::initData(GuiResourceId resourceId) { warning("Unable to open robot file %s", fileName); return; } - - byte version = _resourceData[6]; - if (version != 4 && version != 5) { - warning("Robot version %d isn't supported yet", version); - return; - } - -// sample data: -// Header - 14 bytes -// DWORD:Sample Size - 2 needs to be subtracted (??!!) -// ??? -// Actual samples following - -// version may be 3, 4 and 5 -// version 3 has a different header (unknown to this point) -// -// main header (56 bytes + 2 bytes resource id) -// followed by sample data if hasSound == 1 -// - -// 90.rbt (640x390, 22050, 1 16, ADPCM) 67 frames -// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 f0 00 43 00 ..SOL.........C. -// ^ signature ^ version ^ ^ ^ frames -// ^ 2221 -// 00000010: b0 04 00 a0 00 00 00 00-01 01 00 00 0a 00 01 00 -// ^ ^ ^ ^ ^ ^ ^ ^ ^ -// hasSound -// 00000020: 03 00 01 00 00 cf 03 00-00 00 00 00 00 00 00 00 -// ^ ^ ^ pixel count ^ -// ^ -// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 -// ^ ^ -// Sample-Data (Header): -// compression must be 0 for now -// 0000003c: f2 9f 00 00 00 00 d2 4d 00 00 20 52-00 00 -// ^ ^ ^ -// byte count compression -// 40946 -// Actual Samples following -// a5 11 04 02 85 90 ...M.. R........ -// -// Offset 41020 -// Palette - -// 91.rbt (320x240, 22050, 1 16, ADPCM) 90 frames -// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 f0 00 5a 00 ..SOL.........Z. -// ^ frames -// 00000010: b0 04 00 a0 00 00 00 00-01 01 00 00 0a 00 01 00 ................ -// 00000020: 03 00 01 00 00 2c 01 00-00 00 00 00 00 00 00 00 .....,.......... -// ^ pixel count -// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 f2 9f 00 00 ................ offset 60 -// ^ data begin (sample) -// 00000040: 00 00 d2 4d 00 00 20 52-00 00 82 01 00 01 00 01 ...M.. R........ -// ... -// 0000a030: 8d 8d 8f 8e 8f 90 90 91-92 92 92 94 0e 00 00 00 ................ offset 41004 -// ^ palette start -// 0000a040: 00 00 00 00 00 00 01 00-00 09 01 00 00 00 00 00 ................ -// 0000a050: 00 00 00 00 00 37 00 00-00 51 00 01 01 00 00 00 .....7...Q...... -// ^ color start^ color count -// 0000a060: 00 58 6b 2b 4b 69 28 50-5b 24 68 50 20 5b 53 21 .Xk+Ki(P[$hP [S! -// ^ start pal data -// [...] -// 0000a110: 24 05 41 14 04 18 25 10-64 00 00 2d 18 05 58 00 $.A...%.d..-..X. -// 0000a120: 00 16 20 07 50 00 00 20-19 01 2d 0e 00 48 00 00 .. .P.. ..-..H.. -// 0000a130: 40 00 00 10 18 05 38 00-00 30 00 00 28 00 00 0b @.....8..0..(... -// 0000a140: 0e 00 20 00 00 18 00 00-00 08 00 10 00 00 08 00 .. ............. -// 0000a150: 00 00 00 00 70 70 70 70-70 70 70 70 70 70 70 70 ....pppppppppppp -// [...] -// 0000a4e0: 70 70 70 70 70 70 70 70-70 70 70 70 34 0a 75 0a pppppppppppp4.u. -// 0000a4f0: 4a 0b c5 0b f4 0b 54 0c-bd 0c 7a 0d 91 0e 1f 10 J.....T...z..... -// 0000a500: 16 12 72 14 19 17 ef 19-9a 1c b3 1e 79 20 c1 22 ..r.........y ." -// 0000a510: 33 22 33 23 e0 25 84 26-eb 26 1a 2d 43 2d af 2d 3"3#.%.&.&.-C-.- -// [...] -// 0000aff0: 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20 -// 0000b000: 01 00 7f 64 40 01 f0 00-00 00 00 00 00 00 00 00 ...d@........... -// ^width^height -// 0000b010: 1c 0a 02 00 7f 7f 7f 7f-04 08 00 00 00 f0 00 00 ................ -// 0000b020: 00 00 43 e0 7f ff ff ff-ff ff ff ff ff ff ff ff ..C............. -// 0000b030: ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ - -// 161.rbt (112x155, 22050, 1 16, ADPCM) 29 frames -// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 96 00 1d 00 ..SOL........... -// ^ frames -// 00000010: b0 04 00 a0 00 00 00 00-01 01 00 00 0a 00 01 00 ................ -// 00000020: 03 00 01 00 47 3e 00 00-00 00 00 00 00 00 00 00 ....G>.......... -// ^ pixel count -// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 f2 9f 00 00 ................ -// ^ data begin (sample) -// 00000040: 00 00 d2 4d 00 00 20 52-00 00 00 00 00 00 00 00 ...M.. R........ -// 00000050: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ - -// 213.rbt (125x248, nosound) 30 frames -// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 96 00 1e 00 ..SOL........... -// ^ frames -// 00000010: b0 04 00 00 00 00 00 00-01 00 00 00 0a 00 01 00 ................ -// ^ ?! ^ no sound?! -// 00000020: 03 00 01 00 82 6e 00 00-00 00 00 00 00 00 00 00 .....n.......... -// ^ pixel count -// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 0e 00 00 00 ................ -// ^ data begin (palette) -// 00000040: 00 00 00 00 00 00 01 00-00 ca 00 00 00 00 00 00 ................ -// 00000050: 00 00 00 00 00 37 00 00-00 3c 00 01 01 00 00 00 .....7...<...... -// 00000060: 00 d0 d0 c0 d0 c0 a8 c8-b8 c0 d0 b0 a0 c0 a8 88 -// ^ palette data start -// 00000070: c0 a0 a0 c8 98 90 d0 88-60 b0 90 80 b8 88 80 a0 ........`....... -// 00000080: 90 98 b0 88 90 c0 78 60-a0 80 80 a0 80 70 c8 70 ......x`.....p.p -// [...] -// 00000110: 00 00 00 00 08 70 70 70-70 70 70 70 70 70 70 70 .....ppppppppppp -// ^ ?? -// 00000120: 70 70 70 70 70 70 70 70-70 70 70 70 70 70 70 70 pppppppppppppppp + // The RBT video starts with a SOL audio file, followed by + // video data which is appended after it _frameCount = READ_LE_UINT16(_resourceData + 14); + _audioSize = READ_LE_UINT16(_resourceData + 15); + //_frameSize = READ_LE_UINT32(_resourceData + 34); byte hasSound = _resourceData[25]; @@ -179,21 +72,57 @@ void GfxRobot::initData(GuiResourceId resourceId) { // TODO: just trying around in here... void GfxRobot::draw() { - byte *bitmapData = _resourceData + ROBOT_FILE_STARTOFDATA; + byte *bitmapData = _resourceData + _audioSize; int x, y; - //int frame; + int frame; return; - //for (frame = 0; frame < 30; frame++) { - for (y = 0; y < _height; y++) { - for (x = 0; x < _width; x++) { - _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, *bitmapData, 0, 0); - bitmapData++; + // Each frame contains these bytes: + // 01 00 7f 64 - always the same, perhaps resource type + extra + // 40 01 - total frame width (320 in this case) + // f0 00 - total frame height (240 in this case) + // The total video size is calculated from the maximum width, height + // of all the frames in the robot file + // 4 zeroes + // 4 bytes, perhaps frame x, y on screen? + // 2 bytes, unknown + // 2 bytes, a small number (e.g. 01 00 or 02 00) + // 7f 7f - 127x127 + // 7f 7f - 127x127 + // 2 bytes, related to frame size? + // 00 00 + // 00 f0 + // 4 zeroes + // 43 e0 + // 7f ff + + // The frames themselves seem to contain a size of the actual drawn data + // on screen. The frame data seems to be uncompressed, placed on screen + // at appropriate x,y coordinates, and each frame can have a different size. + // This is apparent from the fact that a 320x240 frame (e.g. in Phantasmagoria + // demo, 91.rbt) has 4833, 4898, 5111, etc bytes, whereas a full frame would + // be 320x240 = 76800 bytes. Thus, each frame is either somehow compressed + // (but the data seems uncompressed?), or only the part that changes is drawn + // on screen, something like the MPEG I-frames + + for (frame = 0; frame < _frameCount; frame++) { + bitmapData += 4; // skip header bytes + _width = READ_LE_UINT16(bitmapData + 4); bitmapData += 2; + _height = READ_LE_UINT16(bitmapData + 6); bitmapData += 2; + + for (y = 0; y < _width; y++) { + for (x = 0; x < _height; x++) { + _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, *bitmapData, 0, 0); + bitmapData++; + } } + + _screen->copyToScreen(); + // Sleep for a second + g_sci->sleep(1000); } - //} - _screen->copyToScreen(); + } #endif diff --git a/engines/sci/graphics/robot.h b/engines/sci/graphics/robot.h index 3ea9a7f735..76dca35a82 100644 --- a/engines/sci/graphics/robot.h +++ b/engines/sci/graphics/robot.h @@ -51,6 +51,7 @@ private: uint16 _height; uint16 _frameCount; uint32 _frameSize; // is width * height (pixelCount) + uint16 _audioSize; }; #endif diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 839b9975c5..7a10a6b749 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -122,9 +122,9 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { // Initialize the actual screen - if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) { - // For SCI1.1 Mac, we need to expand the screen to accommodate for - // the icon bar. Of course, both KQ6 and QFG1 VGA differ in size. + if (g_sci->hasMacIconBar()) { + // For SCI1.1 Mac games with the custom icon bar, we need to expand the screen + // to accommodate for the icon bar. Of course, both KQ6 and QFG1 VGA differ in size. if (g_sci->getGameId() == GID_KQ6) initGraphics(_displayWidth, _displayHeight + 26, _displayWidth > 320); else if (g_sci->getGameId() == GID_QFG1VGA) @@ -345,11 +345,11 @@ byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byt int offset = y * _width + x; byte match = 0; - if (screenMask & GFX_SCREEN_MASK_VISUAL && *(_visualScreen + offset) == t_color) + if ((screenMask & GFX_SCREEN_MASK_VISUAL) && *(_visualScreen + offset) == t_color) match |= GFX_SCREEN_MASK_VISUAL; - if (screenMask & GFX_SCREEN_MASK_PRIORITY && *(_priorityScreen + offset) == t_pri) + if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == t_pri) match |= GFX_SCREEN_MASK_PRIORITY; - if (screenMask & GFX_SCREEN_MASK_CONTROL && *(_controlScreen + offset) == t_con) + if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == t_con) match |= GFX_SCREEN_MASK_CONTROL; return match; } diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp index f5eb268863..3fba3006c7 100644 --- a/engines/sci/graphics/text16.cpp +++ b/engines/sci/graphics/text16.cpp @@ -30,6 +30,7 @@ #include "sci/sci.h" #include "sci/engine/state.h" #include "sci/graphics/cache.h" +#include "sci/graphics/coordadjuster.h" #include "sci/graphics/ports.h" #include "sci/graphics/paint16.h" #include "sci/graphics/font.h" @@ -88,7 +89,7 @@ void GfxText16::ClearChar(int16 chr) { // will process the encountered code and set new font/set color. We only support // one-digit codes currently, don't know if multi-digit codes are possible. // Returns textcode character count. -int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor) { +int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor, bool doingDrawing) { const char *textCode = text; int16 textCodeSize = 0; char curCode; @@ -126,8 +127,20 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 } } break; - case 'r': // reference?! - // Used in Pepper, no idea how this works out + case 'r': // reference (used in pepper) + if (doingDrawing) { + if (_codeRefTempRect.top == -1) { + // Starting point + _codeRefTempRect.top = _ports->_curPort->curTop; + _codeRefTempRect.left = _ports->_curPort->curLeft; + } else { + // End point reached + _codeRefTempRect.bottom = _ports->_curPort->curTop + _ports->_curPort->fontHeight; + _codeRefTempRect.right = _ports->_curPort->curLeft; + _codeRefRects.push_back(_codeRefTempRect); + _codeRefTempRect.left = _codeRefTempRect.top = -1; + } + } break; } return textCodeSize; @@ -162,7 +175,7 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF case 0x7C: if (getSciVersion() >= SCI_VERSION_1_1) { curCharCount++; - curCharCount += CodeProcessing(text, orgFontId, previousPenColor); + curCharCount += CodeProcessing(text, orgFontId, previousPenColor, false); continue; } break; @@ -258,7 +271,7 @@ void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId org break; case 0x7C: if (getSciVersion() >= SCI_VERSION_1_1) { - len -= CodeProcessing(text, orgFontId, 0); + len -= CodeProcessing(text, orgFontId, 0, false); break; } default: @@ -359,7 +372,7 @@ void GfxText16::Draw(const char *text, int16 from, int16 len, GuiResourceId orgF break; case 0x7C: if (getSciVersion() >= SCI_VERSION_1_1) { - len -= CodeProcessing(text, orgFontId, orgPenColor); + len -= CodeProcessing(text, orgFontId, orgPenColor, true); break; } default: @@ -408,6 +421,10 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex doubleByteMode = true; } + // Reset reference code rects + _codeRefRects.clear(); + _codeRefTempRect.left = _codeRefTempRect.top = -1; + maxTextWidth = 0; while (*text) { charCount = GetLongest(text, rect.width(), fontId); @@ -474,6 +491,32 @@ void GfxText16::Draw_String(const char *text) { _ports->penColor(previousPenColor); } +// we need to have a separate status drawing code +// In KQ4 the IV char is actually 0xA, which would otherwise get considered as linebreak and not printed +void GfxText16::Draw_Status(const char *text) { + uint16 curChar, charWidth; + uint16 textLen = strlen(text); + Common::Rect rect; + + GetFont(); + if (!_font) + return; + + rect.top = _ports->_curPort->curTop; + rect.bottom = rect.top + _ports->_curPort->fontHeight; + while (textLen--) { + curChar = (*(const byte *)text++); + switch (curChar) { + case 0: + break; + default: + charWidth = _font->getCharWidth(curChar); + _font->draw(curChar, _ports->_curPort->top + _ports->_curPort->curTop, _ports->_curPort->left + _ports->_curPort->curLeft, _ports->_curPort->penClr, _ports->_curPort->greyedOutput); + _ports->_curPort->curLeft += charWidth; + } + } +} + // Sierra did this in their PC98 interpreter only, they identify a text as being // sjis and then switch to font 900 bool GfxText16::SwitchToFont900OnSjis(const char *text) { @@ -485,6 +528,30 @@ bool GfxText16::SwitchToFont900OnSjis(const char *text) { return false; } +reg_t GfxText16::allocAndFillReferenceRectArray() { + uint rectCount = _codeRefRects.size(); + if (rectCount) { + reg_t rectArray; + byte *rectArrayPtr = g_sci->getEngineState()->_segMan->allocDynmem(4 * 2 * (rectCount + 1), "text code reference rects", &rectArray); + GfxCoordAdjuster *coordAdjuster = g_sci->_gfxCoordAdjuster; + for (uint curRect = 0; curRect < rectCount; curRect++) { + coordAdjuster->kernelLocalToGlobal(_codeRefRects[curRect].left, _codeRefRects[curRect].top); + coordAdjuster->kernelLocalToGlobal(_codeRefRects[curRect].right, _codeRefRects[curRect].bottom); + WRITE_LE_UINT16(rectArrayPtr + 0, _codeRefRects[curRect].left); + WRITE_LE_UINT16(rectArrayPtr + 2, _codeRefRects[curRect].top); + WRITE_LE_UINT16(rectArrayPtr + 4, _codeRefRects[curRect].right); + WRITE_LE_UINT16(rectArrayPtr + 6, _codeRefRects[curRect].bottom); + rectArrayPtr += 8; + } + WRITE_LE_UINT16(rectArrayPtr + 0, 0x7777); + WRITE_LE_UINT16(rectArrayPtr + 2, 0x7777); + WRITE_LE_UINT16(rectArrayPtr + 4, 0x7777); + WRITE_LE_UINT16(rectArrayPtr + 6, 0x7777); + return rectArray; + } + return NULL_REG; +} + void GfxText16::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) { Common::Rect rect(0, 0, 0, 0); Size(rect, text, font, maxWidth); diff --git a/engines/sci/graphics/text16.h b/engines/sci/graphics/text16.h index 9b8b6d9f19..dc3ed2f62b 100644 --- a/engines/sci/graphics/text16.h +++ b/engines/sci/graphics/text16.h @@ -32,6 +32,8 @@ namespace Sci { #define SCI_TEXT16_ALIGNMENT_CENTER 1 #define SCI_TEXT16_ALIGNMENT_LEFT 0 +typedef Common::Array<Common::Rect> CodeRefRectArray; + class GfxPorts; class GfxPaint16; class GfxScreen; @@ -48,7 +50,7 @@ public: GfxFont *GetFont(); void SetFont(GuiResourceId fontId); - int16 CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor); + int16 CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor, bool doingDrawing); void ClearChar(int16 chr); @@ -62,9 +64,12 @@ public: void Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); void Box(const char *text, int16 bshow, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId); void Draw_String(const char *text); + void Draw_Status(const char *text); GfxFont *_font; + reg_t allocAndFillReferenceRectArray(); + void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); void kernelTextFonts(int argc, reg_t *argv); void kernelTextColors(int argc, reg_t *argv); @@ -83,6 +88,9 @@ private: GuiResourceId *_codeFonts; int _codeColorsCount; uint16 *_codeColors; + + Common::Rect _codeRefTempRect; + CodeRefRectArray _codeRefRects; }; } // End of namespace Sci diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp index bd5e061094..3f4ce7bbc8 100644 --- a/engines/sci/graphics/transitions.cpp +++ b/engines/sci/graphics/transitions.cpp @@ -37,6 +37,8 @@ namespace Sci { +//#define DISABLE_TRANSITIONS // uncomment to disable room transitions (for development only! helps in testing games quickly) + GfxTransitions::GfxTransitions(GfxScreen *screen, GfxPalette *palette, bool isVGA) : _screen(screen), _palette(palette), _isVGA(isVGA) { init(); @@ -116,7 +118,11 @@ void GfxTransitions::init() { void GfxTransitions::setup(int16 number, bool blackoutFlag) { if (number != -1) { +#ifndef DISABLE_TRANSITIONS _number = number; +#else + _number = SCI_TRANSITIONS_NONE; +#endif _blackoutFlag = blackoutFlag; } } diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index 6b22ed397e..36d48fe3c9 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -354,6 +354,16 @@ void GfxView::getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, C outRect.top = outRect.bottom - celInfo->height; } +void GfxView::getCelSpecialHoyle4Rect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const { + const CelInfo *celInfo = getCelInfo(loopNo, celNo); + int16 adjustY = y - celInfo->height + celInfo->displaceY + 1; + int16 adjustX = x - ((celInfo->width - 1) >> 1) + celInfo->displaceX; + outRect.top += adjustY; + outRect.bottom += adjustY; + outRect.left += adjustX; + outRect.right += adjustX; +} + void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const { int16 scaledDisplaceX, scaledDisplaceY; int16 scaledWidth, scaledHeight; @@ -525,6 +535,10 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl if (width <= 3) return; + // We need at least 2 pixel lines + if (height < 2) + return; + // If EGA mapping is used for this view, dont do undithering as well if (_EGAmapping) return; @@ -533,20 +547,28 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl int16 bitmapMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; byte *curPtr; byte color1, color2; + byte nextColor1, nextColor2; int16 y, x; memset(&bitmapMemorial, 0, sizeof(bitmapMemorial)); // Count all seemingly dithered pixel-combinations as soon as at least 4 - // pixels are adjacent + // pixels are adjacent and check pixels in the following line as well to + // be the reverse pixel combination + int16 checkHeight = height - 1; curPtr = bitmapPtr; - for (y = 0; y < height; y++) { + byte *nextPtr = curPtr + width; + for (y = 0; y < checkHeight; y++) { color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2]; + nextColor1 = nextPtr[0] << 4; nextColor2 = (nextPtr[2] << 4) | nextPtr[1]; curPtr += 3; + nextPtr += 3; for (x = 3; x < width; x++) { color1 = (color1 << 4) | (color2 >> 4); color2 = (color2 << 4) | *curPtr++; - if (color1 == color2) + nextColor1 = (nextColor1 >> 4) | (nextColor2 << 4); + nextColor2 = (nextColor2 >> 4) | *nextPtr++ << 4; + if ((color1 == color2) && (color1 == nextColor1) && (color1 == nextColor2)) bitmapMemorial[color1]++; } } @@ -583,9 +605,10 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl if (unditherTable[color]) { // Some color with black? Turn colors around, otherwise it won't // be the right color at all. + byte unditheredColor = color; if ((color & 0xF0) == 0) - color = (color << 4) | (color >> 4); - curPtr[0] = color; curPtr[1] = color; + unditheredColor = (color << 4) | (color >> 4); + curPtr[0] = unditheredColor; curPtr[1] = unditheredColor; } curPtr++; } diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h index 990a7e2f71..f785e3c475 100644 --- a/engines/sci/graphics/view.h +++ b/engines/sci/graphics/view.h @@ -66,6 +66,7 @@ public: int16 getHeight(int16 loopNo, int16 celNo) const; const CelInfo *getCelInfo(int16 loopNo, int16 celNo) const; void getCelRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const; + void getCelSpecialHoyle4Rect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, Common::Rect &outRect) const; void getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int16 z, int16 scaleX, int16 scaleY, Common::Rect &outRect) const; const byte *getBitmap(int16 loopNo, int16 celNo); void draw(const Common::Rect &rect, const Common::Rect &clipRect, const Common::Rect &clipRectTranslated, int16 loopNo, int16 celNo, byte priority, uint16 EGAmappingNr, bool upscaledHires); |