From 869d342e9f110374683002d405803d01d365119b Mon Sep 17 00:00:00 2001 From: johndoe123 Date: Thu, 10 Dec 2015 22:16:25 +0100 Subject: [PATCH] ILLUSIONS: BBDOU: Implement getOverlappedObjectAccurate and related functions --- engines/illusions/actor.cpp | 41 ++++++++++++++ engines/illusions/actor.h | 2 + engines/illusions/bbdou/bbdou_specialcode.cpp | 10 ++-- engines/illusions/screen.cpp | 56 +++++++++++++++++++ engines/illusions/screen.h | 3 + 5 files changed, 106 insertions(+), 6 deletions(-) diff --git a/engines/illusions/actor.cpp b/engines/illusions/actor.cpp index 33610ca6af1..a273b523736 100644 --- a/engines/illusions/actor.cpp +++ b/engines/illusions/actor.cpp @@ -945,6 +945,12 @@ void Control::fillActor(byte color) { _actor->_flags |= 0x4000; } +bool Control::isPixelCollision(Common::Point &pt) { + Frame *frame = &(*_actor->_frames)[_actor->_frameIndex - 1]; + return _vm->_screen->isSpritePixelSolid16(pt, _position, _actor->_position, + _actor->_surfInfo, _actor->_scale, frame->_flags, frame->_compressedPixels); +} + void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) { stopActor(); @@ -1311,6 +1317,41 @@ bool Controls::getOverlappedObject(Control *control, Common::Point pt, Control * return foundControl != 0; } +bool Controls::getOverlappedObjectAccurate(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority) { + Control *foundControl = 0; + uint32 foundPriority = 0; + uint32 minPriorityExt = _vm->getPriorityFromBase(minPriority); + + for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) { + Control *testControl = *it; + if (testControl != control && testControl->_pauseCtr == 0 && + (testControl->_flags & 1) && !(testControl->_flags & 0x10) && + (!testControl->_actor || (testControl->_actor->_flags & 1))) { + Common::Rect collisionRect; + testControl->getCollisionRectAccurate(collisionRect); + if (!collisionRect.isEmpty() && collisionRect.contains(pt) && + (!testControl->_actor || testControl->isPixelCollision(pt))) { + uint32 testPriority = testControl->getOverlapPriority(); + if ((!foundControl || foundPriority < testPriority) && + testPriority >= minPriorityExt) { + foundControl = testControl; + foundPriority = testPriority; + } + } + } + } + + if (foundControl) { + if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & 0x40)) { + uint32 parentObjectId = foundControl->getSubActorParent(); + foundControl = _vm->_dict->getObjectControl(parentObjectId); + } + *outOverlappedControl = foundControl; + } + + return foundControl != 0; +} + bool Controls::getDialogItemAtPos(Control *control, Common::Point pt, Control **outOverlappedControl) { Control *foundControl = 0; for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) { diff --git a/engines/illusions/actor.h b/engines/illusions/actor.h index add7519156e..d82ca02228e 100644 --- a/engines/illusions/actor.h +++ b/engines/illusions/actor.h @@ -204,6 +204,7 @@ public: void getActorFrameDimensions(WidthHeight &dimensions); void drawActorRect(const Common::Rect r, byte color); void fillActor(byte color); + bool isPixelCollision(Common::Point &pt); public: IllusionsEngine *_vm; uint _flags; @@ -245,6 +246,7 @@ public: void pauseControlsBySceneId(uint32 sceneId); void unpauseControlsBySceneId(uint32 sceneId); bool getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority); + bool getOverlappedObjectAccurate(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority); bool getDialogItemAtPos(Control *control, Common::Point pt, Control **outOverlappedControl); bool getOverlappedWalkObject(Control *control, Common::Point pt, Control **outOverlappedControl); void destroyControl(Control *control); diff --git a/engines/illusions/bbdou/bbdou_specialcode.cpp b/engines/illusions/bbdou/bbdou_specialcode.cpp index 9278a41813c..497bc561b0f 100644 --- a/engines/illusions/bbdou/bbdou_specialcode.cpp +++ b/engines/illusions/bbdou/bbdou_specialcode.cpp @@ -489,10 +489,10 @@ void BbdouSpecialCode::cursorInteractControlRoutine(Control *cursorControl, uint Control *overlappedControl = 0; if (cursorData._flags & 1) { - foundOverlapped = 0; + foundOverlapped = false; } else if (_vm->getCurrentScene() == 0x1000D) { - /* TODO foundOverlapped = artcntrlGetOverlappedObjectAccurate(cursorControl, cursorPos, - &overlappedControl, cursorData._item10._field58);*/ + foundOverlapped = _vm->_controls->getOverlappedObjectAccurate(cursorControl, cursorPos, + &overlappedControl, cursorData._item10._field58); } else { foundOverlapped = _vm->_controls->getOverlappedObject(cursorControl, cursorPos, &overlappedControl, cursorData._item10._field58); @@ -660,17 +660,15 @@ void BbdouSpecialCode::cursorCrosshairControlRoutine(Control *cursorControl, uin } - Common::Point cursorPos = getBackgroundCursorPos(cursorPos); + Common::Point cursorPos = getBackgroundCursorPos(screenCursorPos); bool foundOverlapped = false; Control *overlappedControl = 0; if (cursorData._flags & 1) foundOverlapped = false; else { - /* TODO Implement getOverlappedObjectAccurate foundOverlapped = _vm->_controls->getOverlappedObjectAccurate(cursorControl, cursorPos, &overlappedControl, cursorData._item10._field58); - */ } if (foundOverlapped) { diff --git a/engines/illusions/screen.cpp b/engines/illusions/screen.cpp index a4a3d274306..52627c84cea 100644 --- a/engines/illusions/screen.cpp +++ b/engines/illusions/screen.cpp @@ -877,6 +877,62 @@ void Screen::drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Co } +bool Screen::isSpritePixelSolid16(Common::Point &testPt, Common::Point &drawPosition, Common::Point &drawOffset, + const SurfInfo &surfInfo, int16 scale, uint flags, byte *compressedPixels) { + + int ptX = scale * drawPosition.x / 100 + testPt.x - drawOffset.x; + int ptY = scale * drawPosition.y / 100 + testPt.y - drawOffset.y; + + if (flags & 1) { + const int scaledWidth = scale * surfInfo._dimensions._width / 100; + ptX += 2 * (scaledWidth - scaledWidth / 2 - ptX); + } + + if (flags & 2) { + const int scaledHeight = scale * surfInfo._dimensions._height / 100; + ptY += 2 * (scaledHeight - scaledHeight / 2 - ptY); + } + + const int pixelLookX = 100 * ptX / scale; + const int pixelLookY = 100 * ptY / scale; + const int lookOffset = pixelLookX + surfInfo._dimensions._width * pixelLookY; + const int dstSize = surfInfo._dimensions._width * surfInfo._dimensions._height; + + if (pixelLookX < 0 || pixelLookX >= surfInfo._dimensions._width || + pixelLookY < 0 || pixelLookY >= surfInfo._dimensions._height || + lookOffset < 0 || lookOffset >= dstSize) + return false; + + byte *src = compressedPixels; + int processedSize = 0; + + while (processedSize < dstSize) { + int16 op = READ_LE_UINT16(src); + src += 2; + if (op & 0x8000) { + int runCount = (op & 0x7FFF) + 1; + uint16 runColor = READ_LE_UINT16(src); + src += 2; + while (runCount--) { + if (processedSize == lookOffset) + return runColor != _colorKey1; + ++processedSize; + } + } else { + int copyCount = op + 1; + while (copyCount--) { + uint16 color = READ_LE_UINT16(src); + src += 2; + if (processedSize == lookOffset) + return color != _colorKey1; + ++processedSize; + } + } + } + + return false; +} + uint16 Screen::convertFontColor(byte color) { if (color) { byte r, g, b; diff --git a/engines/illusions/screen.h b/engines/illusions/screen.h index 6c3e83b8ee8..e22e9b16dc7 100644 --- a/engines/illusions/screen.h +++ b/engines/illusions/screen.h @@ -181,6 +181,9 @@ public: void drawSurface20(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, uint16 colorKey); void drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect); + bool isSpritePixelSolid16(Common::Point &testPt, Common::Point &drawPosition, Common::Point &drawOffset, + const SurfInfo &surfInfo, int16 scale, uint flags, byte *compressedPixels); + uint16 convertFontColor(byte color); };