From 90c687bde0e9dd82fb4e928445fda8b49403daea Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 17 Dec 2024 15:16:00 -0700 Subject: [PATCH 1/4] Implement/match `Act3Brickster::FUN_10042300` (#1238) * Implement/match `Act3Brickster::FUN_10042300` * Add comment about assignment operator * Add another comment * Fix * add back BETA annotation --- .../legoomni/include/legopathcontroller.h | 4 +- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 100 +++++++++++++++++- .../legoomni/src/paths/legopathcontroller.cpp | 62 ----------- LEGO1/lego/sources/geom/legoedge.h | 6 ++ LEGO1/lego/sources/geom/legounkown100db7f4.h | 64 +++++++++++ LEGO1/mxgeometry/mxgeometry3d.h | 3 + LEGO1/realtime/vector.h | 17 +++ 7 files changed, 188 insertions(+), 68 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legopathcontroller.h b/LEGO1/lego/legoomni/include/legopathcontroller.h index 85ef1f9f..37096cc2 100644 --- a/LEGO1/lego/legoomni/include/legopathcontroller.h +++ b/LEGO1/lego/legoomni/include/legopathcontroller.h @@ -22,9 +22,7 @@ class Vector3; // VTABLE: LEGO1 0x100d7da8 // SIZE 0x40 -struct LegoPathCtrlEdge : public LegoUnknown100db7f4 { - inline MxU32 FUN_10048c40(const Vector3& p_position); -}; +struct LegoPathCtrlEdge : public LegoUnknown100db7f4 {}; struct LegoPathCtrlEdgeCompare { MxU32 operator()(const LegoPathCtrlEdge* p_lhs, const LegoPathCtrlEdge* p_rhs) const diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index 306a6e3b..d29ef0fc 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -613,11 +613,105 @@ MxResult Act3Brickster::FUN_100417c0() return SUCCESS; } -// STUB: LEGO1 0x10042300 -// STUB: BETA10 0x1001b017 +// FUNCTION: LEGO1 0x10042300 +// FUNCTION: BETA10 0x1001b017 MxS32 Act3Brickster::FUN_10042300() { - // TODO + // TODO: Has poor inlining, can be fixed by changing the assignment operator in vector.h + // See extended comment in vector.h for operator= + + Act3* a3 = (Act3*) m_world; + + assert(a3 && a3->m_cop1 && a3->m_cop2); + assert(a3->m_cop1->GetROI() && a3->m_cop2->GetROI() && GetROI()); + + Mx3DPointFloat local64[2]; + Mx3DPointFloat local38; + Mx3DPointFloat local18; + + MxS32 local1c = 0; + float local24[2]; + + local64[0] = a3->m_cop1->GetROI()->GetLocal2World()[3]; + local64[1] = a3->m_cop2->GetROI()->GetLocal2World()[3]; + local38 = GetROI()->GetLocal2World()[3]; + + local18 = local64[0]; + local18 -= local38; + local24[0] = local18.LenSquared(); + + local18 = local64[1]; + local18 -= local38; + local24[1] = local18.LenSquared(); + + if (local24[1] < local24[0]) { + local1c = 1; + } + + if (local24[local1c] < 225.0f) { + m_unk0x38 = 8; + + if (m_grec != NULL) { + delete m_grec; + m_grec = NULL; + } + + if (m_pInfo != NULL) { + m_pInfo = NULL; + } + + assert(m_boundary && m_destEdge && m_roi); + + LegoPathBoundary* boundaries[2]; + LegoUnknown100db7f4* maxE = NULL; + boundaries[0] = m_boundary; + + if (m_destEdge->FUN_10048c40(local38)) { + boundaries[1] = (LegoPathBoundary*) m_destEdge->OtherFace(m_boundary); + } + else { + boundaries[1] = NULL; + } + + float local78, local98; + for (MxS32 i = 0; i < (MxS32) sizeOfArray(boundaries); i++) { + if (boundaries[i] != NULL) { + for (MxS32 j = 0; j < boundaries[i]->GetNumEdges(); j++) { + LegoUnknown100db7f4* e = boundaries[i]->GetEdges()[j]; + + if (e->GetMask0x03()) { + Mx3DPointFloat local94(*e->GetPointA()); + local94 += *e->GetPointB(); + local94 /= 2.0f; + + local18 = local94; + local18 -= local64[local1c]; + local98 = local18.LenSquared(); + + local94 -= local38; + local18 = local64[local1c]; + local18 -= local38; + + if (maxE == NULL || (local18.Dot(&local94, &local18) < 0.0f && local78 < local98)) { + maxE = e; + m_boundary = boundaries[i]; + local78 = local98; + } + } + } + } + } + + assert(maxE); + m_destEdge = maxE; + + if (m_boundary != boundaries[0]) { + m_unk0xe4 = 1.0 - m_unk0xe4; + } + + VTable0x9c(); + } + return -1; } diff --git a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp index b17f1508..887d19f7 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp @@ -920,68 +920,6 @@ MxResult LegoPathController::FUN_10048310( return FAILURE; } -// FUNCTION: LEGO1 0x10048c40 -// FUNCTION: BETA10 0x1001cc90 -inline MxU32 LegoPathCtrlEdge::FUN_10048c40(const Vector3& p_position) -{ - MxFloat localc, local10; - MxU32 result = FALSE; - - if (m_unk0x28[0] > 0.001 || m_unk0x28[0] < -0.001) { - localc = (p_position[0] - (*m_pointA)[0]) / m_unk0x28[0]; - - if (localc < 0 || localc > 1) { - return FALSE; - } - - result = TRUE; - } - else { - if (p_position[0] > (*m_pointA)[0] + 0.001 || p_position[0] < (*m_pointA)[0] - 0.001) { - return FALSE; - } - } - - if (m_unk0x28[1] > 0.001 || m_unk0x28[1] < -0.001) { - local10 = (p_position[1] - (*m_pointA)[1]) / m_unk0x28[1]; - - if (result) { - if (localc > local10 + 0.001 || localc < local10 - 0.001) { - return FALSE; - } - } - else { - result = TRUE; - localc = local10; - } - } - else { - if (p_position[1] > (*m_pointA)[1] + 0.001 || p_position[1] < (*m_pointA)[1] - 0.001) { - return FALSE; - } - } - - if (m_unk0x28[2] > 0.001 || m_unk0x28[2] < -0.001) { - local10 = (p_position[2] - (*m_pointA)[2]) / m_unk0x28[2]; - - if (result) { - if (localc > local10 + 0.001 || localc < local10 - 0.001) { - return FALSE; - } - } - else { - return TRUE; - } - } - else { - if (p_position[2] > (*m_pointA)[2] + 0.001 || p_position[2] < (*m_pointA)[2] - 0.001) { - return FALSE; - } - } - - return TRUE; -} - // FUNCTION: LEGO1 0x1004a240 // FUNCTION: BETA10 0x100b9160 MxS32 LegoPathController::FUN_1004a240( diff --git a/LEGO1/lego/sources/geom/legoedge.h b/LEGO1/lego/sources/geom/legoedge.h index 753d6e11..43740bda 100644 --- a/LEGO1/lego/sources/geom/legoedge.h +++ b/LEGO1/lego/sources/geom/legoedge.h @@ -19,6 +19,12 @@ struct LegoEdge { LegoResult FUN_1002ddc0(LegoWEEdge& p_face, Vector3& p_point); + // FUNCTION: BETA10 0x1001cb80 + Vector3* GetPointA() { return m_pointA; } + + // FUNCTION: BETA10 0x1001cbb0 + Vector3* GetPointB() { return m_pointB; } + // SYNTHETIC: LEGO1 0x1009a4a0 // LegoEdge::`scalar deleting destructor' diff --git a/LEGO1/lego/sources/geom/legounkown100db7f4.h b/LEGO1/lego/sources/geom/legounkown100db7f4.h index bd19ee78..ef525932 100644 --- a/LEGO1/lego/sources/geom/legounkown100db7f4.h +++ b/LEGO1/lego/sources/geom/legounkown100db7f4.h @@ -93,6 +93,8 @@ struct LegoUnknown100db7f4 : public LegoEdge { // FUNCTION: BETA10 0x1001cc60 LegoU32 GetMask0x03() { return m_flags & (c_bit1 | c_bit2); } + inline LegoU32 FUN_10048c40(const Vector3& p_position); + // SYNTHETIC: LEGO1 0x1009a6c0 // LegoUnknown100db7f4::`scalar deleting destructor' @@ -101,4 +103,66 @@ struct LegoUnknown100db7f4 : public LegoEdge { float m_unk0x3c; // 0x3c }; +// FUNCTION: LEGO1 0x10048c40 +// FUNCTION: BETA10 0x1001cc90 +inline LegoU32 LegoUnknown100db7f4::FUN_10048c40(const Vector3& p_position) +{ + LegoFloat localc, local10; + LegoU32 result = FALSE; + + if (m_unk0x28[0] > 0.001 || m_unk0x28[0] < -0.001) { + localc = (p_position[0] - (*m_pointA)[0]) / m_unk0x28[0]; + + if (localc < 0 || localc > 1) { + return FALSE; + } + + result = TRUE; + } + else { + if (p_position[0] > (*m_pointA)[0] + 0.001 || p_position[0] < (*m_pointA)[0] - 0.001) { + return FALSE; + } + } + + if (m_unk0x28[1] > 0.001 || m_unk0x28[1] < -0.001) { + local10 = (p_position[1] - (*m_pointA)[1]) / m_unk0x28[1]; + + if (result) { + if (localc > local10 + 0.001 || localc < local10 - 0.001) { + return FALSE; + } + } + else { + result = TRUE; + localc = local10; + } + } + else { + if (p_position[1] > (*m_pointA)[1] + 0.001 || p_position[1] < (*m_pointA)[1] - 0.001) { + return FALSE; + } + } + + if (m_unk0x28[2] > 0.001 || m_unk0x28[2] < -0.001) { + local10 = (p_position[2] - (*m_pointA)[2]) / m_unk0x28[2]; + + if (result) { + if (localc > local10 + 0.001 || localc < local10 - 0.001) { + return FALSE; + } + } + else { + return TRUE; + } + } + else { + if (p_position[2] > (*m_pointA)[2] + 0.001 || p_position[2] < (*m_pointA)[2] - 0.001) { + return FALSE; + } + } + + return TRUE; +} + #endif // __LEGOUNKNOWN100DB7F4_H diff --git a/LEGO1/mxgeometry/mxgeometry3d.h b/LEGO1/mxgeometry/mxgeometry3d.h index 1cfa82ac..99a44fd3 100644 --- a/LEGO1/mxgeometry/mxgeometry3d.h +++ b/LEGO1/mxgeometry/mxgeometry3d.h @@ -33,6 +33,9 @@ class Mx3DPointFloat : public Vector3 { // FUNCTION: LEGO1 0x10003c10 virtual void operator=(const Vector3& p_impl) { EqualsImpl(p_impl.m_data); } // vtable+0x88 + // FUNCTION: BETA10 0x10015240 + // ??4Mx3DPointFloat@@QAEAAV0@ABV0@@Z + // FUNCTION: BETA10 0x10013460 float& operator[](int idx) { return m_data[idx]; } diff --git a/LEGO1/realtime/vector.h b/LEGO1/realtime/vector.h index 02b8d53b..f609c7af 100644 --- a/LEGO1/realtime/vector.h +++ b/LEGO1/realtime/vector.h @@ -151,8 +151,25 @@ class Vector2 { virtual void SetVector(float* p_other) { EqualsImpl(p_other); } // vtable+0x70 // FUNCTION: LEGO1 0x10002260 + // FUNCTION: BETA10 0x100110c0 virtual void SetVector(const Vector2* p_other) { EqualsImpl(p_other->m_data); } // vtable+0x6c + // Note: it's unclear whether Vector3::operator= has been defined explicitly + // with the same function body as Vector2& operator=. The BETA indicates that; + // however, it makes LEGO1 0x10010be0 disappear and worsens matches in + // at least these functions: + // LEGO1 0x100109b0 + // LEGO1 0x10023130 + // LEGO1 0x1002de10 + // LEGO1 0x10050a80 + // LEGO1 0x10053980 + // LEGO1 0x100648f0 + // LEGO1 0x10064b50 + // LEGO1 0x10084030 + // LEGO1 0x100a9410 + // However, defining it as in the BETA improves at least these functions: + // LEGO1 0x10042300 + // SYNTHETIC: LEGO1 0x10010be0 // SYNTHETIC: BETA10 0x100121e0 // Vector3::operator= From 18fc084a3f4320e47d7ef41b620dc32d4ee5d19c Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 17 Dec 2024 17:10:42 -0700 Subject: [PATCH 2/4] Match `LegoGameState::Load` (#1239) --- LEGO1/lego/legoomni/src/common/legogamestate.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index e8835e82..ca462124 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -336,7 +336,7 @@ MxResult LegoGameState::Load(MxULong p_slot) } MxU32 version, status; - MxS16 count, area, act; + MxS16 count, actArea; const char* lightPosition; Read(&fileStorage, &version); @@ -348,8 +348,8 @@ MxResult LegoGameState::Load(MxULong p_slot) Read(&fileStorage, &m_unk0x24); - Read(&fileStorage, &act); - SetCurrentAct((Act) act); + Read(&fileStorage, &actArea); + SetCurrentAct((Act) actArea); Read(&fileStorage, &m_actorId); if (m_actorId) { @@ -406,13 +406,13 @@ MxResult LegoGameState::Load(MxULong p_slot) } } - Read(&fileStorage, &area); + Read(&fileStorage, &actArea); if (m_currentAct == 0) { m_unk0x42c = e_undefined; } else { - m_unk0x42c = (Area) area; + m_unk0x42c = (Area) actArea; } result = SUCCESS; From cb38cf767312306e2b8fcc4a5fbba555667c71c7 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Thu, 19 Dec 2024 12:22:34 -0700 Subject: [PATCH 3/4] Implement/match `Act3Brickster::FUN_100417c0` (#1240) * Implement/match `Act3Brickster::FUN_100417c0` * Move function * Rename var * Revert "Rename var" This reverts commit c9ca75ae7f1d894f976ce6d383d5b4d13ead99a5. --- LEGO1/lego/legoomni/include/act3.h | 1 + LEGO1/lego/legoomni/include/act3actors.h | 6 +- LEGO1/lego/legoomni/include/act3ammo.h | 12 +- LEGO1/lego/legoomni/include/helicopter.h | 1 + LEGO1/lego/legoomni/include/legopathactor.h | 1 + LEGO1/lego/legoomni/src/actors/act3actors.cpp | 248 ++++++++++++++++-- LEGO1/lego/legoomni/src/actors/act3ammo.cpp | 2 +- LEGO1/lego/legoomni/src/actors/helicopter.cpp | 9 + LEGO1/lego/legoomni/src/worlds/act3.cpp | 23 ++ 9 files changed, 277 insertions(+), 26 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index 8f29f41a..44c220db 100644 --- a/LEGO1/lego/legoomni/include/act3.h +++ b/LEGO1/lego/legoomni/include/act3.h @@ -130,6 +130,7 @@ class Act3 : public LegoWorld { void FUN_10073400(); void FUN_10073430(); void GoodEnding(const Matrix4& p_destination); + void BadEnding(const Matrix4& p_destination); void FUN_10073a60(); // BETA indicates that the following classes access certain members directly. diff --git a/LEGO1/lego/legoomni/include/act3actors.h b/LEGO1/lego/legoomni/include/act3actors.h index 2970e45c..e1a44ea3 100644 --- a/LEGO1/lego/legoomni/include/act3actors.h +++ b/LEGO1/lego/legoomni/include/act3actors.h @@ -153,7 +153,7 @@ class Act3Shark : public LegoAnimActor { void Animate(float p_time) override; // vtable+0x70 // LegoAnimActor vtable - virtual MxResult FUN_10042ce0(Act3Ammo* p_ammo); // vtable+0x10 + virtual MxResult EatPizza(Act3Ammo* p_ammo); // vtable+0x10 MxFloat GetUnknown0x2c() { return m_unk0x2c; } @@ -163,8 +163,8 @@ class Act3Shark : public LegoAnimActor { // Act3Shark::`scalar deleting destructor' private: - list m_unk0x1c; // 0x1c - Act3Ammo* m_unk0x28; // 0x28 + list m_eatPizzas; // 0x1c + Act3Ammo* m_nextPizza; // 0x28 MxFloat m_unk0x2c; // 0x2c LegoWorld* m_world; // 0x30 LegoAnimActorStruct* m_unk0x34; // 0x34 diff --git a/LEGO1/lego/legoomni/include/act3ammo.h b/LEGO1/lego/legoomni/include/act3ammo.h index 8beac5be..28de0263 100644 --- a/LEGO1/lego/legoomni/include/act3ammo.h +++ b/LEGO1/lego/legoomni/include/act3ammo.h @@ -15,7 +15,7 @@ class Act3Ammo : public LegoPathActor { c_donut = 0x02, c_valid = 0x04, c_bit4 = 0x08, - c_bit5 = 0x10 + c_sharkFood = 0x10 }; Act3Ammo(); @@ -64,17 +64,17 @@ class Act3Ammo : public LegoPathActor { // FUNCTION: BETA10 0x10021d90 MxU32 IsBit4() { return m_ammoFlag & c_bit4; } - void SetBit5(MxBool p_bit5) + void SetSharkFood(MxBool p_sharkFood) { - if (p_bit5) { - m_ammoFlag |= c_bit5; + if (p_sharkFood) { + m_ammoFlag |= c_sharkFood; } else { - m_ammoFlag &= ~c_bit5; + m_ammoFlag &= ~c_sharkFood; } } - MxU32 IsBit5() { return m_ammoFlag & c_bit5; } + MxU32 IsSharkFood() { return m_ammoFlag & c_sharkFood; } MxFloat GetUnknown0x158() { return m_unk0x158; } diff --git a/LEGO1/lego/legoomni/include/helicopter.h b/LEGO1/lego/legoomni/include/helicopter.h index 4c9b1c0e..b5738be7 100644 --- a/LEGO1/lego/legoomni/include/helicopter.h +++ b/LEGO1/lego/legoomni/include/helicopter.h @@ -77,6 +77,7 @@ class Helicopter : public IslePathActor { void CreateState(); void FUN_10004640(const Matrix4& p_matrix); + void FUN_10004670(const Matrix4& p_matrix); // SYNTHETIC: LEGO1 0x10003210 // Helicopter::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index cf6dba15..e9ef2af2 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -137,6 +137,7 @@ class LegoPathActor : public LegoActor { // FUNCTION: LEGO1 0x10002de0 virtual void VTable0xc8(MxU8 p_unk0x148) { m_unk0x148 = p_unk0x148; } // vtable+0xc8 + // FUNCTION: BETA10 0x1001ca40 LegoPathBoundary* GetBoundary() { return m_boundary; } // FUNCTION: BETA10 0x1001c860 diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index d29ef0fc..b05830b9 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -579,7 +579,7 @@ MxResult Act3Brickster::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(m_world); - if (a3->m_pizzas[index].IsValid() && !a3->m_pizzas[index].IsBit5()) { + if (a3->m_pizzas[index].IsValid() && !a3->m_pizzas[index].IsSharkFood()) { a3->EatPizza(index); } @@ -605,11 +605,227 @@ MxResult Act3Brickster::FUN_100417a0(Act3Ammo& p_ammo, const Vector3&) return SUCCESS; } -// STUB: LEGO1 0x100417c0 -// STUB: BETA10 0x1001a407 +// FUNCTION: LEGO1 0x100417c0 +// FUNCTION: BETA10 0x1001a407 MxResult Act3Brickster::FUN_100417c0() { - // TODO + m_pInfo = NULL; + m_bInfo = NULL; + m_unk0x38 = 0; + LegoPathEdgeContainer* grec = NULL; + Act3* a3 = (Act3*) m_world; + + MxMatrix local70(m_unk0xec); + Vector3 local28(local70[3]); + Vector3 local20(local70[2]); + + if (m_unk0x58 < 8 && m_unk0x24 + 5000.0f < m_lastTime) { + float local18; + + for (MxS32 i = 0; i < MAX_PIZZAS; i++) { + Act3Ammo* pizza = &a3->m_pizzas[i]; + assert(pizza); + + if (pizza->IsValid() && !pizza->IsSharkFood() && pizza->GetActorState() == c_initial) { + LegoROI* proi = pizza->GetROI(); + assert(proi); + + MxMatrix locald0 = proi->GetLocal2World(); + Vector3 local88(locald0[3]); + Mx3DPointFloat localec(local88); + localec -= local28; + + if (localec.LenSquared() > 1600.0f) { + ((Act3*) m_world)->m_shark->EatPizza(pizza); + } + else { + LegoPathEdgeContainer* r2 = new LegoPathEdgeContainer(); + assert(r2); + + MxFloat locald8; + LegoPathEdgeContainer *local16c, *local168, *local174, *local170; // unused + + if (m_pathController->FUN_10048310( + r2, + local28, + local20, + m_boundary, + local88, + localec, + pizza->GetBoundary(), + LegoUnknown100db7f4::c_bit1, + &locald8 + ) == SUCCESS && + (grec == NULL || locald8 < local18)) { + if (grec != NULL) { + local168 = local16c = grec; + delete grec; + } + + grec = r2; + local18 = locald8; + } + + if (grec != r2) { + local170 = local174 = r2; + delete r2; + } + } + } + } + } + + if (grec == NULL) { + MxS32 length = 0; + LegoPlantInfo* pInfo = PlantManager()->GetInfoArray(length); + Mx3DPointFloat local108; + Mx3DPointFloat local138; + MxS32 local120 = -1; + MxU32 local110 = FALSE; + LegoPathBoundary* localf4 = NULL; + LegoBuildingInfo* bInfo = BuildingManager()->GetInfoArray(length); + float local124; + + for (MxS32 i = 0; i < length; i++) { + if (bInfo[i].m_unk0x11 < 0 && bInfo[i].m_boundary != NULL && bInfo[i].m_entity != NULL && i != 0 && + (local120 == -1 || i != 15)) { + Mx3DPointFloat local188(bInfo[i].m_x, bInfo[i].m_y, bInfo[i].m_z); + + local138 = local188; + local138 -= local28; + float length = local138.LenSquared(); + + if (local120 < 0 || length < local124) { + local110 = TRUE; + local120 = i; + local124 = length; + } + } + } + + if (local120 != -1) { + if (local110) { + m_bInfo = &bInfo[local120]; + localf4 = m_bInfo->m_boundary; + Mx3DPointFloat local19c(m_bInfo->m_x, m_bInfo->m_y, m_bInfo->m_z); + local108 = local19c; + } + else { + m_pInfo = &pInfo[local120]; + localf4 = m_pInfo->m_boundary; + Mx3DPointFloat local1b0(m_pInfo->m_x, m_pInfo->m_y, m_pInfo->m_z); + local108 = local1b0; + } + } + + if (localf4 != NULL) { + assert(m_pInfo || m_bInfo); + + grec = new LegoPathEdgeContainer(); + local138 = local108; + local138 -= local28; + local138.Unitize(); + + MxFloat local13c; + LegoPathEdgeContainer *local1c0, *local1bc; // unused + + if (m_pathController->FUN_10048310( + grec, + local28, + local20, + m_boundary, + local108, + local138, + localf4, + LegoUnknown100db7f4::c_bit1, + &local13c + ) != SUCCESS) { + local1bc = local1c0 = grec; + + if (grec != NULL) { + delete grec; + } + + grec = NULL; + assert(0); + } + } + else { + ((Act3*) m_world)->BadEnding(m_roi->GetLocal2World()); + return SUCCESS; + } + } + + if (grec != NULL) { + Mx3DPointFloat local150; + + LegoPathEdgeContainer *local1c4, *local1c8; // unused + if (m_grec != NULL) { + local1c4 = local1c8 = m_grec; + delete m_grec; + } + + m_grec = grec; + Mx3DPointFloat vecUnk; + + if (m_grec->size() == 0) { + vecUnk = m_grec->m_position; + m_boundary = m_grec->m_boundary; + + m_grec->m_direction = m_unk0xec[3]; + m_grec->m_direction -= vecUnk; + + local150 = m_grec->m_direction; + } + else { + LegoEdge* edge = m_grec->back().m_edge; + + Vector3* v1 = edge->CWVertex(*m_grec->m_boundary); + Vector3* v2 = edge->CCWVertex(*m_grec->m_boundary); + assert(v1 && v2); + + local150 = *v2; + local150 -= *v1; + local150 *= m_unk0xe4; + local150 += *v1; + local150 *= -1.0f; + local150 += m_grec->m_position; + local150.Unitize(); + m_grec->m_direction = local150; + + edge = m_grec->front().m_edge; + LegoPathBoundary* boundary = m_grec->front().m_boundary; + + v1 = edge->CWVertex(*boundary); + v2 = edge->CCWVertex(*boundary); + + vecUnk = *v2; + vecUnk -= *v1; + vecUnk *= m_unk0xe4; + vecUnk += *v1; + } + + Vector3 v1(m_unk0xec[0]); + Vector3 v2(m_unk0xec[1]); + Vector3 v3(m_unk0xec[2]); + + v3 = m_unk0xec[3]; + v3 -= vecUnk; + v3.Unitize(); + v1.EqualsCross(&v2, &v3); + v1.Unitize(); + v2.EqualsCross(&v3, &v1); + + VTable0x9c(); + + if (m_pInfo != NULL) { + m_unk0x38 = 5; + } + else if (m_bInfo != NULL) { + m_unk0x38 = 6; + } + } + return SUCCESS; } @@ -742,14 +958,14 @@ MxResult Act3Brickster::VTable0x9c() Act3Shark::Act3Shark() { m_unk0x2c = 0.0f; - m_unk0x28 = NULL; + m_nextPizza = NULL; } // FUNCTION: LEGO1 0x10042ce0 -MxResult Act3Shark::FUN_10042ce0(Act3Ammo* p_ammo) +MxResult Act3Shark::EatPizza(Act3Ammo* p_ammo) { - p_ammo->SetBit5(TRUE); - m_unk0x1c.push_back(p_ammo); + p_ammo->SetSharkFood(TRUE); + m_eatPizzas.push_back(p_ammo); return SUCCESS; } @@ -758,18 +974,18 @@ void Act3Shark::Animate(float p_time) { LegoROI** roiMap = m_unk0x34->GetROIMap(); - if (m_unk0x28 == NULL) { - if (m_unk0x1c.size() > 0) { - m_unk0x28 = m_unk0x1c.front(); - m_unk0x1c.pop_front(); + if (m_nextPizza == NULL) { + if (m_eatPizzas.size() > 0) { + m_nextPizza = m_eatPizzas.front(); + m_eatPizzas.pop_front(); m_unk0x2c = p_time; - roiMap[1] = m_unk0x28->GetROI(); + roiMap[1] = m_nextPizza->GetROI(); m_unk0x3c = roiMap[1]->GetLocal2World()[3]; roiMap[1]->SetVisibility(TRUE); roiMap[2]->SetVisibility(TRUE); } - if (m_unk0x28 == NULL) { + if (m_nextPizza == NULL) { return; } } @@ -798,8 +1014,8 @@ void Act3Shark::Animate(float p_time) } else { roiMap[1] = m_unk0x38; - ((Act3*) m_world)->RemovePizza(*m_unk0x28); - m_unk0x28 = NULL; + ((Act3*) m_world)->RemovePizza(*m_nextPizza); + m_nextPizza = NULL; roiMap[1]->SetVisibility(FALSE); roiMap[2]->SetVisibility(FALSE); } diff --git a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp index 97587e87..ed98b7c6 100644 --- a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp @@ -419,7 +419,7 @@ void Act3Ammo::Animate(float p_time) assert(m_world); - if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsBit5()) { + if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsSharkFood()) { m_world->EatPizza(index); m_world->m_brickster->FUN_100417c0(); } diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index e1d3571b..c8d63a5c 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -439,3 +439,12 @@ void Helicopter::FUN_10004640(const Matrix4& p_matrix) FUN_100042a0(p_matrix); } } + +// FUNCTION: LEGO1 0x10004670 +void Helicopter::FUN_10004670(const Matrix4& p_matrix) +{ + if (m_state->m_unk0x08 != 4 && m_state->m_unk0x08 != 5) { + m_state->m_unk0x08 = 5; + FUN_100042a0(p_matrix); + } +} diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index f4b812da..b3bd9337 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -844,6 +844,29 @@ void Act3::DebugCopter( } } +// FUNCTION: LEGO1 0x100739c0 +// FUNCTION: BETA10 0x10016cc4 +void Act3::BadEnding(const Matrix4& p_destination) +{ + assert(m_cop1 && m_cop2 && m_brickster && m_state); + + m_cop1->SetActorState(LegoPathActor::c_disabled); + m_cop2->SetActorState(LegoPathActor::c_disabled); + m_brickster->SetActorState(LegoPathActor::c_disabled); + + m_unk0x4220.Clear(); + m_copter->FUN_10004670(p_destination); + + DebugPrintf("In Bad Ending..."); + DebugCopter( + m_copter->GetROI()->GetLocal2World(), + p_destination, + m_copter->m_unk0x160, + m_copter->m_unk0x1a8, + m_copter->m_unk0x1f4 + ); +} + // FUNCTION: LEGO1 0x10073a60 void Act3::FUN_10073a60() { From a8729dfef6df542f078bfee053729c800e954d48 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 19 Dec 2024 22:52:33 +0100 Subject: [PATCH 4/4] glD3DRMIMAGE::CreateBuffer, LegoVideoManager::EnableRMDevice and LegoVideoManager::DisableRMDevice (#1241) * Implement TglD3DRMIMAGE::CreateBuffer (ecx/edi are swapped) * Implement LegoVideoManager::EnableRMDevice * Implement LegoVideoManager::DisableRMDevice * clang-format * Match `LegoVideoManager::EnableRMDevice` * Remove padding * Fix naming --------- Co-authored-by: Christian Semmler --- .../lego/legoomni/include/legovideomanager.h | 82 ++++++++------ .../legoomni/src/video/legovideomanager.cpp | 106 +++++++++++++++++- LEGO1/tgl/d3drm/impl.h | 2 + LEGO1/tgl/d3drm/texture.cpp | 40 ++++++- LEGO1/tgl/d3drm/view.cpp | 2 + 5 files changed, 190 insertions(+), 42 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legovideomanager.h b/LEGO1/lego/legoomni/include/legovideomanager.h index 605d0626..e7848c02 100644 --- a/LEGO1/lego/legoomni/include/legovideomanager.h +++ b/LEGO1/lego/legoomni/include/legovideomanager.h @@ -5,12 +5,14 @@ #include "legophonemelist.h" #include "mxvideomanager.h" +#include #include class Lego3DManager; class LegoROI; class MxDirect3D; class MxStopWatch; +struct ViewportAppData; namespace Tgl { @@ -70,40 +72,52 @@ class LegoVideoManager : public MxVideoManager { inline void DrawCursor(); - Tgl::Renderer* m_renderer; // 0x64 - Lego3DManager* m_3dManager; // 0x68 - LegoROI* m_viewROI; // 0x6c - undefined4 m_unk0x70; // 0x70 - MxDirect3D* m_direct3d; // 0x74 - undefined4 m_unk0x78[27]; // 0x78 - MxBool m_render3d; // 0xe4 - MxBool m_unk0xe5; // 0xe5 - MxBool m_unk0xe6; // 0xe6 - PALETTEENTRY m_paletteEntries[256]; // 0xe7 - undefined m_padding0x4e7; // 0x4e7 - LegoPhonemeList* m_phonemeRefList; // 0x4e8 - MxBool m_isFullscreenMovie; // 0x4ec - MxPalette* m_palette; // 0x4f0 - MxStopWatch* m_stopWatch; // 0x4f4 - double m_elapsedSeconds; // 0x4f8 - MxBool m_fullScreenMovie; // 0x500 - MxBool m_drawCursor; // 0x501 - MxS32 m_cursorXCopy; // 0x504 - MxS32 m_cursorYCopy; // 0x508 - MxS32 m_cursorX; // 0x50c - MxS32 m_cursorY; // 0x510 - LPDIRECTDRAWSURFACE m_cursorSurface; // 0x514 - RECT m_cursorRect; // 0x518 - LPDIRECTDRAWSURFACE m_unk0x528; // 0x528 - MxBool m_drawFPS; // 0x52c - RECT m_fpsRect; // 0x530 - HFONT m_arialFont; // 0x540 - SIZE m_fpsSize; // 0x544 - MxFloat m_unk0x54c; // 0x54c - MxFloat m_unk0x550; // 0x550 - MxBool m_unk0x554; // 0x554 - MxBool m_paused; // 0x555 - undefined m_pad0x556[0x39]; // 0x556 + Tgl::Renderer* m_renderer; // 0x64 + Lego3DManager* m_3dManager; // 0x68 + LegoROI* m_viewROI; // 0x6c + undefined4 m_unk0x70; // 0x70 + MxDirect3D* m_direct3d; // 0x74 + undefined4 m_unk0x78[27]; // 0x78 + MxBool m_render3d; // 0xe4 + MxBool m_unk0xe5; // 0xe5 + MxBool m_unk0xe6; // 0xe6 + PALETTEENTRY m_paletteEntries[256]; // 0xe7 + LegoPhonemeList* m_phonemeRefList; // 0x4e8 + MxBool m_isFullscreenMovie; // 0x4ec + MxPalette* m_palette; // 0x4f0 + MxStopWatch* m_stopWatch; // 0x4f4 + double m_elapsedSeconds; // 0x4f8 + MxBool m_fullScreenMovie; // 0x500 + MxBool m_drawCursor; // 0x501 + MxS32 m_cursorXCopy; // 0x504 + MxS32 m_cursorYCopy; // 0x508 + MxS32 m_cursorX; // 0x50c + MxS32 m_cursorY; // 0x510 + LPDIRECTDRAWSURFACE m_cursorSurface; // 0x514 + RECT m_cursorRect; // 0x518 + LPDIRECTDRAWSURFACE m_unk0x528; // 0x528 + MxBool m_drawFPS; // 0x52c + RECT m_fpsRect; // 0x530 + HFONT m_arialFont; // 0x540 + SIZE m_fpsSize; // 0x544 + MxFloat m_unk0x54c; // 0x54c + MxFloat m_unk0x550; // 0x550 + MxBool m_unk0x554; // 0x554 + MxBool m_paused; // 0x555 + D3DVALUE m_back; // 0x558 + D3DVALUE m_front; // 0x55c + float m_cameraWidth; // 0x560 + float m_cameraHeight; // 0x564 + D3DVALUE m_fov; // 0x55c + IDirect3DRMFrame* m_camera; // 0x56c + D3DRMPROJECTIONTYPE m_projection; // 0x570 + ViewportAppData* m_appdata; // 0x574 + D3DRMRENDERQUALITY m_quality; // 0x578 + DWORD m_shades; // 0x57c + D3DRMTEXTUREQUALITY m_textureQuality; // 0x580 + DWORD m_rendermode; // 0x584 + BOOL m_dither; // 0x588 + DWORD m_bufferCount; // 0x58c }; // SYNTHETIC: LEGO1 0x1007ab20 diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 70fae9aa..7c5a2cbb 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -561,18 +561,112 @@ void LegoVideoManager::FUN_1007c520() InputManager()->SetUnknown335(TRUE); } -// STUB: LEGO1 0x1007c560 +extern void ViewportDestroyCallback(IDirect3DRMObject*, void*); + +// FUNCTION: LEGO1 0x1007c560 int LegoVideoManager::EnableRMDevice() { - // TODO - return 0; + IDirect3DRMViewport* viewport; + + if (!m_paused) { + return -1; + } + + TglImpl::DeviceImpl* deviceImpl = (TglImpl::DeviceImpl*) m_3dManager->GetLego3DView()->GetDevice(); + IDirect3DRMDevice2* d3drmDev2 = NULL; + IDirect3D2* d3d2 = m_direct3d->Direct3D(); + IDirect3DDevice2* d3dDev2 = m_direct3d->Direct3DDevice(); + + int result = -1; + IDirect3DRM2* d3drm2 = ((TglImpl::RendererImpl*) m_renderer)->ImplementationData(); + + m_direct3d->RestoreSurfaces(); + + if (d3drm2->CreateDeviceFromD3D(d3d2, d3dDev2, &d3drmDev2) == D3DRM_OK) { + viewport = NULL; + deviceImpl->SetImplementationData(d3drmDev2); + + if (d3drm2->CreateViewport(d3drmDev2, m_camera, 0, 0, m_cameraWidth, m_cameraHeight, &viewport) == D3DRM_OK) { + viewport->SetBack(m_back); + viewport->SetFront(m_front); + viewport->SetField(m_fov); + viewport->SetCamera(m_camera); + viewport->SetProjection(m_projection); + viewport->SetAppData((DWORD) m_appdata); + d3drmDev2->SetQuality(m_quality); + d3drmDev2->SetShades(m_shades); + d3drmDev2->SetTextureQuality(m_textureQuality); + d3drmDev2->SetRenderMode(m_rendermode); + d3drmDev2->SetDither(m_dither); + d3drmDev2->SetBufferCount(m_bufferCount); + m_camera->Release(); + + if (viewport->AddDestroyCallback(ViewportDestroyCallback, m_appdata) == D3DRM_OK) { + ((TglImpl::ViewImpl*) m_3dManager->GetLego3DView()->GetView())->SetImplementationData(viewport); + m_paused = 0; + result = 0; + } + } + } + + return result; } -// STUB: LEGO1 0x1007c740 +// FUNCTION: LEGO1 0x1007c740 int LegoVideoManager::DisableRMDevice() { - // TODO - return 0; + if (m_paused) { + return -1; + } + + IDirect3DRMDevice2* d3drmDev2 = + ((TglImpl::DeviceImpl*) m_3dManager->GetLego3DView()->GetDevice())->ImplementationData(); + + if (d3drmDev2 != NULL) { + IDirect3DRMViewportArray* viewportArray = NULL; + + if (d3drmDev2->GetViewports(&viewportArray) == D3DRM_OK && viewportArray != NULL) { + if (viewportArray->GetSize() == 1) { + IDirect3DRMViewport* viewport = NULL; + + if (viewportArray->GetElement(0, &viewport) == D3DRM_OK) { + m_back = viewport->GetBack(); + m_front = viewport->GetFront(); + m_cameraWidth = viewport->GetWidth(); + m_cameraHeight = viewport->GetHeight(); + m_fov = viewport->GetField(); + viewport->GetCamera(&m_camera); + m_projection = viewport->GetProjection(); + m_appdata = (ViewportAppData*) viewport->GetAppData(); + viewportArray->Release(); + viewport->Release(); + viewport->DeleteDestroyCallback(ViewportDestroyCallback, this->m_appdata); + viewport->Release(); + m_paused = 1; + m_direct3d->Direct3D()->AddRef(); + m_direct3d->Direct3DDevice()->AddRef(); + } + else { + viewportArray->Release(); + } + } + } + + m_quality = d3drmDev2->GetQuality(); + m_shades = d3drmDev2->GetShades(); + m_textureQuality = d3drmDev2->GetTextureQuality(); + m_rendermode = d3drmDev2->GetRenderMode(); + m_dither = d3drmDev2->GetDither(); + m_bufferCount = d3drmDev2->GetBufferCount(); + d3drmDev2->Release(); + } + + if (m_paused) { + return 0; + } + else { + return -1; + } } // FUNCTION: LEGO1 0x1007c930 diff --git a/LEGO1/tgl/d3drm/impl.h b/LEGO1/tgl/d3drm/impl.h index 652ecef2..14acce2a 100644 --- a/LEGO1/tgl/d3drm/impl.h +++ b/LEGO1/tgl/d3drm/impl.h @@ -149,6 +149,7 @@ class DeviceImpl : public Device { void InitFromWindowsDevice(Device*) override; IDirect3DRMDevice2* ImplementationData() const { return m_data; } + void SetImplementationData(IDirect3DRMDevice2* device) { m_data = device; } friend class RendererImpl; @@ -199,6 +200,7 @@ class ViewImpl : public View { ) override; IDirect3DRMViewport* ImplementationData() const { return m_data; } + void SetImplementationData(IDirect3DRMViewport* viewport) { m_data = viewport; } static Result ViewportCreateAppData(IDirect3DRM2*, IDirect3DRMViewport*, IDirect3DRMFrame2*); diff --git a/LEGO1/tgl/d3drm/texture.cpp b/LEGO1/tgl/d3drm/texture.cpp index a51a5c0b..d02b8840 100644 --- a/LEGO1/tgl/d3drm/texture.cpp +++ b/LEGO1/tgl/d3drm/texture.cpp @@ -86,10 +86,46 @@ void TglD3DRMIMAGE::Destroy() delete m_image.palette; } -// STUB: LEGO1 0x100a13e0 +inline static int IsPowerOfTwo(int v) +{ + int m = 0; + + while (v > 2 && m == 0) { + m = v % 2; + v /= 2; + } + + return v == 2 && m == 0; +} + +// FUNCTION: LEGO1 0x100a13e0 Result TglD3DRMIMAGE::CreateBuffer(int width, int height, int depth, void* pBuffer, int useBuffer) { - return Error; + if (!(IsPowerOfTwo(width) && IsPowerOfTwo(height) && width % 4 == 0)) { + return Error; + } + + m_image.width = width; + m_image.height = height; + m_image.depth = depth; + m_image.bytes_per_line = width; + + if (!m_texelsAllocatedByClient) { + delete[] m_image.buffer1; + m_image.buffer1 = NULL; + } + + if (useBuffer) { + m_texelsAllocatedByClient = 1; + m_image.buffer1 = (char*) pBuffer; + } + else { + m_image.buffer1 = new char[width * height]; + memcpy(m_image.buffer1, pBuffer, width * height); + m_texelsAllocatedByClient = 0; + } + + return Success; } // FUNCTION: LEGO1 0x100a1510 diff --git a/LEGO1/tgl/d3drm/view.cpp b/LEGO1/tgl/d3drm/view.cpp index b9fca8e9..3c2ea1d9 100644 --- a/LEGO1/tgl/d3drm/view.cpp +++ b/LEGO1/tgl/d3drm/view.cpp @@ -80,6 +80,8 @@ inline Result ViewRestoreFrameAfterRender( return result; } +// FIXME: from LEGO1/tgl/d3drm/view.cpp + // FUNCTION: LEGO1 0x100a1240 void ViewportDestroyCallback(IDirect3DRMObject* pObject, void* pArg) {