From cbcae58caf674198bf19f4b8bb3bf07c0a30055b Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 6 Sep 2011 15:42:54 -0400 Subject: PEGASUS: Properly handle regions in hotspots --- engines/pegasus/hotspot.cpp | 125 ++++++++++++++++++++++++-- engines/pegasus/hotspot.h | 43 ++++++++- engines/pegasus/neighborhood/neighborhood.cpp | 20 ++--- 3 files changed, 163 insertions(+), 25 deletions(-) diff --git a/engines/pegasus/hotspot.cpp b/engines/pegasus/hotspot.cpp index 58ca353831..b8ff97a897 100755 --- a/engines/pegasus/hotspot.cpp +++ b/engines/pegasus/hotspot.cpp @@ -23,12 +23,123 @@ * */ +#include "common/stream.h" + #include "pegasus/hotspot.h" namespace Pegasus { HotspotList g_allHotspots; +Region::Region(Common::ReadStream *stream) { + uint16 length = stream->readUint16BE(); + + assert(length >= 10); + + _bounds.top = stream->readUint16BE(); + _bounds.left = stream->readUint16BE(); + _bounds.bottom = stream->readUint16BE(); + _bounds.right = stream->readUint16BE(); + + _bounds.debugPrint(0, "Bounds:"); + + if (length == 10) + return; + + length -= 10; + + while (length > 0) { + Vector v; + v.y = stream->readUint16BE(); + length -= 2; + + if (v.y == 0x7fff) + break; + + debug(0, "y: %d", v.y); + + // Normalize y to _bounds + v.y -= _bounds.top; + + while (length > 0) { + Run run; + run.start = stream->readUint16BE(); + length -= 2; + + if (run.start == 0x7fff) + break; + + run.end = stream->readUint16BE(); + length -= 2; + + debug(0, "\t[%d, %d)", run.start, run.end); + + // Normalize to _bounds + run.start -= _bounds.left; + run.end -= _bounds.left; + + v.push_back(run); + } + + _vectors.push_back(v); + } +} + +Region::Region(const Common::Rect &rect) { + _bounds = rect; +} + +bool Region::pointInRegion(const Common::Point &point) const { + if (!_bounds.contains(point)) + return false; + + bool pixelActive = false; + + // Normalize the points to _bounds + uint16 x = point.x - _bounds.left; + uint16 y = point.y - _bounds.top; + + for (Common::List::const_iterator v = _vectors.begin(); v != _vectors.end(); v++) { + if (v->y > y) + return pixelActive; + + for (Vector::const_iterator run = v->begin(); run != v->end(); run++) { + if (x >= run->start && x < run->end) { + pixelActive = !pixelActive; + break; + } + } + } + + // the case if the region is just a rect + return true; +} + +void Region::moveTo(tCoordType h, tCoordType v) { + _bounds.moveTo(h, v); +} + +void Region::moveTo(const Common::Point &point) { + _bounds.moveTo(point); +} + +void Region::translate(tCoordType h, tCoordType v) { + _bounds.translate(h, v); +} + +void Region::translate(const Common::Point &point) { + _bounds.translate(point.x, point.y); +} + +void Region::getCenter(tCoordType &h, tCoordType &v) const { + h = (_bounds.left + _bounds.right) / 2; + v = (_bounds.top + _bounds.bottom) / 2; +} + +void Region::getCenter(Common::Point &point) const { + getCenter(point.x, point.y); +} + Hotspot::Hotspot(const tHotSpotID id) : IDObject(id) { _spotFlags = kNoHotSpotFlags; _spotActive = false; @@ -38,25 +149,23 @@ Hotspot::~Hotspot() { } void Hotspot::setArea(const Common::Rect &area) { - _spotArea = area; + _spotArea = Region(area); } void Hotspot::setArea(const tCoordType left, const tCoordType top, const tCoordType right, const tCoordType bottom) { - _spotArea = Common::Rect(left, top, right, bottom); + _spotArea = Region(Common::Rect(left, top, right, bottom)); } void Hotspot::getBoundingBox(Common::Rect &r) const { - r = _spotArea; + r = _spotArea.getBoundingBox(); } void Hotspot::getCenter(Common::Point &pt) const { - pt.x = (_spotArea.left + _spotArea.right) / 2; - pt.y = (_spotArea.top + _spotArea.bottom) / 2; + _spotArea.getCenter(pt); } void Hotspot::getCenter(tCoordType &h, tCoordType &v) const { - h = (_spotArea.left + _spotArea.right) / 2; - v = (_spotArea.top + _spotArea.bottom) / 2; + _spotArea.getCenter(h, v); } void Hotspot::setActive() { @@ -96,7 +205,7 @@ void Hotspot::moveSpot(const Common::Point pt) { } bool Hotspot::pointInSpot(const Common::Point where) const { - return _spotActive && _spotArea.contains(where); + return _spotActive && _spotArea.pointInRegion(where); } tHotSpotFlags Hotspot::getHotspotFlags() const { diff --git a/engines/pegasus/hotspot.h b/engines/pegasus/hotspot.h index d5a2fb0f6f..aafb96cc19 100755 --- a/engines/pegasus/hotspot.h +++ b/engines/pegasus/hotspot.h @@ -44,16 +44,55 @@ */ +namespace Common { + class ReadStream; +} + namespace Pegasus { +// Our implementation of QuickDraw regions +class Region { +public: + Region() {} + Region(Common::ReadStream *stream); + Region(const Common::Rect &rect); + + Common::Rect getBoundingBox() const { return _bounds; } + + bool pointInRegion(const Common::Point &point) const; + + void moveTo(tCoordType h, tCoordType v); + void moveTo(const Common::Point &point); + void translate(tCoordType h, tCoordType v); + void translate(const Common::Point &point); + void getCenter(tCoordType &h, tCoordType &v) const; + void getCenter(Common::Point &point) const; + +private: + Common::Rect _bounds; + + struct Run { + uint16 start, end; + }; + + class Vector : public Common::List { + public: + uint16 y; + }; + + Common::List _vectors; +}; + class Hotspot : public IDObject { public: Hotspot(const tHotSpotID); virtual ~Hotspot(); - + + void setArea(const Region ®ion) { _spotArea = region; } void setArea(const Common::Rect &); void setArea(const tCoordType, const tCoordType, const tCoordType, const tCoordType); void getBoundingBox(Common::Rect &) const; + void getArea(Region &) const; void getCenter(Common::Point&) const; void getCenter(tCoordType&, tCoordType&) const; @@ -73,7 +112,7 @@ public: void setMaskedHotspotFlags(const tHotSpotFlags flags, const tHotSpotFlags mask); protected: - Common::Rect _spotArea; + Region _spotArea; tHotSpotFlags _spotFlags; bool _spotActive; }; diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp index 39efda35e5..8381188764 100644 --- a/engines/pegasus/neighborhood/neighborhood.cpp +++ b/engines/pegasus/neighborhood/neighborhood.cpp @@ -249,26 +249,16 @@ void Neighborhood::createNeighborhoodSpots() { uint32 flags = hotspotList->readUint32BE(); uint32 rgnSize = hotspotList->readUint32BE(); - // duplicate of rgnSize - hotspotList->readUint16BE(); + int32 startPos = hotspotList->pos(); - Common::Rect boundingBox; - boundingBox.top = hotspotList->readUint16BE(); - boundingBox.left = hotspotList->readUint16BE(); - boundingBox.bottom = hotspotList->readUint16BE(); - boundingBox.right = hotspotList->readUint16BE(); + debug(0, "Hotspot %d:", id); + Region region(hotspotList); - debug(0, "Hotspot[%d]: Flags = %08x", id, flags); - boundingBox.debugPrint(0, "\tBounding Box:"); - - // TODO: Handle non-rectangular hotspots - if (rgnSize != 10) - warning("Non-rectangular hotspot found - %d extra bytes", rgnSize - 10); - hotspotList->skip(rgnSize - 10); + hotspotList->seek(startPos + rgnSize); Hotspot *hotspot = new Hotspot(id); hotspot->setHotspotFlags(flags); - hotspot->setArea(boundingBox); + hotspot->setArea(region); g_allHotspots.push_back(hotspot); _neighborhoodHotspots.push_back(hotspot); -- cgit v1.2.3