From 9c951c49748c8e651bddb7213acca2872a689191 Mon Sep 17 00:00:00 2001 From: MS Date: Tue, 17 Dec 2024 03:07:39 -0500 Subject: [PATCH 01/12] Implement `MxDisplaySurface::DrawTransparentRLE` (#1236) * Implement MxDisplaySurface::DrawTransparentRLE * ncc fix --- LEGO1/omni/include/mxdisplaysurface.h | 8 +- LEGO1/omni/src/video/mxdisplaysurface.cpp | 158 ++++++++++++++++++++-- 2 files changed, 153 insertions(+), 13 deletions(-) diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 2319931d..3c2c83a7 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -99,14 +99,14 @@ class MxDisplaySurface : public MxCore { LPDIRECTDRAWSURFACE GetDirectDrawSurface2() { return m_ddSurface2; } MxVideoParam& GetVideoParam() { return m_videoParam; } - void FUN_100bb500( - MxU8** p_bitmapData, - MxU8** p_surfaceData, + void DrawTransparentRLE( + MxU8*& p_bitmapData, + MxU8*& p_surfaceData, MxU32 p_bitmapSize, MxS32 p_width, MxS32 p_height, MxLong p_pitch, - MxU32 p_bpp + MxU8 p_bpp ); private: diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index de78aadb..3a301af1 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -529,7 +529,7 @@ void MxDisplaySurface::VTable0x30( MxU8* surface = (MxU8*) ddsd.lpSurface + p_right + (p_bottom * ddsd.lPitch); if (p_und) { MxS32 size = p_bitmap->GetBmiHeader()->biSizeImage; - FUN_100bb500(&data, &surface, size, p_width, p_height, ddsd.lPitch, 8); + DrawTransparentRLE(data, surface, size, p_width, p_height, ddsd.lPitch, 8); } else { MxLong stride = -p_width + GetAdjustedStride(p_bitmap); @@ -555,7 +555,7 @@ void MxDisplaySurface::VTable0x30( MxU8* surface = (MxU8*) ddsd.lpSurface + (2 * p_right) + (p_bottom * ddsd.lPitch); if (p_und) { MxS32 size = p_bitmap->GetBmiHeader()->biSizeImage; - FUN_100bb500(&data, &surface, size, p_width, p_height, ddsd.lPitch, 16); + DrawTransparentRLE(data, surface, size, p_width, p_height, ddsd.lPitch, 16); } else { MxLong stride = -p_width + GetAdjustedStride(p_bitmap); @@ -584,19 +584,159 @@ void MxDisplaySurface::VTable0x30( m_ddSurface2->Unlock(ddsd.lpSurface); } -// STUB: LEGO1 0x100bb500 -// STUB: BETA10 0x10140cd6 -void MxDisplaySurface::FUN_100bb500( - MxU8** p_bitmapData, - MxU8** p_surfaceData, +// FUNCTION: LEGO1 0x100bb500 +// FUNCTION: BETA10 0x10140cd6 +void MxDisplaySurface::DrawTransparentRLE( + MxU8*& p_bitmapData, + MxU8*& p_surfaceData, MxU32 p_bitmapSize, MxS32 p_width, MxS32 p_height, MxLong p_pitch, - MxU32 p_bpp + MxU8 p_bpp ) { - // TODO + /* Assumes partial RLE for the bitmap: only the skipped pixels are compressed. + The drawn pixels are uncompressed. The procedure is: + 1. Read 3 bytes from p_bitmapData. Skip this many pixels on the surface. + 2. Read 3 bytes from p_bitmapData. Draw this many pixels on the surface. + 3. Repeat until the end of p_bitmapData is reached. */ + + MxU8* end = p_bitmapData + p_bitmapSize; + MxU8* surfCopy = p_surfaceData; // unused? + + // The total number of pixels drawn or skipped + MxU32 count = 0; + + // Used in both 8 and 16 bit branches + MxU32 skipCount; + MxU32 drawCount; + MxU32 t; + + if (p_bpp == 16) { + // DECOMP: why goto? + goto sixteen_bit; + } + + while (p_bitmapData < end) { + skipCount = *p_bitmapData++; + t = *p_bitmapData++; + skipCount += t << 8; + t = *p_bitmapData++; + skipCount += t << 16; + + MxS32 rowRemainder = p_width - count % p_width; + count += skipCount; + + if (skipCount >= rowRemainder) { + p_surfaceData += rowRemainder; // skip the rest of this row + skipCount -= rowRemainder; + p_surfaceData += p_pitch - p_width; // seek to start of next row + p_surfaceData += p_pitch * (skipCount / p_width); // skip entire rows if any + } + + // skip any pixels at the start of this row + p_surfaceData += skipCount % p_width; + if (p_bitmapData >= end) { + break; + } + + drawCount = *p_bitmapData++; + t = *p_bitmapData++; + drawCount += t << 8; + t = *p_bitmapData++; + drawCount += t << 16; + + rowRemainder = p_width - count % p_width; + count += drawCount; + + if (drawCount >= rowRemainder) { + memcpy(p_surfaceData, p_bitmapData, rowRemainder); + p_surfaceData += rowRemainder; + p_bitmapData += rowRemainder; + + drawCount -= rowRemainder; + + // seek to start of bitmap on this screen row + p_surfaceData += p_pitch - p_width; + MxS32 rows = drawCount / p_width; + + for (MxU32 i = 0; i < rows; i++) { + memcpy(p_surfaceData, p_bitmapData, p_width); + p_bitmapData += p_width; + p_surfaceData += p_pitch; + } + } + + MxS32 tail = drawCount % p_width; + memcpy(p_surfaceData, p_bitmapData, tail); + p_surfaceData += tail; + p_bitmapData += tail; + } + return; + +sixteen_bit: + while (p_bitmapData < end) { + skipCount = *p_bitmapData++; + t = *p_bitmapData++; + skipCount += t << 8; + t = *p_bitmapData++; + skipCount += t << 16; + + MxS32 rowRemainder = p_width - count % p_width; + count += skipCount; + + if (skipCount >= rowRemainder) { + p_surfaceData += 2 * rowRemainder; + skipCount -= rowRemainder; + p_surfaceData += p_pitch - 2 * p_width; + p_surfaceData += p_pitch * (skipCount / p_width); + } + + p_surfaceData += 2 * (skipCount % p_width); + if (p_bitmapData >= end) { + break; + } + + drawCount = *p_bitmapData++; + t = *p_bitmapData++; + drawCount += t << 8; + t = *p_bitmapData++; + drawCount += t << 16; + + rowRemainder = p_width - count % p_width; + count += drawCount; + + if (drawCount >= rowRemainder) { + // memcpy + for (MxU32 j = 0; j < rowRemainder; j++) { + *((MxU16*) p_surfaceData) = m_16bitPal[*p_bitmapData++]; + p_surfaceData += 2; + } + + drawCount -= rowRemainder; + + p_surfaceData += p_pitch - 2 * p_width; + MxS32 rows = drawCount / p_width; + + for (MxU32 i = 0; i < rows; i++) { + // memcpy + for (MxS32 j = 0; j < p_width; j++) { + *((MxU16*) p_surfaceData) = m_16bitPal[*p_bitmapData++]; + p_surfaceData += 2; + } + + p_surfaceData += p_pitch - 2 * p_width; + } + } + + MxS32 tail = drawCount % p_width; + // memcpy + for (MxS32 j = 0; j < tail; j++) { + *((MxU16*) p_surfaceData) = m_16bitPal[*p_bitmapData++]; + p_surfaceData += 2; + } + } } // STUB: LEGO1 0x100bb850 From 66e3c9a2e1e87264cb65c4247fc253c035a5ef5b Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 17 Dec 2024 11:11:47 -0700 Subject: [PATCH 02/12] Implement/match `Act3Brickster::Animate` (#1237) * Implement/match `Act3Brickster::Animate` * Improve loop --- LEGO1/lego/legoomni/include/act3.h | 1 + LEGO1/lego/legoomni/include/act3actors.h | 12 +- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 186 +++++++++++++++++- LEGO1/lego/legoomni/src/worlds/act3.cpp | 7 + 4 files changed, 196 insertions(+), 10 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index da9910d2..8f29f41a 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 FUN_10073a60(); // BETA indicates that the following classes access certain members directly. friend class Act3Ammo; diff --git a/LEGO1/lego/legoomni/include/act3actors.h b/LEGO1/lego/legoomni/include/act3actors.h index 6b80a8f8..2970e45c 100644 --- a/LEGO1/lego/legoomni/include/act3actors.h +++ b/LEGO1/lego/legoomni/include/act3actors.h @@ -6,6 +6,8 @@ // File name verified by multiple assertions, e.g. BETA10 0x10018391 class Act3Ammo; +struct LegoBuildingInfo; +struct LegoPlantInfo; class LegoWorld; // VTABLE: LEGO1 0x100d7668 LegoPathActor @@ -118,17 +120,19 @@ class Act3Brickster : public Act3Actor { // Act3Brickster::`scalar deleting destructor' private: + MxS32 FUN_10042300(); + MxFloat m_unk0x20; // 0x20 MxFloat m_unk0x24; // 0x24 LegoWorld* m_world; // 0x28 - undefined4 m_unk0x2c; // 0x2c - undefined4 m_unk0x30; // 0x30 + LegoPlantInfo* m_pInfo; // 0x2c + LegoBuildingInfo* m_bInfo; // 0x30 LegoAnimActorStruct* m_shootAnim; // 0x34 undefined4 m_unk0x38; // 0x38 Mx3DPointFloat m_unk0x3c; // 0x3c MxFloat m_unk0x50; // 0x50 - undefined4 m_unk0x54; // 0x54 - undefined m_unk0x58; // 0x58 + MxFloat m_unk0x54; // 0x54 + MxU8 m_unk0x58; // 0x58 }; // VTABLE: LEGO1 0x100d7920 LegoPathActor diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index 83fe23ab..306a6e3b 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -4,9 +4,12 @@ #include "act3ammo.h" #include "anim/legoanim.h" #include "define.h" +#include "legobuildingmanager.h" #include "legocachesoundmanager.h" #include "legolocomotionanimpresenter.h" #include "legopathedgecontainer.h" +#include "legoplantmanager.h" +#include "legoplants.h" #include "legosoundmanager.h" #include "misc.h" #include "mxdebug.h" @@ -345,13 +348,13 @@ MxResult Act3Cop::VTable0x9c() Act3Brickster::Act3Brickster() { m_world = NULL; - m_unk0x2c = 0; - m_unk0x30 = 0; + m_pInfo = NULL; + m_bInfo = NULL; m_shootAnim = NULL; m_unk0x38 = 0; m_unk0x20 = 0.0f; m_unk0x24 = 0.0f; - m_unk0x54 = 0; + m_unk0x54 = 0.0f; SetActorState(c_disabled); m_unk0x58 = 0; @@ -385,11 +388,174 @@ void Act3Brickster::ParseAction(char* p_extra) assert(m_shootAnim); } -// STUB: LEGO1 0x10041050 -// STUB: BETA10 0x100197d7 +// FUNCTION: LEGO1 0x10041050 +// FUNCTION: BETA10 0x100197d7 void Act3Brickster::Animate(float p_time) { - // TODO + if (m_lastTime <= m_unk0x20 && m_unk0x20 <= p_time) { + SetWorldSpeed(5.0f); + } + + if (m_unk0x38 != 3 && m_unk0x38 != 4) { + Act3Actor::Animate(p_time); + } + + if (m_unk0x54 < p_time) { + ((Act3*) m_world)->FUN_10072ad0(5); + m_unk0x54 = p_time + 15000.0f; + } + + switch (m_unk0x38) { + case 1: + FUN_100417c0(); + break; + case 2: + m_unk0x58++; + m_unk0x20 = p_time + 2000.0f; + SetWorldSpeed(3.0f); + + assert(SoundManager()->GetCacheSoundManager()); + + if (m_unk0x58 >= 8) { + ((Act3*) m_world)->FUN_10072ad0(6); + } + else { + SoundManager()->GetCacheSoundManager()->Play("eatpz", NULL, FALSE); + } + + FUN_100417c0(); + break; + case 3: + assert(m_shootAnim && m_pInfo); + + if (m_unk0x50 < p_time) { + while (m_pInfo->m_unk0x16) { + PlantManager()->FUN_10026c50(m_pInfo->m_entity); + } + + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("thpt", NULL, FALSE); + m_unk0x58 = 0; + FUN_100417c0(); + } + else { + MxMatrix local70; + local70 = m_unk0xec; + + Vector3 local14(local70[0]); + Vector3 local28(local70[1]); + Vector3 localc(local70[2]); + Vector3 local20(local70[3]); + + localc = local20; + localc -= m_pInfo->m_position; + localc.Unitize(); + local14.EqualsCross(&local28, &localc); + local14.Unitize(); + local28.EqualsCross(&localc, &local14); + + assert(!m_cameraFlag); + + LegoTreeNode* root = m_shootAnim->GetAnimTreePtr()->GetRoot(); + float time = p_time - (m_unk0x50 - m_shootAnim->GetDuration()); + + for (MxS32 i = 0; i < root->GetNumChildren(); i++) { + LegoROI::FUN_100a8e80(root->GetChild(i), local70, time, m_shootAnim->GetROIMap()); + } + } + + m_lastTime = p_time; + break; + case 4: + assert(m_shootAnim && m_bInfo); + + if (m_unk0x50 < p_time) { + ((Act3*) m_world)->FUN_10073a60(); + m_unk0x58 = 0; + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("thpt", NULL, FALSE); + + while (m_bInfo->m_unk0x11 > 0 || m_bInfo->m_unk0x11 == -1) { + if (!BuildingManager()->FUN_10030110(m_bInfo)) { + break; + } + } + + FUN_100417c0(); + } + else { + MxMatrix locale4; + locale4 = m_unk0xec; + + Vector3 local88(locale4[0]); + Vector3 local9c(locale4[1]); + Vector3 local80(locale4[2]); + Vector3 local94(locale4[3]); + + local80 = local94; + assert(m_bInfo->m_entity && m_bInfo->m_entity->GetROI()); + + local80 -= m_unk0x3c; + local80.Unitize(); + local88.EqualsCross(&local9c, &local80); + local88.Unitize(); + local9c.EqualsCross(&local80, &local88); + + assert(!m_cameraFlag); + + LegoTreeNode* root = m_shootAnim->GetAnimTreePtr()->GetRoot(); + float time = p_time - (m_unk0x50 - m_shootAnim->GetDuration()); + + for (MxS32 i = 0; i < root->GetNumChildren(); i++) { + LegoROI::FUN_100a8e80(root->GetChild(i), locale4, time, m_shootAnim->GetROIMap()); + } + } + + m_lastTime = p_time; + break; + case 5: + if (m_grec == NULL) { + assert(m_shootAnim && m_pInfo); + m_unk0x38 = 3; + m_unk0x50 = p_time + m_shootAnim->GetDuration(); + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("xarrow", NULL, FALSE); + } + else { + FUN_10042300(); + } + break; + case 6: + if (m_grec == NULL) { + assert(m_shootAnim && m_bInfo); + m_unk0x38 = 4; + m_unk0x50 = p_time + m_shootAnim->GetDuration(); + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("xarrow", NULL, FALSE); + BuildingManager()->ScheduleAnimation(m_bInfo->m_entity, 0, FALSE, TRUE); + m_unk0x3c = m_bInfo->m_entity->GetROI()->GetLocal2World()[3]; + } + else { + FUN_10042300(); + } + break; + case 7: + default: + FUN_10042300(); + break; + case 8: + m_unk0x24 = p_time + 10000.0f; + m_unk0x38 = 9; + break; + case 9: + if (m_unk0x24 < p_time) { + FUN_100417c0(); + } + else if (m_unk0x24 - 9000.0f < p_time) { + FUN_10042300(); + } + break; + } } // FUNCTION: LEGO1 0x100416b0 @@ -447,6 +613,14 @@ MxResult Act3Brickster::FUN_100417c0() return SUCCESS; } +// STUB: LEGO1 0x10042300 +// STUB: BETA10 0x1001b017 +MxS32 Act3Brickster::FUN_10042300() +{ + // TODO + return -1; +} + // FUNCTION: LEGO1 0x10042990 // FUNCTION: BETA10 0x1001b6e2 void Act3Brickster::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoUnknown100db7f4*& p_edge, float& p_unk0xe4) diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index 170343fd..f4b812da 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -844,6 +844,13 @@ void Act3::DebugCopter( } } +// FUNCTION: LEGO1 0x10073a60 +void Act3::FUN_10073a60() +{ + m_unk0x421e--; + m_helicopterDots[m_unk0x421e]->Enable(FALSE); +} + // FUNCTION: LEGO1 0x10073a90 void Act3::Enable(MxBool p_enable) { From 90c687bde0e9dd82fb4e928445fda8b49403daea Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 17 Dec 2024 15:16:00 -0700 Subject: [PATCH 03/12] 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 04/12] 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 05/12] 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 06/12] 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) { From 7ed2ac9ccc2ca515b869b76f97f5618fbaeb8a46 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Fri, 20 Dec 2024 01:27:14 +0100 Subject: [PATCH 07/12] Progress on `Helicopter::FUN_100042a0` (#1242) * Implement `LegoCameraController::FUN_100123b0` * Improve `UnknownMx4DPointFloat::Unknown7` match, add BETA10 * Add draft for `FUN_100042a0` * Improve match * Match * Use better naming * Remove comments --------- Co-authored-by: jonschz Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/helicopter.h | 3 ++ .../legoomni/include/legocameracontroller.h | 1 + LEGO1/lego/legoomni/src/actors/helicopter.cpp | 45 ++++++++++++++-- .../lego/legoomni/src/build/legocarbuild.cpp | 4 +- .../src/common/legoanimationmanager.cpp | 6 +-- .../src/entity/legocameracontroller.cpp | 14 +++++ LEGO1/lego/sources/anim/legoanim.cpp | 6 +-- LEGO1/mxgeometry/mxgeometry3d.h | 54 ++++++++++--------- reccmp-project.yml | 1 + 9 files changed, 99 insertions(+), 35 deletions(-) diff --git a/LEGO1/lego/legoomni/include/helicopter.h b/LEGO1/lego/legoomni/include/helicopter.h index b5738be7..23285f1e 100644 --- a/LEGO1/lego/legoomni/include/helicopter.h +++ b/LEGO1/lego/legoomni/include/helicopter.h @@ -48,6 +48,7 @@ class HelicopterState : public LegoState { }; // VTABLE: LEGO1 0x100d40f8 +// VTABLE: BETA10 0x101b9880 // SIZE 0x230 class Helicopter : public IslePathActor { public: @@ -55,6 +56,7 @@ class Helicopter : public IslePathActor { ~Helicopter() override; // vtable+0x00 // FUNCTION: LEGO1 0x10003070 + // FUNCTION: BETA10 0x1002b300 const char* ClassName() const override // vtable+0x0c { // STRING: LEGO1 0x100f0130 @@ -62,6 +64,7 @@ class Helicopter : public IslePathActor { } // FUNCTION: LEGO1 0x10003080 + // FUNCTION: BETA10 0x1002b330 MxBool IsA(const char* p_name) const override // vtable+0x10 { return !strcmp(p_name, Helicopter::ClassName()) || IslePathActor::IsA(p_name); diff --git a/LEGO1/lego/legoomni/include/legocameracontroller.h b/LEGO1/lego/legoomni/include/legocameracontroller.h index ec43aa6c..c4a10146 100644 --- a/LEGO1/lego/legoomni/include/legocameracontroller.h +++ b/LEGO1/lego/legoomni/include/legocameracontroller.h @@ -38,6 +38,7 @@ class LegoCameraController : public LegoPointOfViewController { void SetWorldTransform(const Vector3& p_at, const Vector3& p_dir, const Vector3& p_up); void FUN_10012290(float p_angle); void FUN_10012320(float p_angle); + MxResult FUN_100123b0(Matrix4& p_matrix); void FUN_100123e0(const Matrix4& p_transform, MxU32 p_und); Mx3DPointFloat GetWorldUp(); Mx3DPointFloat GetWorldLocation(); diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index c8d63a5c..1d7f78e3 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -14,6 +14,8 @@ #include "legoworld.h" #include "misc.h" #include "mxdebug.h" +#include "mxmisc.h" +#include "mxtimer.h" #include "mxtransitionmanager.h" #include "scripts.h" @@ -405,7 +407,7 @@ void Helicopter::Animate(float p_time) Vector3 v2(m_unk0x1a8[3]); float* loc = m_unk0x1a8[3]; mat.SetIdentity(); - m_unk0x1f4.Unknown6(mat, f2); + m_unk0x1f4.BETA_1004aaa0(mat, f2); v2.SetVector(loc); v2 -= v; v2 *= f2; @@ -425,10 +427,47 @@ void Helicopter::Animate(float p_time) } } -// STUB: LEGO1 0x100042a0 +// FUNCTION: LEGO1 0x100042a0 void Helicopter::FUN_100042a0(const Matrix4& p_matrix) { - // TODO + MxMatrix local48; + MxMatrix local90; + + Vector3 vec1(local48[3]); // local98 // esp+0x30 + Vector3 vec2(local90[3]); // localac // esp+0x1c + Vector3 vec3(m_unk0x1a8[0]); // locala8 // esp+0x20 + Vector3 vec4(m_unk0x1a8[1]); // localb8 // esp+0x10 + Vector3 vec5(m_unk0x1a8[2]); // EDI + Vector3 vec6(m_unk0x1a8[3]); // locala0 // esp+0x28 + + m_world->GetCamera()->FUN_100123b0(local48); + m_unk0x1a8.SetIdentity(); + local90 = p_matrix; + + vec2[1] += 20.0f; + vec4 = vec2; + vec4 -= vec1; + vec4.Unitize(); + + vec5[0] = vec5[2] = 0.0f; + vec5[1] = -1.0f; + + vec3.EqualsCross(&vec4, &vec5); + vec3.Unitize(); + vec4.EqualsCross(&vec5, &vec3); + vec6 = vec2; + + local90 = m_unk0x1a8; + m_unk0x160 = local48; + + vec1.Clear(); + vec2.Clear(); + + m_unk0x1f0 = Timer()->GetTime(); + + m_unk0x1f4.BETA_1004a9f0(local48); + m_unk0x1f4.FUN_10004620(local90); + m_unk0x1f4.FUN_10004520(); } // FUNCTION: LEGO1 0x10004640 diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp index e8ac3d7d..69d2e8a0 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -358,7 +358,7 @@ void LegoCarBuild::VTable0x70() m_unk0x2a0 = sqrt((MxDouble) DISTSQRD2(m_unk0x290, m_unk0x298)); - m_unk0x25c.Unknown1(m_unk0x178, m_unk0x208); + m_unk0x25c.BETA_1004a9b0(m_unk0x178, m_unk0x208); } // FUNCTION: LEGO1 0x10023130 @@ -406,7 +406,7 @@ void LegoCarBuild::FUN_10023130(MxLong p_x, MxLong p_y) MxFloat local1c = sqrt((double) (NORMSQRD2(local20))) / m_unk0x2a0; - m_unk0x25c.Unknown6(local78, local1c); + m_unk0x25c.BETA_1004aaa0(local78, local1c); local78[3][0] = m_unk0x178[3][0] + local18[0]; local78[3][1] = m_unk0x178[3][1] + local18[1]; diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index 4b74fdf1..ec73ba08 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -2793,8 +2793,8 @@ void LegoAnimationManager::FUN_100648f0(LegoTranInfo* p_tranInfo, MxLong p_unk0x LegoLocation* location = NavController()->GetLocation(p_tranInfo->m_location); if (location != NULL) { CalcLocalTransform(location->m_position, location->m_direction, location->m_up, m_unk0x484); - m_unk0x4cc.Unknown1(m_unk0x43c, m_unk0x484); - m_unk0x4cc.Unknown7(); + m_unk0x4cc.BETA_1004a9b0(m_unk0x43c, m_unk0x484); + m_unk0x4cc.FUN_10004520(); } else { p_tranInfo->m_flags &= ~LegoTranInfo::c_bit1; @@ -2828,7 +2828,7 @@ void LegoAnimationManager::FUN_10064b50(MxLong p_time) sub[1] = (m_unk0x484[3][1] - m_unk0x43c[3][1]) * und; sub[2] = (m_unk0x484[3][2] - m_unk0x43c[3][2]) * und; - m_unk0x4cc.Unknown6(mat, (float) (p_time - m_unk0x434) / 1000.0f); + m_unk0x4cc.BETA_1004aaa0(mat, (float) (p_time - m_unk0x434) / 1000.0f); VPV3(mat[3], m_unk0x43c[3], sub); mat[3][3] = 1.0f; diff --git a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp index 71c4114b..bde810e0 100644 --- a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp @@ -140,6 +140,20 @@ void LegoCameraController::FUN_10012320(float p_angle) m_matrix1.RotateY(p_angle); } +// FUNCTION: LEGO1 0x100123b0 +MxResult LegoCameraController::FUN_100123b0(Matrix4& p_matrix) +{ + if (m_lego3DView) { + ViewROI* pov = m_lego3DView->GetPointOfView(); + if (pov) { + p_matrix = pov->GetLocal2World(); + return SUCCESS; + } + } + + return FAILURE; +} + // FUNCTION: LEGO1 0x100123e0 // FUNCTION: BETA10 0x10068cb2 void LegoCameraController::FUN_100123e0(const Matrix4& p_transform, MxU32 p_und) diff --git a/LEGO1/lego/sources/anim/legoanim.cpp b/LEGO1/lego/sources/anim/legoanim.cpp index 0328738b..4ee2dc69 100644 --- a/LEGO1/lego/sources/anim/legoanim.cpp +++ b/LEGO1/lego/sources/anim/legoanim.cpp @@ -878,9 +878,9 @@ inline void LegoAnimNodeData::GetTranslation( c[3] = p_rotationKeys[i + 1].GetAngle(); } - b.Unknown4(a); - b.Unknown5(c); - b.Unknown6( + b.BETA_10180b80(a); + b.BETA_10180bc0(c); + b.BETA_1004aaa0( p_matrix, (p_time - p_rotationKeys[i].GetTime()) / (p_rotationKeys[i + 1].GetTime() - p_rotationKeys[i].GetTime()) ); diff --git a/LEGO1/mxgeometry/mxgeometry3d.h b/LEGO1/mxgeometry/mxgeometry3d.h index 99a44fd3..15fd1ab0 100644 --- a/LEGO1/mxgeometry/mxgeometry3d.h +++ b/LEGO1/mxgeometry/mxgeometry3d.h @@ -105,35 +105,36 @@ class UnknownMx4DPointFloat { UnknownMx4DPointFloat() : m_unk0x30(0) {} // FUNCTION: BETA10 0x1004a9b0 - void Unknown1(Matrix4& p_m1, Matrix4& p_m2) + void BETA_1004a9b0(Matrix4& p_m1, Matrix4& p_m2) { - Unknown2(p_m1); - Unknown3(p_m2); + BETA_1004a9f0(p_m1); + FUN_10004620(p_m2); } // FUNCTION: BETA10 0x1004a9f0 - void Unknown2(Matrix4& p_m) + void BETA_1004a9f0(Matrix4& p_m) { p_m.ToQuaternion(m_unk0x00); m_unk0x30 |= c_bit1; } + // FUNCTION: LEGO1 0x10004620 // FUNCTION: BETA10 0x1004aa30 - void Unknown3(Matrix4& p_m) + void FUN_10004620(Matrix4& p_m) { p_m.ToQuaternion(m_unk0x18); m_unk0x30 |= c_bit2; } // FUNCTION: BETA10 0x10180b80 - void Unknown4(Vector4& p_v) + void BETA_10180b80(Vector4& p_v) { m_unk0x00 = p_v; m_unk0x30 |= c_bit1; } // FUNCTION: BETA10 0x10180bc0 - void Unknown5(Vector4& p_v) + void BETA_10180bc0(Vector4& p_v) { m_unk0x18 = p_v; m_unk0x30 |= c_bit2; @@ -143,8 +144,8 @@ class UnknownMx4DPointFloat { const Vector4& GetUnknown0x18() const { return m_unk0x18; } undefined4 GetUnknown0x30() const { return m_unk0x30; } - inline int Unknown6(Matrix4& p_matrix, float p_f); - inline void Unknown7(); + inline int BETA_1004aaa0(Matrix4& p_matrix, float p_f); + inline long FUN_10004520(); private: inline int FUN_100040a0(Vector4& p_v, float p_f); @@ -155,7 +156,7 @@ class UnknownMx4DPointFloat { }; // FUNCTION: BETA10 0x1004aaa0 -int UnknownMx4DPointFloat::Unknown6(Matrix4& p_matrix, float p_f) +int UnknownMx4DPointFloat::BETA_1004aaa0(Matrix4& p_matrix, float p_f) { float data[4]; Vector4 v(data); @@ -168,22 +169,27 @@ int UnknownMx4DPointFloat::Unknown6(Matrix4& p_matrix, float p_f) } } -inline void UnknownMx4DPointFloat::Unknown7() +// FUNCTION: LEGO1 0x10004520 +inline long UnknownMx4DPointFloat::FUN_10004520() { - if (m_unk0x30) { - Mx4DPointFloat v1; - Mx4DPointFloat v2; - - v1 = m_unk0x00; - v1 += m_unk0x18; - - v2 = m_unk0x00; - v2 -= m_unk0x18; - - if (v1.Dot(&v1, &v1) < v2.Dot(&v2, &v2)) { - m_unk0x18 *= -1.0f; - } + if (!m_unk0x30) { + return -1; } + + Mx4DPointFloat v1; + Mx4DPointFloat v2; + + v1 = m_unk0x00; + v1 += m_unk0x18; + + v2 = m_unk0x00; + v2 -= m_unk0x18; + + if (v1.Dot(&v1, &v1) < v2.Dot(&v2, &v2)) { + m_unk0x18 *= -1.0f; + } + + return 0; } // FUNCTION: LEGO1 0x100040a0 diff --git a/reccmp-project.yml b/reccmp-project.yml index d2aaf9ba..c614cded 100644 --- a/reccmp-project.yml +++ b/reccmp-project.yml @@ -31,5 +31,6 @@ targets: - LegoWorld ignore-functions: # strcpy, strlen, ... (arguments are imported incorrectly) + - 0x100f8ad0 - 0x100fa200 - 0x100f9780 From 6f3f8c2ade4350d6ca2dad45f3dff2aed2c510e1 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 20 Dec 2024 17:05:40 +0100 Subject: [PATCH 08/12] Implement LegoVideoManager::DrawFPS (#1243) * Implement LegoVideoManager::DrawFPS * Implement MxDisplaySurface::FUN_100bc8b0 * Match functions * type --------- Co-authored-by: Christian Semmler --- .../legoomni/src/video/legovideomanager.cpp | 123 +++++++++++++++++- LEGO1/omni/include/mxdisplaysurface.h | 2 + LEGO1/omni/src/video/mxdisplaysurface.cpp | 36 +++++ 3 files changed, 158 insertions(+), 3 deletions(-) diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 7c5a2cbb..fcaada49 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -19,6 +19,8 @@ #include "tgl/d3drm/impl.h" #include "viewmanager/viewroi.h" +#include + DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590) DECOMP_SIZE_ASSERT(MxStopWatch, 0x18) DECOMP_SIZE_ASSERT(MxFrequencyMeter, 0x20) @@ -390,10 +392,125 @@ inline void LegoVideoManager::DrawCursor() ->BltFast(m_cursorXCopy, m_cursorYCopy, m_cursorSurface, &m_cursorRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); } -// STUB: LEGO1 0x1007bbc0 +// FUNCTION: LEGO1 0x1007bbc0 void LegoVideoManager::DrawFPS() { - // TODO + char zeros[8] = "0000.00"; + + if (m_unk0x528 == NULL) { + m_arialFont = CreateFontA( + 12, + 0, + 0, + 0, + FW_NORMAL, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_DONTCARE | VARIABLE_PITCH, + "Arial" + ); + + HDC dc = GetDC(NULL); + SelectObject(dc, m_arialFont); + GetTextExtentPointA(dc, zeros, strlen(zeros), &m_fpsSize); + ReleaseDC(NULL, dc); + + m_unk0x528 = m_displaySurface->FUN_100bc8b0(m_fpsSize.cx, m_fpsSize.cy); + SetRect(&m_fpsRect, 0, 0, m_fpsSize.cx, m_fpsSize.cy); + + if (m_unk0x528 == NULL) { + DeleteObject(m_arialFont); + m_arialFont = NULL; + return; + } + + DDCOLORKEY colorKey; + memset(&colorKey, 0, sizeof(colorKey)); + m_unk0x528->SetColorKey(DDCKEY_SRCBLT, &colorKey); + + DDSURFACEDESC surfaceDesc; + memset(&surfaceDesc, 0, sizeof(surfaceDesc)); + surfaceDesc.dwSize = sizeof(surfaceDesc); + + if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) != DD_OK) { + m_unk0x528->Release(); + DeleteObject(m_arialFont); + m_unk0x528 = NULL; + m_arialFont = NULL; + } + else { + DWORD i; + char* ptr = (char*) surfaceDesc.lpSurface; + + for (i = 0; i < surfaceDesc.dwHeight; i++) { + memset(ptr, 0, surfaceDesc.dwWidth * surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8); + ptr += surfaceDesc.lPitch; + } + + m_unk0x528->Unlock(surfaceDesc.lpSurface); + m_unk0x54c = Timer()->GetTime(); + m_unk0x550 = 1.f; + } + } + else { + if (Timer()->GetTime() > m_unk0x54c + 5000.f) { + char buffer[32]; + MxFloat time = (Timer()->GetTime() - m_unk0x54c) / 1000.0f; + MxS32 nb = sprintf(buffer, "%.02f", m_unk0x550 / time); + m_unk0x54c = Timer()->GetTime(); + + DDSURFACEDESC surfaceDesc; + memset(&surfaceDesc, 0, sizeof(surfaceDesc)); + surfaceDesc.dwSize = sizeof(surfaceDesc); + + if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) { + DWORD i; + char* ptr = (char*) surfaceDesc.lpSurface; + + for (i = 0; i < surfaceDesc.dwHeight; i++) { + memset(ptr, 0, surfaceDesc.dwWidth * surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8); + ptr += surfaceDesc.lPitch; + } + + m_unk0x528->Unlock(surfaceDesc.lpSurface); + } + + HDC dc; + if (m_unk0x528->GetDC(&dc) != DD_OK) { + m_unk0x528->Release(); + m_unk0x528 = NULL; + DeleteObject(m_arialFont); + m_arialFont = NULL; + return; + } + + SelectObject(dc, m_arialFont); + SetTextColor(dc, RGB(255, 255, 0)); + SetBkColor(dc, RGB(0, 0, 0)); + SetBkMode(dc, OPAQUE); + GetTextExtentPoint32A(dc, buffer, nb, &m_fpsSize); + + RECT rect; + SetRect(&rect, 0, 0, m_fpsSize.cx, m_fpsSize.cy); + ExtTextOutA(dc, 0, 0, ETO_OPAQUE, &rect, buffer, nb, NULL); + m_unk0x528->ReleaseDC(dc); + m_unk0x550 = 1.f; + } + else { + m_unk0x550 += 1.f; + } + + if (m_unk0x528 != NULL) { + m_displaySurface->GetDirectDrawSurface2() + ->BltFast(20, 20, m_unk0x528, &m_fpsRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + m_3dManager->GetLego3DView()->GetView()->ForceUpdate(20, 20, m_fpsRect.right, m_fpsRect.bottom); + } + } } // FUNCTION: LEGO1 0x1007c080 @@ -531,7 +648,7 @@ void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) // FUNCTION: LEGO1 0x1007c4c0 void LegoVideoManager::OverrideSkyColor(MxBool p_shouldOverride) { - this->m_videoParam.GetPalette()->SetOverrideSkyColor(p_shouldOverride); + m_videoParam.GetPalette()->SetOverrideSkyColor(p_shouldOverride); } // FUNCTION: LEGO1 0x1007c4d0 diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 3c2c83a7..43606bd0 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -109,6 +109,8 @@ class MxDisplaySurface : public MxCore { MxU8 p_bpp ); + LPDIRECTDRAWSURFACE FUN_100bc8b0(MxS32 width, MxS32 height); + private: MxU8 CountTotalBitsSetTo1(MxU32 p_param); MxU8 CountContiguousBitsSetTo1(MxU32 p_param); diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 3a301af1..647de44a 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -1092,3 +1092,39 @@ MxBool MxDisplaySurface::VTable0x2c( { return 0; } + +// FUNCTION: LEGO1 0x100bc8b0 +LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 width, MxS32 height) +{ + LPDIRECTDRAWSURFACE surface = NULL; + + LPDIRECTDRAW ddraw = MVideoManager()->GetDirectDraw(); + MxVideoParam& unused = MVideoManager()->GetVideoParam(); + + DDSURFACEDESC surfaceDesc; + memset(&surfaceDesc, 0, sizeof(surfaceDesc)); + surfaceDesc.dwSize = sizeof(surfaceDesc); + + if (ddraw->GetDisplayMode(&surfaceDesc) != DD_OK) { + return NULL; + } + + if (surfaceDesc.ddpfPixelFormat.dwRGBBitCount != 16) { + return NULL; + } + + surfaceDesc.dwWidth = width; + surfaceDesc.dwHeight = height; + surfaceDesc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + surfaceDesc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; + + if (ddraw->CreateSurface(&surfaceDesc, &surface, NULL) != DD_OK) { + surfaceDesc.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + surfaceDesc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + if (ddraw->CreateSurface(&surfaceDesc, &surface, NULL) != DD_OK) { + return NULL; + } + } + + return surface; +} From b338a66a7727a4028a8dfe6bf54c06801c490c91 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 20 Dec 2024 17:50:33 +0100 Subject: [PATCH 09/12] Implement GroupImpl::RemoveAll (#1244) * Implement GroupImpl::RemoveAll (81.30%) * Minor improvement * Add 2 to total function count --------- Co-authored-by: Christian Semmler --- .github/workflows/build.yml | 2 +- LEGO1/tgl/d3drm/group.cpp | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36a7db9a..a946f005 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -139,7 +139,7 @@ jobs: run: | reccmp-reccmp -S CONFIGPROGRESS.SVG --svg-icon assets/config.png --target CONFIG | tee CONFIGPROGRESS.TXT reccmp-reccmp -S ISLEPROGRESS.SVG --svg-icon assets/isle.png --target ISLE | tee ISLEPROGRESS.TXT - reccmp-reccmp -S LEGO1PROGRESS.SVG -T 4352 --svg-icon assets/lego1.png --target LEGO1 | tee LEGO1PROGRESS.TXT + reccmp-reccmp -S LEGO1PROGRESS.SVG -T 4354 --svg-icon assets/lego1.png --target LEGO1 | tee LEGO1PROGRESS.TXT - name: Compare Accuracy With Current Master shell: bash diff --git a/LEGO1/tgl/d3drm/group.cpp b/LEGO1/tgl/d3drm/group.cpp index a9df8fd6..854788b8 100644 --- a/LEGO1/tgl/d3drm/group.cpp +++ b/LEGO1/tgl/d3drm/group.cpp @@ -106,10 +106,26 @@ Result GroupImpl::Remove(const Group* pGroup) return ResultVal(m_data->DeleteVisual(pGroupImpl->m_data)); } -// STUB: LEGO1 0x100a34b0 +// FUNCTION: LEGO1 0x100a34b0 Result GroupImpl::RemoveAll() { - return Error; + IDirect3DRMVisualArray* visuals; + IDirect3DRMFrame2* frame = m_data; + Result result = (Result) SUCCEEDED(frame->GetVisuals(&visuals)); + + if (result == Success) { + for (int i = 0; i < (int) visuals->GetSize(); i++) { + IDirect3DRMVisual* visual; + + result = (Result) SUCCEEDED(visuals->GetElement(i, &visual)); + frame->DeleteVisual(visual); + visual->Release(); + } + + visuals->Release(); + } + + return result; } // STUB: LEGO1 0x100a3540 From bfc6d460a8ae1a6b74b3b131e9748fd9d91a5c73 Mon Sep 17 00:00:00 2001 From: MS Date: Fri, 20 Dec 2024 13:23:24 -0500 Subject: [PATCH 10/12] `MxDSBuffer::SkipToData` to 100% (#1245) * MxDSBuffer::SkipToData to 100% * Add blank line --- LEGO1/omni/src/stream/mxdsbuffer.cpp | 39 ++++++++++++++++------------ 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/LEGO1/omni/src/stream/mxdsbuffer.cpp b/LEGO1/omni/src/stream/mxdsbuffer.cpp index b7dca118..44de686b 100644 --- a/LEGO1/omni/src/stream/mxdsbuffer.cpp +++ b/LEGO1/omni/src/stream/mxdsbuffer.cpp @@ -338,42 +338,47 @@ MxCore* MxDSBuffer::ReadChunk(MxDSBuffer* p_buffer, MxU32* p_chunkData, MxU16 p_ } // FUNCTION: LEGO1 0x100c6df0 +// FUNCTION: BETA10 0x10157e0a MxU8* MxDSBuffer::SkipToData() { MxU8* result = NULL; if (m_pIntoBuffer != NULL) { - do { - MxU32* ptr = (MxU32*) m_pIntoBuffer; - switch (*ptr) { - case FOURCC('L', 'I', 'S', 'T'): - case FOURCC('R', 'I', 'F', 'F'): - m_pIntoBuffer = (MxU8*) (ptr + 3); - break; + while (TRUE) { + switch (*(MxU32*) m_pIntoBuffer) { case FOURCC('M', 'x', 'O', 'b'): case FOURCC('M', 'x', 'C', 'h'): result = m_pIntoBuffer; - m_pIntoBuffer = (MxU8*) ((ptr[1] & 1) + ptr[1] + (MxU32) ptr); - m_pIntoBuffer = (MxU8*) ((MxU32*) m_pIntoBuffer + 2); - if (m_pBuffer + (m_writeOffset - 8) < m_pIntoBuffer) { - m_pIntoBuffer2 = result; + m_pIntoBuffer += (*(MxU32*) (m_pIntoBuffer + 4) & 1) + *(MxU32*) (m_pIntoBuffer + 4); + m_pIntoBuffer += 8; + + if (m_pBuffer + m_writeOffset - 8 < m_pIntoBuffer) { m_pIntoBuffer = NULL; - return result; } + goto done; case FOURCC('M', 'x', 'D', 'a'): case FOURCC('M', 'x', 'S', 't'): - m_pIntoBuffer = (MxU8*) (ptr + 2); + m_pIntoBuffer += 8; break; case FOURCC('M', 'x', 'H', 'd'): - m_pIntoBuffer = (MxU8*) ((MxU32) ptr + ptr[1] + 8); + m_pIntoBuffer += *(MxU32*) (m_pIntoBuffer + 4) + 8; + break; + case FOURCC('L', 'I', 'S', 'T'): + case FOURCC('R', 'I', 'F', 'F'): + m_pIntoBuffer += 12; break; default: m_pIntoBuffer = NULL; - m_pIntoBuffer2 = NULL; - return NULL; + result = NULL; + goto done; } - } while (m_pIntoBuffer <= m_pBuffer + (m_writeOffset - 8)); + + if (m_pIntoBuffer > m_pBuffer + m_writeOffset - 8) { + m_pIntoBuffer = NULL; + goto done; + } + } } done: m_pIntoBuffer2 = result; From 581ba0f5aef7a204c20ebe4c2ebbdb7174236703 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 20 Dec 2024 19:48:31 +0100 Subject: [PATCH 11/12] Implement GroupImpl::Bounds (#1246) * Implement/match DeviceImpl::HandleActivate * Implement/match DeviceImpl::HandlePaint * Implement GroupImpl::Unknown (71.63%) * Fixes --------- Co-authored-by: Christian Semmler --- LEGO1/tgl/d3drm/device.cpp | 16 ++++------ LEGO1/tgl/d3drm/group.cpp | 65 ++++++++++++++++++++++++++++++++++++-- LEGO1/tgl/d3drm/impl.h | 9 ++++-- LEGO1/tgl/tgl.h | 6 ++-- 4 files changed, 78 insertions(+), 18 deletions(-) diff --git a/LEGO1/tgl/d3drm/device.cpp b/LEGO1/tgl/d3drm/device.cpp index b991d417..a1c7b0c8 100644 --- a/LEGO1/tgl/d3drm/device.cpp +++ b/LEGO1/tgl/d3drm/device.cpp @@ -49,28 +49,23 @@ Result DeviceImpl::SetDither(int dither) return ResultVal(m_data->SetDither(dither)); } -// Probably wrong, not sure what's going on in this method. // FUNCTION: LEGO1 0x100a2ce0 -void DeviceImpl::InitFromD3DDevice(Device*) +void DeviceImpl::HandleActivate(WORD wParam) { // Device argument is intentionally unused. IDirect3DRMWinDevice* winDevice; if (ResultVal(m_data->QueryInterface(IID_IDirect3DRMWinDevice, (LPVOID*) &winDevice))) { - m_data->InitFromD3D((LPDIRECT3D) &winDevice, (LPDIRECT3DDEVICE) m_data); + winDevice->HandleActivate(wParam); winDevice->Release(); } } -// Really don't know what's going on here. Seems it will call down to Init -// but the decomp suggests it otherwise looks the same as InitFromD3D but Init -// takes widly different parameters. // FUNCTION: LEGO1 0x100a2d20 -void DeviceImpl::InitFromWindowsDevice(Device*) +void DeviceImpl::HandlePaint(HDC p_dc) { - // Device argument is intentionally unused. IDirect3DRMWinDevice* winDevice; if (SUCCEEDED(m_data->QueryInterface(IID_IDirect3DRMWinDevice, (LPVOID*) &winDevice))) { - // m_data->Init(??); + winDevice->HandlePaint(p_dc); winDevice->Release(); } } @@ -80,3 +75,6 @@ Result DeviceImpl::Update() { return ResultVal(m_data->Update()); } + +// GLOBAL: LEGO1 0x100dd1d0 +// IID_IDirect3DRMWinDevice diff --git a/LEGO1/tgl/d3drm/group.cpp b/LEGO1/tgl/d3drm/group.cpp index 854788b8..912cc137 100644 --- a/LEGO1/tgl/d3drm/group.cpp +++ b/LEGO1/tgl/d3drm/group.cpp @@ -128,8 +128,67 @@ Result GroupImpl::RemoveAll() return result; } -// STUB: LEGO1 0x100a3540 -Result GroupImpl::Unknown() +// FUNCTION: LEGO1 0x100a3540 +Result GroupImpl::Bounds(D3DVECTOR* p_min, D3DVECTOR* p_max) { - return Error; + D3DRMBOX size; + IDirect3DRMFrame2* frame = m_data; + + size.min.x = 88888.f; + size.min.y = 88888.f; + size.min.z = 88888.f; + size.max.x = -88888.f; + size.max.y = -88888.f; + size.max.z = -88888.f; + + IDirect3DRMVisualArray* visuals; + Result result = (Result) SUCCEEDED(frame->GetVisuals(&visuals)); + + if (result == Success) { + int i; + for (i = 0; i < (int) visuals->GetSize(); i++) { + IDirect3DRMVisual* visual; + visuals->GetElement(i, &visual); + IDirect3DRMMesh* mesh; + /* + * BUG: should be: + * visual->QueryInterface(IID_IDirect3DRMMesh, (void**)&mesh)); + */ + result = (Result) SUCCEEDED(visual->QueryInterface(IID_IDirect3DRMMeshBuilder, (void**) &mesh)); + + if (result == Success) { + D3DRMBOX box; + result = (Result) SUCCEEDED(mesh->GetBox(&box)); + + if (size.max.y < box.max.y) { + size.max.y = box.max.y; + } + if (size.max.z < box.max.z) { + size.max.z = box.max.z; + } + if (box.min.x < size.min.x) { + size.min.x = box.min.x; + } + if (box.min.y < size.min.y) { + size.min.y = box.min.y; + } + if (box.min.z < size.min.z) { + size.min.z = box.min.z; + } + if (size.max.x < box.max.x) { + size.max.x = box.max.x; + } + + mesh->Release(); + } + + visual->Release(); + } + + visuals->Release(); + } + + *p_min = size.min; + *p_max = size.max; + return result; } diff --git a/LEGO1/tgl/d3drm/impl.h b/LEGO1/tgl/d3drm/impl.h index 14acce2a..a2998c7a 100644 --- a/LEGO1/tgl/d3drm/impl.h +++ b/LEGO1/tgl/d3drm/impl.h @@ -145,8 +145,8 @@ class DeviceImpl : public Device { // vtable+0x20 Result Update() override; - void InitFromD3DDevice(Device*) override; - void InitFromWindowsDevice(Device*) override; + void HandleActivate(WORD) override; + void HandlePaint(HDC) override; IDirect3DRMDevice2* ImplementationData() const { return m_data; } void SetImplementationData(IDirect3DRMDevice2* device) { m_data = device; } @@ -335,7 +335,7 @@ class GroupImpl : public Group { Result RemoveAll() override; // vtable+0x30 - Result Unknown() override; + Result Bounds(D3DVECTOR* p_min, D3DVECTOR* p_max) override; IDirect3DRMFrame2* ImplementationData() const { return m_data; } @@ -545,4 +545,7 @@ inline D3DRMMATRIX4D* Translate(FloatMatrix4& tglMatrix4x4, D3DRMMATRIX4D& rD3DR // SYNTHETIC: LEGO1 0x100a3d80 // TglImpl::MeshImpl::`scalar deleting destructor' +// GLOBAL: LEGO1 0x100dd1e0 +// IID_IDirect3DRMMeshBuilder + } /* namespace TglImpl */ diff --git a/LEGO1/tgl/tgl.h b/LEGO1/tgl/tgl.h index 4c29ed1f..34b1d5ee 100644 --- a/LEGO1/tgl/tgl.h +++ b/LEGO1/tgl/tgl.h @@ -171,8 +171,8 @@ class Device : public Object { // vtable+0x20 virtual Result Update() = 0; - virtual void InitFromD3DDevice(Device*) = 0; - virtual void InitFromWindowsDevice(Device*) = 0; + virtual void HandleActivate(WORD) = 0; + virtual void HandlePaint(HDC) = 0; // SYNTHETIC: LEGO1 0x100a2350 // Tgl::Device::~Device @@ -305,7 +305,7 @@ class Group : public Object { // This is TransformLocalToWorld in the leak, however it seems // to have been replaced by something else in the shipped code. - virtual Result Unknown() = 0; + virtual Result Bounds(D3DVECTOR*, D3DVECTOR*) = 0; // SYNTHETIC: LEGO1 0x100a2510 // Tgl::Group::~Group From 2b4f71e17d6a94e04c8d5c9ff870c6b98d3761d0 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 20 Dec 2024 11:49:18 -0700 Subject: [PATCH 12/12] Implement/match `Act3Cop::FUN_10040360` (#1247) * Implement/match `Act3Cop::FUN_10040360` * Remove comments * Modern compiler fix --- LEGO1/lego/legoomni/src/actors/act3actors.cpp | 186 +++++++++++++++++- 1 file changed, 182 insertions(+), 4 deletions(-) diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index b05830b9..f09c691a 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -320,11 +320,188 @@ MxResult Act3Cop::FUN_10040350(Act3Ammo& p_ammo, const Vector3&) return FUN_10040360(); } -// STUB: LEGO1 0x10040360 -// STUB: BETA10 0x10018c6a +// FUNCTION: LEGO1 0x10040360 +// FUNCTION: BETA10 0x10018c6a MxResult Act3Cop::FUN_10040360() { - // TODO + LegoPathEdgeContainer* grec = NULL; + Act3* a3 = (Act3*) m_world; + + MxMatrix local74(m_unk0xec); + Vector3 local2c(local74[3]); + Vector3 local20(local74[2]); + + Mx3DPointFloat local7c; + local7c = a3->m_brickster->GetROI()->GetLocal2World()[3]; + local7c -= local2c; + + if (local7c.LenSquared() < 144.0f) { + local7c = a3->m_brickster->GetROI()->GetLocal2World()[3]; + Mx3DPointFloat local5c(a3->m_brickster->GetROI()->GetLocal2World()[2]); + LegoPathBoundary* boundary = a3->m_brickster->GetBoundary(); + + grec = new LegoPathEdgeContainer(); + assert(grec); + + MxFloat local34; + if (m_pathController->FUN_10048310( + grec, + local2c, + local20, + m_boundary, + local7c, + local5c, + boundary, + LegoUnknown100db7f4::c_bit1, + &local34 + ) != SUCCESS) { + delete grec; + grec = NULL; + } + } + + if (grec == NULL) { + float local18; + + for (MxS32 i = 0; i < MAX_DONUTS; i++) { + Act3Ammo* donut = &a3->m_donuts[i]; + assert(donut); + + if (donut->IsValid() && donut->GetActorState() == c_initial) { + LegoROI* proi = donut->GetROI(); + assert(proi); + + MxMatrix locald0 = proi->GetLocal2World(); + Vector3 local88(locald0[3]); + Mx3DPointFloat localec(local88); + localec -= local88; + + LegoPathEdgeContainer* r2 = new LegoPathEdgeContainer(); + assert(r2); + + MxFloat locald8; + LegoPathEdgeContainer *local138, *local134, *local140, *local13c; // unused + + if (m_pathController->FUN_10048310( + r2, + local2c, + local20, + m_boundary, + local88, + localec, + donut->GetBoundary(), + LegoUnknown100db7f4::c_bit1, + &locald8 + ) == SUCCESS && + (grec == NULL || locald8 < local18)) { + if (grec != NULL) { + local134 = local138 = grec; + delete grec; + } + + grec = r2; + local18 = locald8; + } + + if (grec != r2) { + local13c = local140 = r2; + delete r2; + } + } + } + + if (grec == NULL) { + MxS32 random = rand() % (MxS32) sizeOfArray(g_copDest); + Vector3 localf8(g_copDest[random].m_unk0x08); + Vector3 local108(g_copDest[random].m_unk0x14); + + grec = new LegoPathEdgeContainer(); + LegoPathBoundary* boundary = g_copDest[random].m_boundary; + + if (boundary != NULL) { + MxFloat local100; + LegoPathEdgeContainer *local150, *local14c; // unused + + if (m_pathController->FUN_10048310( + grec, + local2c, + local20, + m_boundary, + localf8, + local108, + boundary, + LegoUnknown100db7f4::c_bit1, + &local100 + ) != SUCCESS) { + local14c = local150 = grec; + delete grec; + grec = NULL; + } + } + } + } + + if (grec != NULL) { + LegoPathEdgeContainer *local158, *local154; // unused + if (m_grec != NULL) { + local154 = local158 = 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; + } + else { + Mx3DPointFloat local128; + 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); + + local128 = *v2; + local128 -= *v1; + local128 *= m_unk0xe4; + local128 += *v1; + local128 *= -1.0f; + local128 += m_grec->m_position; + local128.Unitize(); + m_grec->m_direction = local128; + + 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]); + Vector3 v4(m_unk0xec[3]); + + v3 = v4; + v3 -= vecUnk; + v3.Unitize(); + v1.EqualsCross(&v2, &v3); + v1.Unitize(); + v2.EqualsCross(&v3, &v1); + + VTable0x9c(); + } + return SUCCESS; } @@ -808,8 +985,9 @@ MxResult Act3Brickster::FUN_100417c0() Vector3 v1(m_unk0xec[0]); Vector3 v2(m_unk0xec[1]); Vector3 v3(m_unk0xec[2]); + Vector3 v4(m_unk0xec[3]); - v3 = m_unk0xec[3]; + v3 = v4; v3 -= vecUnk; v3.Unitize(); v1.EqualsCross(&v2, &v3);