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 <jonschz@users.noreply.github.com>
This commit is contained in:
jonschz 2026-02-14 17:50:15 +01:00 committed by GitHub
parent d7f594bf7e
commit 183a69874f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 158 additions and 53 deletions

View File

@ -222,9 +222,6 @@ class LegoPathActor : public LegoActor {
MxFloat m_linearRotationRatio; // 0x150 MxFloat m_linearRotationRatio; // 0x150
}; };
// FUNCTION: LEGO1 0x1002edd0
// LegoPathActor::CheckIntersectionBothFaces
// TEMPLATE: LEGO1 0x10018b70 // TEMPLATE: LEGO1 0x10018b70
// List<LegoBoundaryEdge>::~List<LegoBoundaryEdge> // List<LegoBoundaryEdge>::~List<LegoBoundaryEdge>

View File

@ -194,16 +194,18 @@ void LegoEntity::SetLocation(
} }
// FUNCTION: LEGO1 0x10010c30 // FUNCTION: LEGO1 0x10010c30
// FUNCTION: BETA10 0x1007ea5a
void LegoEntity::TransformPointOfView() void LegoEntity::TransformPointOfView()
{ {
LegoWorld* world = CurrentWorld(); 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); world->GetCameraController()->TransformPointOfView(m_roi->GetLocal2World(), 1);
} }
} }
// FUNCTION: LEGO1 0x10010c60 // FUNCTION: LEGO1 0x10010c60
// FUNCTION: BETA10 0x1007ead0
Mx3DPointFloat LegoEntity::GetWorldDirection() Mx3DPointFloat LegoEntity::GetWorldDirection()
{ {
if (m_roi != NULL) { if (m_roi != NULL) {
@ -215,6 +217,7 @@ Mx3DPointFloat LegoEntity::GetWorldDirection()
} }
// FUNCTION: LEGO1 0x10010cf0 // FUNCTION: LEGO1 0x10010cf0
// FUNCTION: BETA10 0x1007eb47
Mx3DPointFloat LegoEntity::GetWorldUp() Mx3DPointFloat LegoEntity::GetWorldUp()
{ {
if (m_roi != NULL) { if (m_roi != NULL) {

View File

@ -188,23 +188,31 @@ MxResult LegoPathActor::SetTransformAndDestinationFromPoints(
assert(p_destEdge); assert(p_destEdge);
Vector3* v3 = p_destEdge->CWVertex(*p_boundary); Vector3* v3 = p_destEdge->CWVertex(*p_boundary);
// LINE: LEGO1 0x1002de35
Vector3* v4 = p_destEdge->CCWVertex(*p_boundary); Vector3* v4 = p_destEdge->CCWVertex(*p_boundary);
assert(v3 && v4); assert(v3 && v4);
Mx3DPointFloat end, destNormal, endDirection; Mx3DPointFloat end, destNormal, endDirection;
// LINE: LEGO1 0x1002de8f
end = *v4; end = *v4;
end -= *v3; end -= *v3;
end *= p_destScale; end *= p_destScale;
// LINE: LEGO1 0x1002deae
end += *v3; end += *v3;
// LINE: LEGO1 0x1002deba
m_boundary = p_boundary; m_boundary = p_boundary;
// LINE: LEGO1 0x1002dece
m_destEdge = p_destEdge; m_destEdge = p_destEdge;
// LINE: LEGO1 0x1002ded4
m_destScale = p_destScale; m_destScale = p_destScale;
m_traveledDistance = 0; m_traveledDistance = 0;
m_transformTime = p_time; m_transformTime = p_time;
m_actorTime = p_time; m_actorTime = p_time;
// TODO: this one fails to inline
// LINE: LEGO1 0x1002deed
p_destEdge->GetFaceNormal(*p_boundary, destNormal); p_destEdge->GetFaceNormal(*p_boundary, destNormal);
MxMatrix matrix; MxMatrix matrix;
@ -515,6 +523,95 @@ MxU32 LegoPathActor::CheckPresenterAndActorIntersections(
return 0; 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<LegoPathBoundary*> 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( inline MxU32 LegoPathActor::CheckIntersectionBothFaces(
list<LegoPathBoundary*>& p_checkedBoundaries, list<LegoPathBoundary*>& p_checkedBoundaries,
LegoPathBoundary* p_boundary, LegoPathBoundary* p_boundary,
@ -548,17 +645,22 @@ inline MxU32 LegoPathActor::CheckIntersectionBothFaces(
LegoS32 numEdges = p_boundary->GetNumEdges(); LegoS32 numEdges = p_boundary->GetNumEdges();
for (MxS32 i = 0; i < numEdges; i++) { for (MxS32 i = 0; i < numEdges; i++) {
LegoOrientedEdge* edge = p_boundary->GetEdges()[i]; LegoOrientedEdge* edge = p_boundary->GetEdges()[i];
// LINE: LEGO1 0x1002ee8c
LegoPathBoundary* boundary = (LegoPathBoundary*) edge->OtherFace(p_boundary); LegoPathBoundary* boundary = (LegoPathBoundary*) edge->OtherFace(p_boundary);
// LINE: LEGO1 0x1002ee9f
if (boundary != NULL) { if (boundary != NULL) {
list<LegoPathBoundary*>::const_iterator it; list<LegoPathBoundary*>::const_iterator it;
// LINE: LEGO1 0x1002eead
for (it = p_checkedBoundaries.begin(); !(it == p_checkedBoundaries.end()); it++) { for (it = p_checkedBoundaries.begin(); !(it == p_checkedBoundaries.end()); it++) {
// LINE: LEGO1 0x1002eeb3
if ((*it) == boundary) { if ((*it) == boundary) {
break; break;
} }
} }
// LINE: LEGO1 0x1002eec4
if (it == p_checkedBoundaries.end()) { if (it == p_checkedBoundaries.end()) {
result = CheckIntersectionBothFaces( result = CheckIntersectionBothFaces(
p_checkedBoundaries, p_checkedBoundaries,
@ -581,39 +683,6 @@ inline MxU32 LegoPathActor::CheckIntersectionBothFaces(
return 0; 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<LegoPathBoundary*> boundaries;
return CheckIntersectionBothFaces(
boundaries,
m_boundary,
p_rayOrigin,
rayDirection,
len,
radius,
p_intersectionPoint,
0
);
}
// FUNCTION: LEGO1 0x1002f020 // FUNCTION: LEGO1 0x1002f020
// FUNCTION: BETA10 0x100af54a // FUNCTION: BETA10 0x100af54a
void LegoPathActor::ParseAction(char* p_extra) void LegoPathActor::ParseAction(char* p_extra)

View File

@ -6,6 +6,7 @@
DECOMP_SIZE_ASSERT(LegoEdge, 0x24) DECOMP_SIZE_ASSERT(LegoEdge, 0x24)
// FUNCTION: LEGO1 0x1009a470 // FUNCTION: LEGO1 0x1009a470
// FUNCTION: BETA10 0x10182250
LegoEdge::LegoEdge() LegoEdge::LegoEdge()
{ {
m_faceA = NULL; m_faceA = NULL;
@ -19,36 +20,65 @@ LegoEdge::LegoEdge()
} }
// FUNCTION: LEGO1 0x1009a4c0 // FUNCTION: LEGO1 0x1009a4c0
// FUNCTION: BETA10 0x101822c2
LegoEdge::~LegoEdge() 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: LEGO1 0x1009a4d0
// FUNCTION: BETA10 0x10182397
LegoEdge* LegoEdge::GetClockwiseEdge(LegoWEEdge& p_face) LegoEdge* LegoEdge::GetClockwiseEdge(LegoWEEdge& p_face)
{ {
if (&p_face == m_faceA) { if (&p_face == m_faceA) {
return m_cwA; return m_cwA;
} }
else if (&p_face == m_faceB) { if (&p_face == m_faceB) {
return m_cwB; return m_cwB;
} }
else {
return NULL; return NULL;
}
} }
// FUNCTION: LEGO1 0x1009a4f0 // FUNCTION: LEGO1 0x1009a4f0
// FUNCTION: BETA10 0x101823e5
LegoEdge* LegoEdge::GetCounterclockwiseEdge(LegoWEEdge& p_face) LegoEdge* LegoEdge::GetCounterclockwiseEdge(LegoWEEdge& p_face)
{ {
if (&p_face == m_faceA) { if (&p_face == m_faceA) {
return m_ccwA; return m_ccwA;
} }
else if (&p_face == m_faceB) { if (&p_face == m_faceB) {
return m_ccwB; return m_ccwB;
} }
else {
return NULL; return NULL;
}
} }
// FUNCTION: LEGO1 0x1009a510 // FUNCTION: LEGO1 0x1009a510
@ -58,10 +88,8 @@ Vector3* LegoEdge::CWVertex(LegoWEEdge& p_face)
if (m_faceA == &p_face) { if (m_faceA == &p_face) {
return m_pointB; return m_pointB;
} }
else {
assert(m_faceB == &p_face); assert(m_faceB == &p_face);
return m_pointA; return m_pointA;
}
} }
// FUNCTION: LEGO1 0x1009a530 // FUNCTION: LEGO1 0x1009a530
@ -71,8 +99,6 @@ Vector3* LegoEdge::CCWVertex(LegoWEEdge& p_face)
if (m_faceB == &p_face) { if (m_faceB == &p_face) {
return m_pointB; return m_pointB;
} }
else {
assert(m_faceA == &p_face); assert(m_faceA == &p_face);
return m_pointA; return m_pointA;
}
} }

View File

@ -7,11 +7,14 @@ class LegoWEEdge;
class Vector3; class Vector3;
// VTABLE: LEGO1 0x100db7b8 // VTABLE: LEGO1 0x100db7b8
// VTABLE: BETA10 0x101c3728
// SIZE 0x24 // SIZE 0x24
struct LegoEdge { struct LegoEdge {
LegoEdge(); LegoEdge();
virtual ~LegoEdge(); // vtable+0x00 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* GetClockwiseEdge(LegoWEEdge& p_face);
LegoEdge* GetCounterclockwiseEdge(LegoWEEdge& p_face); LegoEdge* GetCounterclockwiseEdge(LegoWEEdge& p_face);
Vector3* CWVertex(LegoWEEdge& p_face); Vector3* CWVertex(LegoWEEdge& p_face);
@ -32,6 +35,7 @@ struct LegoEdge {
Vector3* GetPointB() { return m_pointB; } Vector3* GetPointB() { return m_pointB; }
// SYNTHETIC: LEGO1 0x1009a4a0 // SYNTHETIC: LEGO1 0x1009a4a0
// SYNTHETIC: BETA10 0x10182b30
// LegoEdge::`scalar deleting destructor' // LegoEdge::`scalar deleting destructor'
LegoWEEdge* m_faceA; // 0x04 LegoWEEdge* m_faceA; // 0x04

View File

@ -8,6 +8,7 @@
#include <assert.h> #include <assert.h>
// VTABLE: LEGO1 0x100db7f4 // VTABLE: LEGO1 0x100db7f4
// VTABLE: BETA10 0x101c3794
// SIZE 0x40 // SIZE 0x40
struct LegoOrientedEdge : public LegoEdge { struct LegoOrientedEdge : public LegoEdge {
public: public:
@ -99,8 +100,12 @@ struct LegoOrientedEdge : public LegoEdge {
inline LegoU32 FUN_10048c40(const Vector3& p_position); inline LegoU32 FUN_10048c40(const Vector3& p_position);
// SYNTHETIC: LEGO1 0x1009a6c0 // SYNTHETIC: LEGO1 0x1009a6c0
// SYNTHETIC: BETA10 0x101840f0
// LegoOrientedEdge::`scalar deleting destructor' // LegoOrientedEdge::`scalar deleting destructor'
// SYNTHETIC: BETA10 0x100bd390
// LegoOrientedEdge::~LegoOrientedEdge
LegoU16 m_flags; // 0x24 LegoU16 m_flags; // 0x24
Mx3DPointFloat m_dir; // 0x28 Mx3DPointFloat m_dir; // 0x28
float m_length; // 0x3c float m_length; // 0x3c

View File

@ -29,6 +29,7 @@ void OrientableROI::WrappedSetLocal2WorldWithWorldDataUpdate(const Matrix4& p_lo
} }
// FUNCTION: LEGO1 0x100a46b0 // FUNCTION: LEGO1 0x100a46b0
// FUNCTION: BETA10 0x1016528f
void OrientableROI::UpdateTransformationRelativeToParent(const Matrix4& p_transform) void OrientableROI::UpdateTransformationRelativeToParent(const Matrix4& p_transform)
{ {
MxMatrix mat; MxMatrix mat;