From af2418e61fc3ebd4ce151da6b7197a343baba640 Mon Sep 17 00:00:00 2001 From: jonschz <17198703+jonschz@users.noreply.github.com> Date: Mon, 5 Jan 2026 23:45:36 +0100 Subject: [PATCH] Beta match `LegoLOD` and related classes (#1704) * beta match LegoLOD, part 1 * Fix name collision for Ghidra * More LegoLOD matches * LegoMesh and LegoColor matches * Various matches * 73 % beta match on LegoLOD::Read * Fix LEGO1 regressions, improve match * 70.93 % on LEGO1 * 72.85 %, stack too small now * Cleanup * Cleanup --------- Co-authored-by: jonschz --- LEGO1/lego/sources/roi/legolod.cpp | 252 ++++++++++++++++++++----- LEGO1/lego/sources/roi/legolod.h | 4 + LEGO1/lego/sources/roi/legoroi.cpp | 6 +- LEGO1/lego/sources/shape/legocolor.cpp | 1 + LEGO1/lego/sources/shape/legocolor.h | 10 + LEGO1/lego/sources/shape/legomesh.cpp | 3 + LEGO1/lego/sources/shape/legomesh.h | 23 +++ LEGO1/library_msvc.h | 1 + LEGO1/realtime/roi.h | 6 + LEGO1/viewmanager/viewlod.cpp | 6 +- LEGO1/viewmanager/viewlod.h | 9 + LEGO1/viewmanager/viewmanager.cpp | 6 +- reccmp-project.yml | 1 + util/decomp.h | 6 + 14 files changed, 280 insertions(+), 54 deletions(-) diff --git a/LEGO1/lego/sources/roi/legolod.cpp b/LEGO1/lego/sources/roi/legolod.cpp index 453a4dac..e4b11fc7 100644 --- a/LEGO1/lego/sources/roi/legolod.cpp +++ b/LEGO1/lego/sources/roi/legolod.cpp @@ -13,19 +13,35 @@ DECOMP_SIZE_ASSERT(LegoLOD, 0x20) DECOMP_SIZE_ASSERT(LegoLOD::Mesh, 0x08) // GLOBAL: LEGO1 0x101013d4 -LPDIRECT3DRMMATERIAL g_unk0x101013d4 = NULL; +// GLOBAL: BETA10 0x10207230 +LPDIRECT3DRMMATERIAL g_lodMaterial = NULL; // GLOBAL: LEGO1 0x101013dc +// GLOBAL: BETA10 0x10207238 const char* g_InhPrefix = "inh"; -inline IDirect3DRM2* GetD3DRM(Tgl::Renderer* pRenderer); -inline BOOL GetMeshData(IDirect3DRMMesh*& mesh, D3DRMGROUPINDEX& index, Tgl::Mesh* pMesh); +#ifdef BETA10 +inline BOOL GetD3DRM_legolod(IDirect3DRM2*& d3drm, Tgl::Renderer* pRenderer); +#else +inline IDirect3DRM2* GetD3DRM_legolod(Tgl::Renderer* pRenderer); +#endif +inline BOOL GetMeshData(IDirect3DRMMesh** mesh, D3DRMGROUPINDEX* index, Tgl::Mesh* pMesh); // FUNCTION: LEGO1 0x100aa380 +// FUNCTION: BETA10 0x1018ce90 LegoLOD::LegoLOD(Tgl::Renderer* p_renderer) : ViewLOD(p_renderer) { - if (g_unk0x101013d4 == NULL) { - GetD3DRM(p_renderer)->CreateMaterial(10.0, &g_unk0x101013d4); + if (g_lodMaterial == NULL) { +#ifdef BETA10 + IDirect3DRM2* d3drm = NULL; + assert((p_renderer != NULL)); + GetD3DRM_legolod(d3drm, p_renderer); + if (d3drm->CreateMaterial(10.0, &g_lodMaterial)) { + assert(0); + } +#else + GetD3DRM_legolod(p_renderer)->CreateMaterial(10.0, &g_lodMaterial); +#endif } m_melems = NULL; @@ -36,6 +52,7 @@ LegoLOD::LegoLOD(Tgl::Renderer* p_renderer) : ViewLOD(p_renderer) } // FUNCTION: LEGO1 0x100aa450 +// FUNCTION: BETA10 0x1018d017 LegoLOD::~LegoLOD() { if (m_numMeshes && m_melems != NULL) { @@ -52,21 +69,59 @@ LegoLOD::~LegoLOD() } } +#ifdef BETA10 +/// This class does not exist in LEGO1. +class UnknownBeta0x1018e7e0 { +public: + // FUNCTION: BETA10 0x1018e7e0 + UnknownBeta0x1018e7e0() + { + m_unk0x00 = 0; + m_unk0x04 = 0; + m_unk0x08 = 0; + m_unk0x0c = 0; + m_unk0x10 = 0; + m_unk0x14 = 0; + m_unk0x18 = 0; + } + + // STUB: BETA10 0x1018e840 + undefined4 BETA10_1018e840(LegoStorage* p_storage) { return 0; } + + undefined4 m_unk0x00; + undefined4 m_unk0x04; + undefined4 m_unk0x08; + undefined4 m_unk0x0c; + undefined4 m_unk0x10; + undefined4 m_unk0x14; + undefined4 m_unk0x18; + undefined4 m_unk0x1c; +}; +#endif + // FUNCTION: LEGO1 0x100aa510 +// FUNCTION: BETA10 0x1018d15d LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage) { + using Tgl::Succeeded; + float(*normals)[3] = NULL; float(*vertices)[3] = NULL; float(*textureVertices)[2] = NULL; LegoS32 numVerts = 0; LegoS32 numNormals = 0; LegoS32 numTextureVertices = 0; - LegoMesh* mesh = NULL; + LegoMesh* legoMesh = NULL; LegoU32(*polyIndices)[3] = NULL; LegoU32(*textureIndices)[3] = NULL; LegoTextureInfo* textureInfo = NULL; - + LegoU8 local4c = 0; // BETA10 only, only written, never read + LegoU32 numPolys, numVertices, numTextureIndices, meshIndex; LegoU32 i, indexBackwards, indexForwards, tempNumVertsAndNormals; + LegoFloat red, green, blue, alpha; + IDirect3DRMMesh* d3dmesh; + D3DRMGROUPINDEX index; + unsigned char paletteEntries[256]; if (p_storage->Read(&m_flags, sizeof(LegoU32)) != SUCCESS) { @@ -74,6 +129,14 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text } if (SkipReadingData()) { +#ifdef BETA10 + // There was an additional field of the correct type here in BETA10 + m_flags = (unsigned int) new UnknownBeta0x1018e7e0(); + if (((UnknownBeta0x1018e7e0*) m_flags)->BETA10_1018e840(p_storage)) { + assert(0); + return FAILURE; + } +#endif return SUCCESS; } @@ -84,11 +147,15 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text } if (m_numMeshes == 0) { +#ifndef BETA10 ClearFlag(c_hasMesh); +#endif return SUCCESS; } +#ifndef BETA10 SetFlag(c_hasMesh); +#endif m_melems = new Mesh[m_numMeshes]; memset(m_melems, 0, sizeof(*m_melems) * m_numMeshes); @@ -97,19 +164,24 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text indexForwards = 0; if (p_storage->Read(&tempNumVertsAndNormals, sizeof(LegoU32)) != SUCCESS) { + assertIfBeta10(0); goto done; } + // TODO: Can't get this one right numVerts = *((LegoU16*) &tempNumVertsAndNormals) & MAXSHORT; numNormals = (*((LegoU16*) &tempNumVertsAndNormals + 1) >> 1) & MAXSHORT; if (p_storage->Read(&numTextureVertices, sizeof(LegoS32)) != SUCCESS) { + assertIfBeta10(0); goto done; } if (numVerts > 0) { vertices = new float[numVerts][sizeOfArray(*vertices)]; if (p_storage->Read(vertices, numVerts * 3 * sizeof(float)) != SUCCESS) { + // LINE: BETA10 0x1018d443 + assertIfBeta10(0); goto done; } } @@ -117,6 +189,7 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text if (numNormals > 0) { normals = new float[numNormals][sizeOfArray(*normals)]; if (p_storage->Read(normals, numNormals * 3 * sizeof(float)) != SUCCESS) { + assertIfBeta10(0); goto done; } } @@ -124,37 +197,44 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text if (numTextureVertices > 0) { textureVertices = new float[numTextureVertices][sizeOfArray(*textureVertices)]; if (p_storage->Read(textureVertices, numTextureVertices * 2 * sizeof(float)) != SUCCESS) { + // LINE: BETA10 0x1018d513 + assertIfBeta10(0); goto done; } } for (i = 0; i < m_numMeshes; i++) { - LegoU32 numPolys, numVertices, numTextureIndices, meshIndex; + local4c = 0; const LegoChar *textureName, *materialName; Tgl::ShadingModel shadingModel; if (p_storage->Read(&numPolys, 2) != SUCCESS) { + assertIfBeta10(0); goto done; } m_numPolys += numPolys & USHRT_MAX; if (p_storage->Read(&numVertices, 2) != SUCCESS) { + assertIfBeta10(0); goto done; } polyIndices = new LegoU32[numPolys & USHRT_MAX][sizeOfArray(*polyIndices)]; if (p_storage->Read(polyIndices, (numPolys & USHRT_MAX) * 3 * sizeof(LegoU32)) != SUCCESS) { + assertIfBeta10(0); goto done; } if (p_storage->Read(&numTextureIndices, sizeof(numTextureIndices)) != SUCCESS) { + assertIfBeta10(0); goto done; } if (numTextureIndices > 0) { textureIndices = new LegoU32[numPolys & USHRT_MAX][sizeOfArray(*textureIndices)]; if (p_storage->Read(textureIndices, (numPolys & USHRT_MAX) * 3 * sizeof(LegoU32)) != SUCCESS) { + assertIfBeta10(0); goto done; } } @@ -162,13 +242,14 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text textureIndices = NULL; } - mesh = new LegoMesh(); + legoMesh = new LegoMesh(); - if (mesh->Read(p_storage) != SUCCESS) { + if (legoMesh->Read(p_storage) != SUCCESS) { + assertIfBeta10(0); goto done; } - switch (mesh->GetShading()) { + switch (legoMesh->GetShading()) { case LegoMesh::e_flat: shadingModel = Tgl::Flat; break; @@ -181,19 +262,23 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text m_numVertices += numVertices & USHRT_MAX; - textureName = mesh->GetTextureName(); - materialName = mesh->GetMaterialName(); + textureName = legoMesh->GetTextureName(); + materialName = legoMesh->GetMaterialName(); if (HasInhPrefix(textureName) || HasInhPrefix(materialName)) { meshIndex = indexBackwards; indexBackwards--; } else { + local4c = 1; meshIndex = indexForwards; indexForwards++; } - m_melems[meshIndex].m_tglMesh = m_meshBuilder->CreateMesh( + Tgl::MeshBuilder* locMesh = m_meshBuilder; + assert(locMesh); + + m_melems[meshIndex].m_tglMesh = locMesh->CreateMesh( numPolys & USHRT_MAX, numVertices & USHRT_MAX, vertices, @@ -202,58 +287,84 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text polyIndices, textureIndices, shadingModel + // LINE: LEGO1 0x100aa885 ); if (m_melems[meshIndex].m_tglMesh == NULL) { + assertIfBeta10(0); goto done; } - m_melems[meshIndex].m_tglMesh->SetShadingModel(shadingModel); + Tgl::Result tglResult = m_melems[meshIndex].m_tglMesh->SetShadingModel(shadingModel); + + // clang-format off + assert(Succeeded( tglResult )); + // clang-format on if (textureName != NULL) { - if (mesh->GetUseAlias()) { - LegoROI::GetPaletteEntries(textureName, paletteEntries, sizeOfArray(paletteEntries)); + if (legoMesh->GetUseAlias() && + LegoROI::GetPaletteEntries(textureName, paletteEntries, sizeOfArray(paletteEntries))) { +#ifdef BETA10 + textureName = (const LegoChar*) paletteEntries; +#endif } - textureInfo = p_textureContainer->Get(mesh->GetTextureName()); + textureInfo = p_textureContainer->Get(legoMesh->GetTextureName()); if (textureInfo == NULL) { + assertIfBeta10(0); goto done; } - m_melems[meshIndex].m_tglMesh->SetColor(1.0F, 1.0F, 1.0F, 0.0F); + tglResult = m_melems[meshIndex].m_tglMesh->SetColor(1.0F, 1.0F, 1.0F, 0.0F); + // clang-format off + assert(Succeeded( tglResult )); + // clang-format on + +#ifdef BETA10 + // This typecast is invalid, `textureInfo` had a different type in BETA10 + tglResult = m_melems[meshIndex].m_tglMesh->SetTexture((TglImpl::TextureImpl*) textureInfo); + // clang-format off + assert(Succeeded( tglResult )); + // clang-format on +#else LegoTextureInfo::SetGroupTexture(m_melems[meshIndex].m_tglMesh, textureInfo); +#endif + m_melems[meshIndex].m_textured = TRUE; } else { - LegoFloat red = 1.0F; - LegoFloat green = 0.0F; - LegoFloat blue = 1.0F; - LegoFloat alpha = 0.0F; + red = 1.0F; + // LINE: BETA10 0x1018db2d + green = 0.0F; + blue = 1.0F; + alpha = 0.0F; - if (mesh->GetUseAlias()) { + if (legoMesh->GetUseAlias()) { LegoROI::GetRGBAColor(materialName, red, green, blue, alpha); } else { - red = mesh->GetColor().GetRed() / 255.0; - green = mesh->GetColor().GetGreen() / 255.0; - blue = mesh->GetColor().GetBlue() / 255.0; - alpha = mesh->GetAlpha(); + red = legoMesh->GetColor().GetRed() / 255.0; + green = legoMesh->GetColor().GetGreen() / 255.0; + blue = legoMesh->GetColor().GetBlue() / 255.0; + alpha = legoMesh->GetAlpha(); } - m_melems[meshIndex].m_tglMesh->SetColor(red, green, blue, alpha); + tglResult = m_melems[meshIndex].m_tglMesh->SetColor(red, green, blue, alpha); + // clang-format off + // LINE: BETA10 0x1018dc72 + assert(Succeeded( tglResult )); + // clang-format on } - if (mesh->GetUnknown0x0d() > 0) { - IDirect3DRMMesh* mesh; - D3DRMGROUPINDEX index; - GetMeshData(mesh, index, m_melems[meshIndex].m_tglMesh); - mesh->SetGroupMaterial(index, g_unk0x101013d4); + if (legoMesh->GetUnknown0x0d() > 0) { + GetMeshData(&d3dmesh, &index, m_melems[meshIndex].m_tglMesh); + d3dmesh->SetGroupMaterial(index, g_lodMaterial); } - if (mesh != NULL) { - delete mesh; - mesh = NULL; + if (legoMesh != NULL) { + delete legoMesh; + legoMesh = NULL; } if (polyIndices != NULL) { delete[] polyIndices; @@ -265,6 +376,7 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text } } + // LINE: LEGO1 0x100aab45 m_meshOffset = indexForwards; if (textureVertices != NULL) { @@ -289,8 +401,8 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text if (textureVertices != NULL) { delete[] textureVertices; } - if (mesh != NULL) { - delete mesh; + if (legoMesh != NULL) { + delete legoMesh; } if (polyIndices != NULL) { delete[] polyIndices; @@ -303,6 +415,7 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text } // FUNCTION: LEGO1 0x100aabb0 +// FUNCTION: BETA10 0x1018e02a LegoLOD* LegoLOD::Clone(Tgl::Renderer* p_renderer) { LegoLOD* dupLod = new LegoLOD(p_renderer); @@ -310,6 +423,8 @@ LegoLOD* LegoLOD::Clone(Tgl::Renderer* p_renderer) dupLod->m_meshBuilder = m_meshBuilder->Clone(); dupLod->m_melems = new Mesh[m_numMeshes]; + assert(dupLod->m_melems); + for (LegoU32 i = 0; i < m_numMeshes; i++) { dupLod->m_melems[i].m_tglMesh = m_melems[i].m_tglMesh->ShallowClone(dupLod->m_meshBuilder); dupLod->m_melems[i].m_textured = m_melems[i].m_textured; @@ -337,11 +452,22 @@ LegoResult LegoLOD::SetColor(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blu } // FUNCTION: LEGO1 0x100aad00 +// FUNCTION: BETA10 0x1018e241 LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo) { + using Tgl::Succeeded; + for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) { if (m_melems[i].m_textured) { +#ifdef BETA10 + // This function likely had a different signature in BETA10 + Tgl::Result tglResult = m_melems[i].m_tglMesh->SetTexture((const Tgl::Texture*) p_textureInfo); + // clang-format off + assert(Succeeded( tglResult )); + // clang-format on +#else LegoTextureInfo::SetGroupTexture(m_melems[i].m_tglMesh, p_textureInfo); +#endif m_melems[i].m_tglMesh->SetColor(1.0F, 1.0F, 1.0F, 0.0F); m_melems[i].m_textured = TRUE; } @@ -351,11 +477,22 @@ LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo) } // FUNCTION: LEGO1 0x100aad70 +// FUNCTION: BETA10 0x1018e32c LegoResult LegoLOD::UpdateTextureInfo(LegoTextureInfo* p_textureInfo) { + using Tgl::Succeeded; + for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) { if (m_melems[i].m_textured) { +#ifdef BETA10 + // This function likely had a different signature in BETA10 + Tgl::Result tglResult = m_melems[i].m_tglMesh->SetTexture((const Tgl::Texture*) p_textureInfo); + // clang-format off + assert(Succeeded( tglResult )); + // clang-format on +#else LegoTextureInfo::SetGroupTexture(m_melems[i].m_tglMesh, p_textureInfo); +#endif } } @@ -377,15 +514,15 @@ LegoResult LegoLOD::GetTextureInfo(LegoTextureInfo*& p_textureInfo) } // FUNCTION: LEGO1 0x100aae20 +// FUNCTION: BETA10 0x1018e46d LegoBool LegoLOD::HasInhPrefix(const LegoChar* p_name) { - if (p_name != NULL) { - if (!strnicmp(p_name, g_InhPrefix, strlen(g_InhPrefix))) { - return TRUE; - } + if (p_name != NULL && !strnicmp(p_name, g_InhPrefix, strlen(g_InhPrefix))) { + return TRUE; + } + else { + return FALSE; } - - return FALSE; } // FUNCTION: LEGO1 0x100aae60 @@ -395,14 +532,31 @@ void LegoLOD::ClearMeshOffset() m_meshOffset = 0; } -inline BOOL GetMeshData(IDirect3DRMMesh*& mesh, D3DRMGROUPINDEX& index, Tgl::Mesh* pMesh) +// FUNCTION: BETA10 0x1018dfc4 +inline BOOL GetMeshData(IDirect3DRMMesh** mesh, D3DRMGROUPINDEX* index, Tgl::Mesh* p_tglElem) { - mesh = ((TglImpl::MeshImpl*) pMesh)->ImplementationData()->groupMesh; - index = ((TglImpl::MeshImpl*) pMesh)->ImplementationData()->groupIndex; + assert(p_tglElem); + TglImpl::MeshImpl* meshImpl = (TglImpl::MeshImpl*) p_tglElem; + // Note: Diff in BETA10 (thunked in recompile but not in orig) + *mesh = meshImpl->ImplementationData()->groupMesh; + *index = meshImpl->ImplementationData()->groupIndex; return FALSE; } -inline IDirect3DRM2* GetD3DRM(Tgl::Renderer* pRenderer) +#ifdef BETA10 +// FUNCTION: BETA10 0x1018cfc5 +inline BOOL GetD3DRM_legolod(IDirect3DRM2*& d3drm, Tgl::Renderer* p_tglRenderer) +{ + // Note: Code duplication with viewmanager.cpp:GetD3DRM() + assert(p_tglRenderer); + TglImpl::RendererImpl* renderer = (TglImpl::RendererImpl*) p_tglRenderer; + // Note: Diff in BETA10 (thunked in recompile but not in orig) + d3drm = renderer->ImplementationData(); + return 0; +} +#else +inline IDirect3DRM2* GetD3DRM_legolod(Tgl::Renderer* pRenderer) { return ((TglImpl::RendererImpl*) pRenderer)->ImplementationData(); } +#endif diff --git a/LEGO1/lego/sources/roi/legolod.h b/LEGO1/lego/sources/roi/legolod.h index e787d377..fa59d97c 100644 --- a/LEGO1/lego/sources/roi/legolod.h +++ b/LEGO1/lego/sources/roi/legolod.h @@ -9,6 +9,7 @@ class LegoTextureInfo; class LegoStorage; // VTABLE: LEGO1 0x100dbf10 +// VTABLE: BETA10 0x101c3978 // SIZE 0x20 class LegoLOD : public ViewLOD { public: @@ -22,9 +23,11 @@ class LegoLOD : public ViewLOD { ~LegoLOD() override; // FUNCTION: LEGO1 0x100aae70 + // FUNCTION: BETA10 0x1018e650 int NumPolys() const override { return m_numPolys; } // vtable+0x0c // FUNCTION: LEGO1 0x100aae80 + // FUNCTION: BETA10 0x1018e670 float VTable0x10() override { return 0.0; } // vtable+0x10 LegoResult Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage); @@ -38,6 +41,7 @@ class LegoLOD : public ViewLOD { static LegoBool HasInhPrefix(const LegoChar* p_name); // SYNTHETIC: LEGO1 0x100aa430 + // SYNTHETIC: BETA10 0x1018e530 // LegoLOD::`scalar deleting destructor' protected: diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp index fd1b6de6..575d1d83 100644 --- a/LEGO1/lego/sources/roi/legoroi.cpp +++ b/LEGO1/lego/sources/roi/legoroi.cpp @@ -56,6 +56,7 @@ const char* g_alwaysLoadNames[] = {"rcuser", "jsuser", "dunebugy", "chtrblad", " ColorOverride g_colorOverride = NULL; // GLOBAL: LEGO1 0x101013b0 +// GLOBAL: BETA10 0x10206f24 TextureHandler g_textureHandler = NULL; // FUNCTION: LEGO1 0x100a81b0 @@ -816,6 +817,7 @@ LegoBool LegoROI::ColorAliasLookup(const LegoChar* p_param, float& p_red, float& } // FUNCTION: LEGO1 0x100a9cf0 +// FUNCTION: BETA10 0x1018bead LegoBool LegoROI::GetPaletteEntries(const LegoChar* p_name, unsigned char* paletteEntries, LegoU32 p_numEntries) { if (p_name == NULL) { @@ -826,8 +828,10 @@ LegoBool LegoROI::GetPaletteEntries(const LegoChar* p_name, unsigned char* palet if (g_textureHandler != NULL) { return g_textureHandler(p_name, paletteEntries, p_numEntries); } + else { + paletteEntries[0] = '\0'; + } - paletteEntries[0] = '\0'; return FALSE; } diff --git a/LEGO1/lego/sources/shape/legocolor.cpp b/LEGO1/lego/sources/shape/legocolor.cpp index 69728742..ba52a7a7 100644 --- a/LEGO1/lego/sources/shape/legocolor.cpp +++ b/LEGO1/lego/sources/shape/legocolor.cpp @@ -6,6 +6,7 @@ DECOMP_SIZE_ASSERT(LegoColor, 0x03) // FUNCTION: LEGO1 0x100d3a20 +// FUNCTION: BETA10 0x10190730 LegoResult LegoColor::Read(LegoStorage* p_storage) { LegoResult result; diff --git a/LEGO1/lego/sources/shape/legocolor.h b/LEGO1/lego/sources/shape/legocolor.h index ac0f2ec0..9ae615f8 100644 --- a/LEGO1/lego/sources/shape/legocolor.h +++ b/LEGO1/lego/sources/shape/legocolor.h @@ -9,12 +9,22 @@ class LegoStorage; class LegoColor { public: LegoColor() { m_red = m_green = m_blue = 0; } + + // FUNCTION: BETA10 0x1018e690 LegoU8 GetRed() { return m_red; } + void SetRed(LegoU8 p_red) { m_red = p_red; } + + // FUNCTION: BETA10 0x1018e6b0 LegoU8 GetGreen() { return m_green; } + void SetGreen(LegoU8 p_green) { m_green = p_green; } + + // FUNCTION: BETA10 0x1018e6d0 LegoU8 GetBlue() { return m_blue; } + void SetBlue(LegoU8 p_blue) { m_blue = p_blue; } + LegoResult Read(LegoStorage* p_storage); protected: diff --git a/LEGO1/lego/sources/shape/legomesh.cpp b/LEGO1/lego/sources/shape/legomesh.cpp index 69dee797..b622dd3d 100644 --- a/LEGO1/lego/sources/shape/legomesh.cpp +++ b/LEGO1/lego/sources/shape/legomesh.cpp @@ -6,6 +6,7 @@ DECOMP_SIZE_ASSERT(LegoMeshUnkComponent, 0x1c) DECOMP_SIZE_ASSERT(LegoMesh, 0x24) // FUNCTION: LEGO1 0x100d3810 +// FUNCTION: BETA10 0x1018fd60 LegoMesh::LegoMesh() { m_alpha = 0.0F; @@ -20,6 +21,7 @@ LegoMesh::LegoMesh() } // FUNCTION: LEGO1 0x100d3860 +// FUNCTION: BETA10 0x1018fddb LegoMesh::~LegoMesh() { if (m_textureName != NULL) { @@ -36,6 +38,7 @@ LegoMesh::~LegoMesh() } // FUNCTION: LEGO1 0x100d38f0 +// FUNCTION: BETA10 0x1018ff5d LegoResult LegoMesh::Read(LegoStorage* p_storage) { LegoResult result; diff --git a/LEGO1/lego/sources/shape/legomesh.h b/LEGO1/lego/sources/shape/legomesh.h index 3092d7e4..ad0d5ce9 100644 --- a/LEGO1/lego/sources/shape/legomesh.h +++ b/LEGO1/lego/sources/shape/legomesh.h @@ -9,6 +9,7 @@ class LegoStorage; // SIZE 0x1c struct LegoMeshUnkComponent { + // FUNCTION: BETA10 0x101905b0 ~LegoMeshUnkComponent() { if (m_unk0x08) { @@ -36,7 +37,11 @@ struct LegoMeshUnkComponent { undefined* m_unk0x18; // 0x18 }; +// SYNTHETIC: BETA10 0x10190530 +// LegoMeshUnkComponent::`scalar deleting destructor' + // VTABLE: LEGO1 0x100dd228 +// VTABLE: BETA10 0x101c39c4 // SIZE 0x24 class LegoMesh { public: @@ -48,18 +53,36 @@ class LegoMesh { LegoMesh(); virtual ~LegoMesh(); + + // FUNCTION: BETA10 0x1018e6f0 LegoColor GetColor() { return m_color; } + void SetColor(LegoColor p_color) { m_color = p_color; } + + // FUNCTION: BETA10 0x1018e720 LegoFloat GetAlpha() { return m_alpha; } + + // FUNCTION: BETA10 0x1018e740 LegoU8 GetShading() { return m_shading; } + void SetShading(LegoU8 p_shading) { m_shading = p_shading; } + + // FUNCTION: BETA10 0x1018e760 LegoU8 GetUnknown0x0d() { return m_unk0x0d; } + + // FUNCTION: BETA10 0x1018e780 const LegoChar* GetTextureName() { return m_textureName; } + + // FUNCTION: BETA10 0x1018e7a0 const LegoChar* GetMaterialName() { return m_materialName; } + + // FUNCTION: BETA10 0x1018e7c0 LegoBool GetUseAlias() { return m_useAlias; } + LegoResult Read(LegoStorage* p_storage); // SYNTHETIC: LEGO1 0x100d3840 + // SYNTHETIC: BETA10 0x101904f0 // LegoMesh::`scalar deleting destructor' protected: diff --git a/LEGO1/library_msvc.h b/LEGO1/library_msvc.h index 5b4971d9..fd185a53 100644 --- a/LEGO1/library_msvc.h +++ b/LEGO1/library_msvc.h @@ -137,6 +137,7 @@ // ?__ArrayUnwind@@YGXPAXIHP6EX0@Z@Z // LIBRARY: LEGO1 0x1008c410 +// LIBRARY: BETA10 0x100fa340 // _strlwr // LIBRARY: LEGO1 0x1008c570 diff --git a/LEGO1/realtime/roi.h b/LEGO1/realtime/roi.h index 73e837d6..64964ad3 100644 --- a/LEGO1/realtime/roi.h +++ b/LEGO1/realtime/roi.h @@ -70,12 +70,14 @@ class BoundingSphere { * a geometric object. */ // VTABLE: LEGO1 0x100dbd90 +// VTABLE: BETA10 0x101c34c0 // SIZE 0x04 class LODObject { public: // LODObject(); // FUNCTION: LEGO1 0x100a6f00 + // FUNCTION: BETA10 0x10174c70 virtual ~LODObject() {} virtual double AveragePolyArea() const = 0; // vtable+0x04 @@ -84,9 +86,13 @@ class LODObject { virtual float VTable0x10() = 0; // vtable+0x10 // SYNTHETIC: LEGO1 0x100a6f10 + // SYNTHETIC: BETA10 0x10174c90 // LODObject::`scalar deleting destructor' }; +// SYNTHETIC: BETA10 0x1018e620 +// LODObject::LODObject + /* * A CompoundObject is simply a set of ROI objects which * all together represent a single object with sub-parts. diff --git a/LEGO1/viewmanager/viewlod.cpp b/LEGO1/viewmanager/viewlod.cpp index aa04813e..7cead057 100644 --- a/LEGO1/viewmanager/viewlod.cpp +++ b/LEGO1/viewmanager/viewlod.cpp @@ -1,7 +1,11 @@ #include "viewlod.h" // FUNCTION: LEGO1 0x100a5e40 +// FUNCTION: BETA10 0x10171bdf ViewLOD::~ViewLOD() { - delete m_meshBuilder; + if (m_meshBuilder) { + delete m_meshBuilder; + } + // something else happens on BETA10 here } diff --git a/LEGO1/viewmanager/viewlod.h b/LEGO1/viewmanager/viewlod.h index b7104526..fbf4f8bf 100644 --- a/LEGO1/viewmanager/viewlod.h +++ b/LEGO1/viewmanager/viewlod.h @@ -10,6 +10,7 @@ // // VTABLE: LEGO1 0x100dbd70 +// VTABLE: BETA10 0x101c34a8 // SIZE 0x0c class ViewLOD : public LODObject { public: @@ -17,25 +18,33 @@ class ViewLOD : public LODObject { c_hasMesh = 0x10 }; + // FUNCTION: BETA10 0x1018e570 ViewLOD(Tgl::Renderer* pRenderer) : m_meshBuilder(NULL), m_flags(3) {} + ~ViewLOD() override; // FUNCTION: LEGO1 0x100a6f30 + // FUNCTION: BETA10 0x10174db0 double AveragePolyArea() const override { return 2 * 3.14159 * 10.0 / NumPolys(); } // vtable+0x04 // FUNCTION: LEGO1 0x100a6f50 + // FUNCTION: BETA10 0x10174de0 int NVerts() const override { return NumPolys() * 2; } // vtable+0x08 Tgl::MeshBuilder* GetMeshBuilder() { return m_meshBuilder; } const Tgl::MeshBuilder* GetMeshBuilder() const { return m_meshBuilder; } unsigned int GetFlags() { return m_flags; } + + // FUNCTION: BETA10 0x1018e600 unsigned char SkipReadingData() { return m_flags & 0xffffff04; } + unsigned char IsExtraLOD() { return m_flags & 0xffffff08; } void SetFlag(unsigned char p_flag) { m_flags |= p_flag; } void ClearFlag(unsigned char p_flag) { m_flags &= ~p_flag; } // SYNTHETIC: LEGO1 0x100a6f60 + // SYNTHETIC: BETA10 0x10174f10 // ViewLOD::`scalar deleting destructor' protected: diff --git a/LEGO1/viewmanager/viewmanager.cpp b/LEGO1/viewmanager/viewmanager.cpp index 9bf1db44..fb48c623 100644 --- a/LEGO1/viewmanager/viewmanager.cpp +++ b/LEGO1/viewmanager/viewmanager.cpp @@ -35,7 +35,7 @@ float g_viewDistance = 0.000125F; float g_elapsedSeconds = 0; inline void SetAppData(ViewROI* p_roi, LPD3DRM_APPDATA data); -inline undefined4 GetD3DRM(IDirect3DRM2*& d3drm, Tgl::Renderer* pRenderer); +inline undefined4 GetD3DRM_viewmanager(IDirect3DRM2*& d3drm, Tgl::Renderer* pRenderer); inline undefined4 GetFrame(IDirect3DRMFrame2** frame, Tgl::Group* scene); // STUB: BETA10 0x1017202e @@ -64,7 +64,7 @@ ViewManager::ViewManager(Tgl::Renderer* pRenderer, Tgl::Group* scene, const Orie { SetPOVSource(point_of_view); prev_render_time = 0.09; - GetD3DRM(d3drm, pRenderer); + GetD3DRM_viewmanager(d3drm, pRenderer); GetFrame(&frame, scene); #ifdef BETA10 @@ -601,7 +601,7 @@ inline void SetAppData(ViewROI* p_roi, LPD3DRM_APPDATA data) } // FUNCTION: BETA10 0x10171f30 -inline undefined4 GetD3DRM(IDirect3DRM2*& d3drm, Tgl::Renderer* p_tglRenderer) +inline undefined4 GetD3DRM_viewmanager(IDirect3DRM2*& d3drm, Tgl::Renderer* p_tglRenderer) { assert(p_tglRenderer); TglImpl::RendererImpl* renderer = (TglImpl::RendererImpl*) p_tglRenderer; diff --git a/reccmp-project.yml b/reccmp-project.yml index 315674a3..94990d6b 100644 --- a/reccmp-project.yml +++ b/reccmp-project.yml @@ -28,6 +28,7 @@ targets: - LegoAct2 - LegoCarBuild - LegoCarBuildAnimPresenter + - LegoLOD - LegoRace - LegoWorld ignore-functions: diff --git a/util/decomp.h b/util/decomp.h index 673df553..86fbf09e 100644 --- a/util/decomp.h +++ b/util/decomp.h @@ -23,6 +23,12 @@ #define sizeOfArray(arr) (sizeof(arr) / sizeof(arr[0])) #endif +#ifdef BETA10 +#define assertIfBeta10(A) assert(A) +#else +#define assertIfBeta10(A) +#endif + typedef unsigned char undefined; typedef unsigned short undefined2; typedef unsigned int undefined4;