From 183a69874f03cd87368fd4d03717319a76582f4f Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Sat, 14 Feb 2026 17:50:15 +0100 Subject: [PATCH] Beta matches on `LegoEdge` and others, `LegoPathActor` improvements (#1743) * BETA matches for LegoEdge and related * Some progress on CheckIntersections * Cleanup * Fix duplicate offset --------- Co-authored-by: jonschz --- LEGO1/lego/legoomni/include/legopathactor.h | 3 - LEGO1/lego/legoomni/src/entity/legoentity.cpp | 5 +- .../lego/legoomni/src/paths/legopathactor.cpp | 135 +++++++++++++----- LEGO1/lego/sources/geom/legoedge.cpp | 58 +++++--- LEGO1/lego/sources/geom/legoedge.h | 4 + LEGO1/lego/sources/geom/legoorientededge.h | 5 + LEGO1/realtime/orientableroi.cpp | 1 + 7 files changed, 158 insertions(+), 53 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index 491e067c..dac4f341 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -222,9 +222,6 @@ class LegoPathActor : public LegoActor { MxFloat m_linearRotationRatio; // 0x150 }; -// FUNCTION: LEGO1 0x1002edd0 -// LegoPathActor::CheckIntersectionBothFaces - // TEMPLATE: LEGO1 0x10018b70 // List::~List diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index d02c1c71..544b3384 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -194,16 +194,18 @@ void LegoEntity::SetLocation( } // FUNCTION: LEGO1 0x10010c30 +// FUNCTION: BETA10 0x1007ea5a void LegoEntity::TransformPointOfView() { LegoWorld* world = CurrentWorld(); - if (m_cameraFlag && world && world->GetCameraController() && m_roi) { + if (GetCameraFlag() && world && world->GetCameraController() && m_roi) { world->GetCameraController()->TransformPointOfView(m_roi->GetLocal2World(), 1); } } // FUNCTION: LEGO1 0x10010c60 +// FUNCTION: BETA10 0x1007ead0 Mx3DPointFloat LegoEntity::GetWorldDirection() { if (m_roi != NULL) { @@ -215,6 +217,7 @@ Mx3DPointFloat LegoEntity::GetWorldDirection() } // FUNCTION: LEGO1 0x10010cf0 +// FUNCTION: BETA10 0x1007eb47 Mx3DPointFloat LegoEntity::GetWorldUp() { if (m_roi != NULL) { diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index 2fca5127..cee77829 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -188,23 +188,31 @@ MxResult LegoPathActor::SetTransformAndDestinationFromPoints( assert(p_destEdge); Vector3* v3 = p_destEdge->CWVertex(*p_boundary); + // LINE: LEGO1 0x1002de35 Vector3* v4 = p_destEdge->CCWVertex(*p_boundary); assert(v3 && v4); Mx3DPointFloat end, destNormal, endDirection; + // LINE: LEGO1 0x1002de8f end = *v4; end -= *v3; end *= p_destScale; + // LINE: LEGO1 0x1002deae end += *v3; + // LINE: LEGO1 0x1002deba m_boundary = p_boundary; + // LINE: LEGO1 0x1002dece m_destEdge = p_destEdge; + // LINE: LEGO1 0x1002ded4 m_destScale = p_destScale; m_traveledDistance = 0; m_transformTime = p_time; m_actorTime = p_time; + // TODO: this one fails to inline + // LINE: LEGO1 0x1002deed p_destEdge->GetFaceNormal(*p_boundary, destNormal); MxMatrix matrix; @@ -515,6 +523,95 @@ MxU32 LegoPathActor::CheckPresenterAndActorIntersections( return 0; } +#ifdef BETA10 +// FUNCTION: BETA10 0x100af35e +MxS32 LegoPathActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) +{ + assert(m_boundary && m_roi); + + Mx3DPointFloat rayDirection(p_rayEnd); + rayDirection -= p_rayOrigin; + + float len = rayDirection.LenSquared(); + + if (len <= 0.001) { + return 0; + } + + len = sqrt((double) len); + rayDirection /= len; + + float radius = m_roi->GetWorldBoundingSphere().Radius(); + LegoPathBoundary* b = m_boundary; + LegoOrientedEdge* local14 = *m_boundary->GetEdges(); + LegoOrientedEdge* local18 = NULL; + + while (1) { + assert(b); + + MxU32 result = + CheckPresenterAndActorIntersections(b, p_rayOrigin, rayDirection, len, radius, p_intersectionPoint); + + if (result != 0) { + return result; + } + + if (local18 == NULL) { + local18 = (LegoOrientedEdge*) local14->GetCounterclockwiseEdge(*m_boundary); + b = (LegoPathBoundary*) local14->OtherFace(m_boundary); + } + else { + b = NULL; + } + + while (!b) { + if (local18 == local14) { + return 0; + } + + b = (LegoPathBoundary*) local18->OtherFace(m_boundary); + local18 = (LegoOrientedEdge*) local18->GetCounterclockwiseEdge(*m_boundary); + } + } + + return 0; +} +#else +// FUNCTION: LEGO1 0x1002ebe0 +MxS32 LegoPathActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) +{ + assert(m_boundary && m_roi); + + Mx3DPointFloat rayDirection(p_rayEnd); + rayDirection -= p_rayOrigin; + + float len = rayDirection.LenSquared(); + + if (len <= 0.001) { + return 0; + } + + len = sqrt((double) len); + rayDirection /= len; + + float radius = m_roi->GetWorldBoundingSphere().Radius(); + list boundaries; + // This function is inlined once. The recursion calls into the actual function. + // Matching `CheckIntersectionBothFaces` will likely match `CheckIntersections` as well. + return CheckIntersectionBothFaces( + boundaries, + m_boundary, + p_rayOrigin, + rayDirection, + len, + radius, + p_intersectionPoint, + 0 + ); +} +#endif + +// FUNCTION: LEGO1 0x1002edd0 inline MxU32 LegoPathActor::CheckIntersectionBothFaces( list& p_checkedBoundaries, LegoPathBoundary* p_boundary, @@ -548,17 +645,22 @@ inline MxU32 LegoPathActor::CheckIntersectionBothFaces( LegoS32 numEdges = p_boundary->GetNumEdges(); for (MxS32 i = 0; i < numEdges; i++) { LegoOrientedEdge* edge = p_boundary->GetEdges()[i]; + // LINE: LEGO1 0x1002ee8c LegoPathBoundary* boundary = (LegoPathBoundary*) edge->OtherFace(p_boundary); + // LINE: LEGO1 0x1002ee9f if (boundary != NULL) { list::const_iterator it; + // LINE: LEGO1 0x1002eead for (it = p_checkedBoundaries.begin(); !(it == p_checkedBoundaries.end()); it++) { + // LINE: LEGO1 0x1002eeb3 if ((*it) == boundary) { break; } } + // LINE: LEGO1 0x1002eec4 if (it == p_checkedBoundaries.end()) { result = CheckIntersectionBothFaces( p_checkedBoundaries, @@ -581,39 +683,6 @@ inline MxU32 LegoPathActor::CheckIntersectionBothFaces( return 0; } -// FUNCTION: LEGO1 0x1002ebe0 -// FUNCTION: BETA10 0x100af35e -MxS32 LegoPathActor::CheckIntersections(Vector3& p_rayOrigin, Vector3& p_rayEnd, Vector3& p_intersectionPoint) -{ - assert(m_boundary && m_roi); - - Mx3DPointFloat rayDirection(p_rayEnd); - rayDirection -= p_rayOrigin; - - float len = rayDirection.LenSquared(); - - if (len <= 0.001) { - return 0; - } - - len = sqrt((double) len); - rayDirection /= len; - - float radius = m_roi->GetWorldBoundingSphere().Radius(); - list boundaries; - - return CheckIntersectionBothFaces( - boundaries, - m_boundary, - p_rayOrigin, - rayDirection, - len, - radius, - p_intersectionPoint, - 0 - ); -} - // FUNCTION: LEGO1 0x1002f020 // FUNCTION: BETA10 0x100af54a void LegoPathActor::ParseAction(char* p_extra) diff --git a/LEGO1/lego/sources/geom/legoedge.cpp b/LEGO1/lego/sources/geom/legoedge.cpp index d1a810d6..2bcea209 100644 --- a/LEGO1/lego/sources/geom/legoedge.cpp +++ b/LEGO1/lego/sources/geom/legoedge.cpp @@ -6,6 +6,7 @@ DECOMP_SIZE_ASSERT(LegoEdge, 0x24) // FUNCTION: LEGO1 0x1009a470 +// FUNCTION: BETA10 0x10182250 LegoEdge::LegoEdge() { m_faceA = NULL; @@ -19,36 +20,65 @@ LegoEdge::LegoEdge() } // FUNCTION: LEGO1 0x1009a4c0 +// FUNCTION: BETA10 0x101822c2 LegoEdge::~LegoEdge() { } +// FUNCTION: BETA10 0x101822e1 +LegoResult LegoEdge::SetCounterclockwiseEdge(LegoWEEdge& p_face, LegoEdge* p_edge) +{ + // unreferenced in BETA10, not in LEGO1 + if (&p_face == m_faceA) { + m_ccwA = p_edge; + return SUCCESS; + } + if (&p_face == m_faceB) { + m_ccwB = p_edge; + return SUCCESS; + } + return FAILURE; +} + +// FUNCTION: BETA10 0x1018233c +LegoResult LegoEdge::SetClockwiseEdge(LegoWEEdge& p_face, LegoEdge* p_edge) +{ + // unreferenced in BETA10, not in LEGO1 + if (&p_face == m_faceA) { + m_cwA = p_edge; + return SUCCESS; + } + if (&p_face == m_faceB) { + m_cwB = p_edge; + return SUCCESS; + } + return FAILURE; +} + // FUNCTION: LEGO1 0x1009a4d0 +// FUNCTION: BETA10 0x10182397 LegoEdge* LegoEdge::GetClockwiseEdge(LegoWEEdge& p_face) { if (&p_face == m_faceA) { return m_cwA; } - else if (&p_face == m_faceB) { + if (&p_face == m_faceB) { return m_cwB; } - else { - return NULL; - } + return NULL; } // FUNCTION: LEGO1 0x1009a4f0 +// FUNCTION: BETA10 0x101823e5 LegoEdge* LegoEdge::GetCounterclockwiseEdge(LegoWEEdge& p_face) { if (&p_face == m_faceA) { return m_ccwA; } - else if (&p_face == m_faceB) { + if (&p_face == m_faceB) { return m_ccwB; } - else { - return NULL; - } + return NULL; } // FUNCTION: LEGO1 0x1009a510 @@ -58,10 +88,8 @@ Vector3* LegoEdge::CWVertex(LegoWEEdge& p_face) if (m_faceA == &p_face) { return m_pointB; } - else { - assert(m_faceB == &p_face); - return m_pointA; - } + assert(m_faceB == &p_face); + return m_pointA; } // FUNCTION: LEGO1 0x1009a530 @@ -71,8 +99,6 @@ Vector3* LegoEdge::CCWVertex(LegoWEEdge& p_face) if (m_faceB == &p_face) { return m_pointB; } - else { - assert(m_faceA == &p_face); - return m_pointA; - } + assert(m_faceA == &p_face); + return m_pointA; } diff --git a/LEGO1/lego/sources/geom/legoedge.h b/LEGO1/lego/sources/geom/legoedge.h index 9a14eef4..31cdfddf 100644 --- a/LEGO1/lego/sources/geom/legoedge.h +++ b/LEGO1/lego/sources/geom/legoedge.h @@ -7,11 +7,14 @@ class LegoWEEdge; class Vector3; // VTABLE: LEGO1 0x100db7b8 +// VTABLE: BETA10 0x101c3728 // SIZE 0x24 struct LegoEdge { LegoEdge(); virtual ~LegoEdge(); // vtable+0x00 + LegoResult SetCounterclockwiseEdge(LegoWEEdge& p_face, LegoEdge* p_edge); + LegoResult SetClockwiseEdge(LegoWEEdge& p_face, LegoEdge* p_edge); LegoEdge* GetClockwiseEdge(LegoWEEdge& p_face); LegoEdge* GetCounterclockwiseEdge(LegoWEEdge& p_face); Vector3* CWVertex(LegoWEEdge& p_face); @@ -32,6 +35,7 @@ struct LegoEdge { Vector3* GetPointB() { return m_pointB; } // SYNTHETIC: LEGO1 0x1009a4a0 + // SYNTHETIC: BETA10 0x10182b30 // LegoEdge::`scalar deleting destructor' LegoWEEdge* m_faceA; // 0x04 diff --git a/LEGO1/lego/sources/geom/legoorientededge.h b/LEGO1/lego/sources/geom/legoorientededge.h index bb613563..05cd8009 100644 --- a/LEGO1/lego/sources/geom/legoorientededge.h +++ b/LEGO1/lego/sources/geom/legoorientededge.h @@ -8,6 +8,7 @@ #include // VTABLE: LEGO1 0x100db7f4 +// VTABLE: BETA10 0x101c3794 // SIZE 0x40 struct LegoOrientedEdge : public LegoEdge { public: @@ -99,8 +100,12 @@ struct LegoOrientedEdge : public LegoEdge { inline LegoU32 FUN_10048c40(const Vector3& p_position); // SYNTHETIC: LEGO1 0x1009a6c0 + // SYNTHETIC: BETA10 0x101840f0 // LegoOrientedEdge::`scalar deleting destructor' + // SYNTHETIC: BETA10 0x100bd390 + // LegoOrientedEdge::~LegoOrientedEdge + LegoU16 m_flags; // 0x24 Mx3DPointFloat m_dir; // 0x28 float m_length; // 0x3c diff --git a/LEGO1/realtime/orientableroi.cpp b/LEGO1/realtime/orientableroi.cpp index 3c45e90f..db46a206 100644 --- a/LEGO1/realtime/orientableroi.cpp +++ b/LEGO1/realtime/orientableroi.cpp @@ -29,6 +29,7 @@ void OrientableROI::WrappedSetLocal2WorldWithWorldDataUpdate(const Matrix4& p_lo } // FUNCTION: LEGO1 0x100a46b0 +// FUNCTION: BETA10 0x1016528f void OrientableROI::UpdateTransformationRelativeToParent(const Matrix4& p_transform) { MxMatrix mat;