[Scummvm-git-logs] scummvm master -> 34faf7f6ead4fc3cec65dc697b54a4d73d790c5f
elasota
noreply at scummvm.org
Fri Jun 24 06:58:22 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
34faf7f6ea MTROPOLIS: Shape click detection
Commit: 34faf7f6ead4fc3cec65dc697b54a4d73d790c5f
https://github.com/scummvm/scummvm/commit/34faf7f6ead4fc3cec65dc697b54a4d73d790c5f
Author: elasota (ejlasota at gmail.com)
Date: 2022-06-24T02:57:35-04:00
Commit Message:
MTROPOLIS: Shape click detection
Changed paths:
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 82aa4a5f7ae..565cee13ef2 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -4292,7 +4292,7 @@ void Runtime::recursiveFindMouseCollision(Structural *&bestResult, int32 &bestLa
}
}
- if (isInFront && visual->isMouseInsideBox(relativeX, relativeY) && isStructuralMouseInteractive(visual, testType) && visual->isMouseCollisionAtPoint(relativeX, relativeY)) {
+ if (isInFront && visual->isMouseInsideDrawableArea(relativeX, relativeY) && isStructuralMouseInteractive(visual, testType) && visual->isMouseCollisionAtPoint(relativeX, relativeY)) {
bestResult = candidate;
bestLayer = layer;
bestStackHeight = stackHeight;
@@ -4802,7 +4802,7 @@ VThreadState Runtime::updateMousePositionTask(const UpdateMousePositionTaskData
Common::Point parentOrigin = visual->getParentOrigin();
int32 relativeX = data.x - parentOrigin.x;
int32 relativeY = data.y - parentOrigin.y;
- bool mouseOutside = !visual->isMouseInsideBox(relativeX, relativeY) || !visual->isMouseCollisionAtPoint(relativeX, relativeY);
+ bool mouseOutside = !visual->isMouseInsideDrawableArea(relativeX, relativeY) || !visual->isMouseCollisionAtPoint(relativeX, relativeY);
if (mouseOutside != _trackedMouseOutside) {
if (mouseOutside) {
@@ -6718,8 +6718,128 @@ VThreadState VisualElement::consumeCommand(Runtime *runtime, const Common::Share
return Element::consumeCommand(runtime, msg);
}
-bool VisualElement::isMouseInsideBox(int32 relativeX, int32 relativeY) const {
- return relativeX >= _rect.left && relativeX < _rect.right && relativeY >= _rect.top && relativeY < _rect.bottom;
+bool VisualElement::isMouseInsideDrawableArea(int32 relativeX, int32 relativeY) const {
+ if (relativeX < _rect.left || relativeX >= _rect.right || relativeY < _rect.top || relativeY >= _rect.bottom)
+ return false;
+
+ // NOTE: This is actually incomplete, graphic modifiers are supposed to mask out the drawable area for non-rect
+ // shapes, so what we SHOULD be doing here is generating a mask and hoisting the mask gen code out of
+ // GraphicModifier to more common code, and check the mask here.
+ //
+ // For now, we just use this for click detection.
+ relativeX -= _rect.left;
+ relativeY -= _rect.top;
+
+ switch (_renderProps.getShape()) {
+ case VisualElementRenderProperties::kShapePolygon:
+ case VisualElementRenderProperties::kShapeStar: {
+ Common::Point starPoints[10];
+ const Common::Point *polyPoints = nullptr;
+ size_t numPolyPoints = 0;
+
+ if (_renderProps.getShape() == VisualElementRenderProperties::kShapeStar) {
+ int16 width = _rect.width();
+ int16 height = _rect.height();
+ starPoints[0] = Common::Point(width / 2, 0);
+ starPoints[1] = Common::Point(width * 2 / 3, height / 3);
+ starPoints[2] = Common::Point(width, height / 3);
+ starPoints[3] = Common::Point(width * 3 / 4, height / 2);
+ starPoints[4] = Common::Point(width, height);
+ starPoints[5] = Common::Point(width / 2, height * 2 / 3);
+ starPoints[6] = Common::Point(0, height);
+ starPoints[7] = Common::Point(width / 4, height / 2);
+ starPoints[8] = Common::Point(0, height / 3);
+ starPoints[9] = Common::Point(width / 3, height / 3);
+ polyPoints = starPoints;
+ numPolyPoints = 10;
+ } else {
+ numPolyPoints = _renderProps.getPolyPoints().size();
+ if (numPolyPoints > 0)
+ polyPoints = &_renderProps.getPolyPoints()[0];
+ else
+ return false;
+ }
+
+ bool insideMask = false;
+ for (size_t edgeIndex = 2; edgeIndex < numPolyPoints; edgeIndex++) {
+ const Common::Point *points[3] = {&polyPoints[0], &polyPoints[edgeIndex - 1], &polyPoints[edgeIndex]};
+
+ int32 rays[3][2];
+ int32 normals[3][2];
+
+ for (int i = 0; i < 3; i++) {
+ const Common::Point *nextPoint = points[(i + 1) % 3];
+ rays[i][0] = nextPoint->x - points[i]->x;
+ rays[i][1] = nextPoint->y - points[i]->y;
+
+ normals[i][0] = -rays[i][1];
+ normals[i][1] = rays[i][0];
+ }
+
+ int32 cDist = rays[1][0] * normals[0][0] + rays[1][1] * normals[0][1];
+ if (cDist == 0)
+ continue; // Degenerate triangle
+
+ if (cDist < 0) {
+ // Counter-clockwise triangle, flip normals
+ for (int i = 0; i < 3; i++) {
+ normals[i][0] = -normals[i][0];
+ normals[i][1] = -normals[i][1];
+ }
+ }
+
+ bool inFrontOfAll = true;
+ for (int i = 0; i < 3; i++) {
+ int32 nx = normals[i][0];
+ int32 ny = normals[i][1];
+ int32 dist = (relativeX - points[i]->x) * nx + (relativeY - points[i]->y) * ny;
+ bool isInFront = (dist > 0);
+ if (dist == 0) {
+ if (nx != 0)
+ isInFront = (nx >= 0);
+ else
+ isInFront = (ny >= 0);
+ }
+
+ if (!isInFront) {
+ inFrontOfAll = false;
+ break;
+ }
+ }
+
+ if (inFrontOfAll)
+ insideMask = !insideMask;
+ }
+
+ return insideMask;
+ } break;
+ case VisualElementRenderProperties::kShapeRect:
+ // Rect is always in collision if inside of the rect
+ return true;
+
+ case VisualElementRenderProperties::kShapeOval: {
+ int32 w = _rect.width();
+ int32 h = _rect.height();
+
+ int32 dcx = relativeX * 2 - w;
+ int32 dcy = relativeY * 2 - h;
+ dcx *= h;
+ dcy *= w;
+
+ int32 expandedRadius = w * h;
+
+ return (dcx * dcx + dcy * dcy <= expandedRadius * expandedRadius);
+ } break;
+
+ case VisualElementRenderProperties::kShapeRoundedRect:
+ // Rounded rect corners are 13x13 at maximum
+
+ default:
+ warning("Unsupported shape type for checking mouse collision");
+ return false;
+ };
+
+ return true;
}
bool VisualElement::isMouseCollisionAtPoint(int32 relativeX, int32 relativeY) const {
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 32b67be486b..12e983813ef 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -2398,7 +2398,7 @@ public:
bool isDirectToScreen() const;
uint16 getLayer() const;
- bool isMouseInsideBox(int32 relativeX, int32 relativeY) const;
+ bool isMouseInsideDrawableArea(int32 relativeX, int32 relativeY) const;
// Returns true if there is mouse collision at a specified point, assuming it has already passed isMouseInsideBox
virtual bool isMouseCollisionAtPoint(int32 relativeX, int32 relativeY) const;
More information about the Scummvm-git-logs
mailing list