Beta match LegoLOD and related classes (#1704)
Some checks failed
Analyze / ${{ matrix.who }} annotations (CONFIG) (push) Has been cancelled
Analyze / ${{ matrix.who }} annotations (ISLE) (push) Has been cancelled
Analyze / ${{ matrix.who }} annotations (LEGO1) (push) Has been cancelled
Build / Download original binaries (push) Has been cancelled
Build / Current ${{ matrix.toolchain.name }} (map[clang-tidy:true msys-env:mingw-w64-i686 msystem:mingw32 name:msys2 mingw32 shell:msys2 {0} werror:true]) (push) Has been cancelled
Build / Current ${{ matrix.toolchain.name }} (map[name:MSVC setup-cmake:true setup-msvc:true setup-ninja:true shell:sh]) (push) Has been cancelled
Build / MSVC 4.20 (push) Has been cancelled
Build / MSVC 4.20 (BETA10) (push) Has been cancelled
Format / C++ (push) Has been cancelled
Naming / C++ (push) Has been cancelled
Build / Verify decomp (push) Has been cancelled
Build / Upload artifacts (push) Has been cancelled

* 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 <jonschz@users.noreply.github.com>
This commit is contained in:
jonschz 2026-01-05 23:45:36 +01:00 committed by GitHub
parent e9eb2493bb
commit af2418e61f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 280 additions and 54 deletions

View File

@ -13,19 +13,35 @@ DECOMP_SIZE_ASSERT(LegoLOD, 0x20)
DECOMP_SIZE_ASSERT(LegoLOD::Mesh, 0x08) DECOMP_SIZE_ASSERT(LegoLOD::Mesh, 0x08)
// GLOBAL: LEGO1 0x101013d4 // GLOBAL: LEGO1 0x101013d4
LPDIRECT3DRMMATERIAL g_unk0x101013d4 = NULL; // GLOBAL: BETA10 0x10207230
LPDIRECT3DRMMATERIAL g_lodMaterial = NULL;
// GLOBAL: LEGO1 0x101013dc // GLOBAL: LEGO1 0x101013dc
// GLOBAL: BETA10 0x10207238
const char* g_InhPrefix = "inh"; const char* g_InhPrefix = "inh";
inline IDirect3DRM2* GetD3DRM(Tgl::Renderer* pRenderer); #ifdef BETA10
inline BOOL GetMeshData(IDirect3DRMMesh*& mesh, D3DRMGROUPINDEX& index, Tgl::Mesh* pMesh); 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: LEGO1 0x100aa380
// FUNCTION: BETA10 0x1018ce90
LegoLOD::LegoLOD(Tgl::Renderer* p_renderer) : ViewLOD(p_renderer) LegoLOD::LegoLOD(Tgl::Renderer* p_renderer) : ViewLOD(p_renderer)
{ {
if (g_unk0x101013d4 == NULL) { if (g_lodMaterial == NULL) {
GetD3DRM(p_renderer)->CreateMaterial(10.0, &g_unk0x101013d4); #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; m_melems = NULL;
@ -36,6 +52,7 @@ LegoLOD::LegoLOD(Tgl::Renderer* p_renderer) : ViewLOD(p_renderer)
} }
// FUNCTION: LEGO1 0x100aa450 // FUNCTION: LEGO1 0x100aa450
// FUNCTION: BETA10 0x1018d017
LegoLOD::~LegoLOD() LegoLOD::~LegoLOD()
{ {
if (m_numMeshes && m_melems != NULL) { 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: LEGO1 0x100aa510
// FUNCTION: BETA10 0x1018d15d
LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage) LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage)
{ {
using Tgl::Succeeded;
float(*normals)[3] = NULL; float(*normals)[3] = NULL;
float(*vertices)[3] = NULL; float(*vertices)[3] = NULL;
float(*textureVertices)[2] = NULL; float(*textureVertices)[2] = NULL;
LegoS32 numVerts = 0; LegoS32 numVerts = 0;
LegoS32 numNormals = 0; LegoS32 numNormals = 0;
LegoS32 numTextureVertices = 0; LegoS32 numTextureVertices = 0;
LegoMesh* mesh = NULL; LegoMesh* legoMesh = NULL;
LegoU32(*polyIndices)[3] = NULL; LegoU32(*polyIndices)[3] = NULL;
LegoU32(*textureIndices)[3] = NULL; LegoU32(*textureIndices)[3] = NULL;
LegoTextureInfo* textureInfo = NULL; LegoTextureInfo* textureInfo = NULL;
LegoU8 local4c = 0; // BETA10 only, only written, never read
LegoU32 numPolys, numVertices, numTextureIndices, meshIndex;
LegoU32 i, indexBackwards, indexForwards, tempNumVertsAndNormals; LegoU32 i, indexBackwards, indexForwards, tempNumVertsAndNormals;
LegoFloat red, green, blue, alpha;
IDirect3DRMMesh* d3dmesh;
D3DRMGROUPINDEX index;
unsigned char paletteEntries[256]; unsigned char paletteEntries[256];
if (p_storage->Read(&m_flags, sizeof(LegoU32)) != SUCCESS) { 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()) { 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; return SUCCESS;
} }
@ -84,11 +147,15 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
} }
if (m_numMeshes == 0) { if (m_numMeshes == 0) {
#ifndef BETA10
ClearFlag(c_hasMesh); ClearFlag(c_hasMesh);
#endif
return SUCCESS; return SUCCESS;
} }
#ifndef BETA10
SetFlag(c_hasMesh); SetFlag(c_hasMesh);
#endif
m_melems = new Mesh[m_numMeshes]; m_melems = new Mesh[m_numMeshes];
memset(m_melems, 0, sizeof(*m_melems) * 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; indexForwards = 0;
if (p_storage->Read(&tempNumVertsAndNormals, sizeof(LegoU32)) != SUCCESS) { if (p_storage->Read(&tempNumVertsAndNormals, sizeof(LegoU32)) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
// TODO: Can't get this one right
numVerts = *((LegoU16*) &tempNumVertsAndNormals) & MAXSHORT; numVerts = *((LegoU16*) &tempNumVertsAndNormals) & MAXSHORT;
numNormals = (*((LegoU16*) &tempNumVertsAndNormals + 1) >> 1) & MAXSHORT; numNormals = (*((LegoU16*) &tempNumVertsAndNormals + 1) >> 1) & MAXSHORT;
if (p_storage->Read(&numTextureVertices, sizeof(LegoS32)) != SUCCESS) { if (p_storage->Read(&numTextureVertices, sizeof(LegoS32)) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
if (numVerts > 0) { if (numVerts > 0) {
vertices = new float[numVerts][sizeOfArray(*vertices)]; vertices = new float[numVerts][sizeOfArray(*vertices)];
if (p_storage->Read(vertices, numVerts * 3 * sizeof(float)) != SUCCESS) { if (p_storage->Read(vertices, numVerts * 3 * sizeof(float)) != SUCCESS) {
// LINE: BETA10 0x1018d443
assertIfBeta10(0);
goto done; goto done;
} }
} }
@ -117,6 +189,7 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
if (numNormals > 0) { if (numNormals > 0) {
normals = new float[numNormals][sizeOfArray(*normals)]; normals = new float[numNormals][sizeOfArray(*normals)];
if (p_storage->Read(normals, numNormals * 3 * sizeof(float)) != SUCCESS) { if (p_storage->Read(normals, numNormals * 3 * sizeof(float)) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
} }
@ -124,37 +197,44 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
if (numTextureVertices > 0) { if (numTextureVertices > 0) {
textureVertices = new float[numTextureVertices][sizeOfArray(*textureVertices)]; textureVertices = new float[numTextureVertices][sizeOfArray(*textureVertices)];
if (p_storage->Read(textureVertices, numTextureVertices * 2 * sizeof(float)) != SUCCESS) { if (p_storage->Read(textureVertices, numTextureVertices * 2 * sizeof(float)) != SUCCESS) {
// LINE: BETA10 0x1018d513
assertIfBeta10(0);
goto done; goto done;
} }
} }
for (i = 0; i < m_numMeshes; i++) { for (i = 0; i < m_numMeshes; i++) {
LegoU32 numPolys, numVertices, numTextureIndices, meshIndex; local4c = 0;
const LegoChar *textureName, *materialName; const LegoChar *textureName, *materialName;
Tgl::ShadingModel shadingModel; Tgl::ShadingModel shadingModel;
if (p_storage->Read(&numPolys, 2) != SUCCESS) { if (p_storage->Read(&numPolys, 2) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
m_numPolys += numPolys & USHRT_MAX; m_numPolys += numPolys & USHRT_MAX;
if (p_storage->Read(&numVertices, 2) != SUCCESS) { if (p_storage->Read(&numVertices, 2) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
polyIndices = new LegoU32[numPolys & USHRT_MAX][sizeOfArray(*polyIndices)]; polyIndices = new LegoU32[numPolys & USHRT_MAX][sizeOfArray(*polyIndices)];
if (p_storage->Read(polyIndices, (numPolys & USHRT_MAX) * 3 * sizeof(LegoU32)) != SUCCESS) { if (p_storage->Read(polyIndices, (numPolys & USHRT_MAX) * 3 * sizeof(LegoU32)) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
if (p_storage->Read(&numTextureIndices, sizeof(numTextureIndices)) != SUCCESS) { if (p_storage->Read(&numTextureIndices, sizeof(numTextureIndices)) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
if (numTextureIndices > 0) { if (numTextureIndices > 0) {
textureIndices = new LegoU32[numPolys & USHRT_MAX][sizeOfArray(*textureIndices)]; textureIndices = new LegoU32[numPolys & USHRT_MAX][sizeOfArray(*textureIndices)];
if (p_storage->Read(textureIndices, (numPolys & USHRT_MAX) * 3 * sizeof(LegoU32)) != SUCCESS) { if (p_storage->Read(textureIndices, (numPolys & USHRT_MAX) * 3 * sizeof(LegoU32)) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
} }
@ -162,13 +242,14 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
textureIndices = NULL; textureIndices = NULL;
} }
mesh = new LegoMesh(); legoMesh = new LegoMesh();
if (mesh->Read(p_storage) != SUCCESS) { if (legoMesh->Read(p_storage) != SUCCESS) {
assertIfBeta10(0);
goto done; goto done;
} }
switch (mesh->GetShading()) { switch (legoMesh->GetShading()) {
case LegoMesh::e_flat: case LegoMesh::e_flat:
shadingModel = Tgl::Flat; shadingModel = Tgl::Flat;
break; break;
@ -181,19 +262,23 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
m_numVertices += numVertices & USHRT_MAX; m_numVertices += numVertices & USHRT_MAX;
textureName = mesh->GetTextureName(); textureName = legoMesh->GetTextureName();
materialName = mesh->GetMaterialName(); materialName = legoMesh->GetMaterialName();
if (HasInhPrefix(textureName) || HasInhPrefix(materialName)) { if (HasInhPrefix(textureName) || HasInhPrefix(materialName)) {
meshIndex = indexBackwards; meshIndex = indexBackwards;
indexBackwards--; indexBackwards--;
} }
else { else {
local4c = 1;
meshIndex = indexForwards; meshIndex = indexForwards;
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, numPolys & USHRT_MAX,
numVertices & USHRT_MAX, numVertices & USHRT_MAX,
vertices, vertices,
@ -202,58 +287,84 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
polyIndices, polyIndices,
textureIndices, textureIndices,
shadingModel shadingModel
// LINE: LEGO1 0x100aa885
); );
if (m_melems[meshIndex].m_tglMesh == NULL) { if (m_melems[meshIndex].m_tglMesh == NULL) {
assertIfBeta10(0);
goto done; 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 (textureName != NULL) {
if (mesh->GetUseAlias()) { if (legoMesh->GetUseAlias() &&
LegoROI::GetPaletteEntries(textureName, paletteEntries, sizeOfArray(paletteEntries)); 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) { if (textureInfo == NULL) {
assertIfBeta10(0);
goto done; 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); LegoTextureInfo::SetGroupTexture(m_melems[meshIndex].m_tglMesh, textureInfo);
#endif
m_melems[meshIndex].m_textured = TRUE; m_melems[meshIndex].m_textured = TRUE;
} }
else { else {
LegoFloat red = 1.0F; red = 1.0F;
LegoFloat green = 0.0F; // LINE: BETA10 0x1018db2d
LegoFloat blue = 1.0F; green = 0.0F;
LegoFloat alpha = 0.0F; blue = 1.0F;
alpha = 0.0F;
if (mesh->GetUseAlias()) { if (legoMesh->GetUseAlias()) {
LegoROI::GetRGBAColor(materialName, red, green, blue, alpha); LegoROI::GetRGBAColor(materialName, red, green, blue, alpha);
} }
else { else {
red = mesh->GetColor().GetRed() / 255.0; red = legoMesh->GetColor().GetRed() / 255.0;
green = mesh->GetColor().GetGreen() / 255.0; green = legoMesh->GetColor().GetGreen() / 255.0;
blue = mesh->GetColor().GetBlue() / 255.0; blue = legoMesh->GetColor().GetBlue() / 255.0;
alpha = mesh->GetAlpha(); 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) { if (legoMesh->GetUnknown0x0d() > 0) {
IDirect3DRMMesh* mesh; GetMeshData(&d3dmesh, &index, m_melems[meshIndex].m_tglMesh);
D3DRMGROUPINDEX index; d3dmesh->SetGroupMaterial(index, g_lodMaterial);
GetMeshData(mesh, index, m_melems[meshIndex].m_tglMesh);
mesh->SetGroupMaterial(index, g_unk0x101013d4);
} }
if (mesh != NULL) { if (legoMesh != NULL) {
delete mesh; delete legoMesh;
mesh = NULL; legoMesh = NULL;
} }
if (polyIndices != NULL) { if (polyIndices != NULL) {
delete[] polyIndices; delete[] polyIndices;
@ -265,6 +376,7 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
} }
} }
// LINE: LEGO1 0x100aab45
m_meshOffset = indexForwards; m_meshOffset = indexForwards;
if (textureVertices != NULL) { if (textureVertices != NULL) {
@ -289,8 +401,8 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
if (textureVertices != NULL) { if (textureVertices != NULL) {
delete[] textureVertices; delete[] textureVertices;
} }
if (mesh != NULL) { if (legoMesh != NULL) {
delete mesh; delete legoMesh;
} }
if (polyIndices != NULL) { if (polyIndices != NULL) {
delete[] polyIndices; delete[] polyIndices;
@ -303,6 +415,7 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text
} }
// FUNCTION: LEGO1 0x100aabb0 // FUNCTION: LEGO1 0x100aabb0
// FUNCTION: BETA10 0x1018e02a
LegoLOD* LegoLOD::Clone(Tgl::Renderer* p_renderer) LegoLOD* LegoLOD::Clone(Tgl::Renderer* p_renderer)
{ {
LegoLOD* dupLod = new LegoLOD(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_meshBuilder = m_meshBuilder->Clone();
dupLod->m_melems = new Mesh[m_numMeshes]; dupLod->m_melems = new Mesh[m_numMeshes];
assert(dupLod->m_melems);
for (LegoU32 i = 0; i < m_numMeshes; i++) { 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_tglMesh = m_melems[i].m_tglMesh->ShallowClone(dupLod->m_meshBuilder);
dupLod->m_melems[i].m_textured = m_melems[i].m_textured; 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: LEGO1 0x100aad00
// FUNCTION: BETA10 0x1018e241
LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo) LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo)
{ {
using Tgl::Succeeded;
for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) { for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) {
if (m_melems[i].m_textured) { 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); 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_tglMesh->SetColor(1.0F, 1.0F, 1.0F, 0.0F);
m_melems[i].m_textured = TRUE; m_melems[i].m_textured = TRUE;
} }
@ -351,11 +477,22 @@ LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo)
} }
// FUNCTION: LEGO1 0x100aad70 // FUNCTION: LEGO1 0x100aad70
// FUNCTION: BETA10 0x1018e32c
LegoResult LegoLOD::UpdateTextureInfo(LegoTextureInfo* p_textureInfo) LegoResult LegoLOD::UpdateTextureInfo(LegoTextureInfo* p_textureInfo)
{ {
using Tgl::Succeeded;
for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) { for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) {
if (m_melems[i].m_textured) { 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); LegoTextureInfo::SetGroupTexture(m_melems[i].m_tglMesh, p_textureInfo);
#endif
} }
} }
@ -377,15 +514,15 @@ LegoResult LegoLOD::GetTextureInfo(LegoTextureInfo*& p_textureInfo)
} }
// FUNCTION: LEGO1 0x100aae20 // FUNCTION: LEGO1 0x100aae20
// FUNCTION: BETA10 0x1018e46d
LegoBool LegoLOD::HasInhPrefix(const LegoChar* p_name) LegoBool LegoLOD::HasInhPrefix(const LegoChar* p_name)
{ {
if (p_name != NULL) { if (p_name != NULL && !strnicmp(p_name, g_InhPrefix, strlen(g_InhPrefix))) {
if (!strnicmp(p_name, g_InhPrefix, strlen(g_InhPrefix))) { return TRUE;
return TRUE; }
} else {
return FALSE;
} }
return FALSE;
} }
// FUNCTION: LEGO1 0x100aae60 // FUNCTION: LEGO1 0x100aae60
@ -395,14 +532,31 @@ void LegoLOD::ClearMeshOffset()
m_meshOffset = 0; 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; assert(p_tglElem);
index = ((TglImpl::MeshImpl*) pMesh)->ImplementationData()->groupIndex; 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; 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(); return ((TglImpl::RendererImpl*) pRenderer)->ImplementationData();
} }
#endif

View File

@ -9,6 +9,7 @@ class LegoTextureInfo;
class LegoStorage; class LegoStorage;
// VTABLE: LEGO1 0x100dbf10 // VTABLE: LEGO1 0x100dbf10
// VTABLE: BETA10 0x101c3978
// SIZE 0x20 // SIZE 0x20
class LegoLOD : public ViewLOD { class LegoLOD : public ViewLOD {
public: public:
@ -22,9 +23,11 @@ class LegoLOD : public ViewLOD {
~LegoLOD() override; ~LegoLOD() override;
// FUNCTION: LEGO1 0x100aae70 // FUNCTION: LEGO1 0x100aae70
// FUNCTION: BETA10 0x1018e650
int NumPolys() const override { return m_numPolys; } // vtable+0x0c int NumPolys() const override { return m_numPolys; } // vtable+0x0c
// FUNCTION: LEGO1 0x100aae80 // FUNCTION: LEGO1 0x100aae80
// FUNCTION: BETA10 0x1018e670
float VTable0x10() override { return 0.0; } // vtable+0x10 float VTable0x10() override { return 0.0; } // vtable+0x10
LegoResult Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage); 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); static LegoBool HasInhPrefix(const LegoChar* p_name);
// SYNTHETIC: LEGO1 0x100aa430 // SYNTHETIC: LEGO1 0x100aa430
// SYNTHETIC: BETA10 0x1018e530
// LegoLOD::`scalar deleting destructor' // LegoLOD::`scalar deleting destructor'
protected: protected:

View File

@ -56,6 +56,7 @@ const char* g_alwaysLoadNames[] = {"rcuser", "jsuser", "dunebugy", "chtrblad", "
ColorOverride g_colorOverride = NULL; ColorOverride g_colorOverride = NULL;
// GLOBAL: LEGO1 0x101013b0 // GLOBAL: LEGO1 0x101013b0
// GLOBAL: BETA10 0x10206f24
TextureHandler g_textureHandler = NULL; TextureHandler g_textureHandler = NULL;
// FUNCTION: LEGO1 0x100a81b0 // FUNCTION: LEGO1 0x100a81b0
@ -816,6 +817,7 @@ LegoBool LegoROI::ColorAliasLookup(const LegoChar* p_param, float& p_red, float&
} }
// FUNCTION: LEGO1 0x100a9cf0 // FUNCTION: LEGO1 0x100a9cf0
// FUNCTION: BETA10 0x1018bead
LegoBool LegoROI::GetPaletteEntries(const LegoChar* p_name, unsigned char* paletteEntries, LegoU32 p_numEntries) LegoBool LegoROI::GetPaletteEntries(const LegoChar* p_name, unsigned char* paletteEntries, LegoU32 p_numEntries)
{ {
if (p_name == NULL) { if (p_name == NULL) {
@ -826,8 +828,10 @@ LegoBool LegoROI::GetPaletteEntries(const LegoChar* p_name, unsigned char* palet
if (g_textureHandler != NULL) { if (g_textureHandler != NULL) {
return g_textureHandler(p_name, paletteEntries, p_numEntries); return g_textureHandler(p_name, paletteEntries, p_numEntries);
} }
else {
paletteEntries[0] = '\0';
}
paletteEntries[0] = '\0';
return FALSE; return FALSE;
} }

View File

@ -6,6 +6,7 @@
DECOMP_SIZE_ASSERT(LegoColor, 0x03) DECOMP_SIZE_ASSERT(LegoColor, 0x03)
// FUNCTION: LEGO1 0x100d3a20 // FUNCTION: LEGO1 0x100d3a20
// FUNCTION: BETA10 0x10190730
LegoResult LegoColor::Read(LegoStorage* p_storage) LegoResult LegoColor::Read(LegoStorage* p_storage)
{ {
LegoResult result; LegoResult result;

View File

@ -9,12 +9,22 @@ class LegoStorage;
class LegoColor { class LegoColor {
public: public:
LegoColor() { m_red = m_green = m_blue = 0; } LegoColor() { m_red = m_green = m_blue = 0; }
// FUNCTION: BETA10 0x1018e690
LegoU8 GetRed() { return m_red; } LegoU8 GetRed() { return m_red; }
void SetRed(LegoU8 p_red) { m_red = p_red; } void SetRed(LegoU8 p_red) { m_red = p_red; }
// FUNCTION: BETA10 0x1018e6b0
LegoU8 GetGreen() { return m_green; } LegoU8 GetGreen() { return m_green; }
void SetGreen(LegoU8 p_green) { m_green = p_green; } void SetGreen(LegoU8 p_green) { m_green = p_green; }
// FUNCTION: BETA10 0x1018e6d0
LegoU8 GetBlue() { return m_blue; } LegoU8 GetBlue() { return m_blue; }
void SetBlue(LegoU8 p_blue) { m_blue = p_blue; } void SetBlue(LegoU8 p_blue) { m_blue = p_blue; }
LegoResult Read(LegoStorage* p_storage); LegoResult Read(LegoStorage* p_storage);
protected: protected:

View File

@ -6,6 +6,7 @@ DECOMP_SIZE_ASSERT(LegoMeshUnkComponent, 0x1c)
DECOMP_SIZE_ASSERT(LegoMesh, 0x24) DECOMP_SIZE_ASSERT(LegoMesh, 0x24)
// FUNCTION: LEGO1 0x100d3810 // FUNCTION: LEGO1 0x100d3810
// FUNCTION: BETA10 0x1018fd60
LegoMesh::LegoMesh() LegoMesh::LegoMesh()
{ {
m_alpha = 0.0F; m_alpha = 0.0F;
@ -20,6 +21,7 @@ LegoMesh::LegoMesh()
} }
// FUNCTION: LEGO1 0x100d3860 // FUNCTION: LEGO1 0x100d3860
// FUNCTION: BETA10 0x1018fddb
LegoMesh::~LegoMesh() LegoMesh::~LegoMesh()
{ {
if (m_textureName != NULL) { if (m_textureName != NULL) {
@ -36,6 +38,7 @@ LegoMesh::~LegoMesh()
} }
// FUNCTION: LEGO1 0x100d38f0 // FUNCTION: LEGO1 0x100d38f0
// FUNCTION: BETA10 0x1018ff5d
LegoResult LegoMesh::Read(LegoStorage* p_storage) LegoResult LegoMesh::Read(LegoStorage* p_storage)
{ {
LegoResult result; LegoResult result;

View File

@ -9,6 +9,7 @@ class LegoStorage;
// SIZE 0x1c // SIZE 0x1c
struct LegoMeshUnkComponent { struct LegoMeshUnkComponent {
// FUNCTION: BETA10 0x101905b0
~LegoMeshUnkComponent() ~LegoMeshUnkComponent()
{ {
if (m_unk0x08) { if (m_unk0x08) {
@ -36,7 +37,11 @@ struct LegoMeshUnkComponent {
undefined* m_unk0x18; // 0x18 undefined* m_unk0x18; // 0x18
}; };
// SYNTHETIC: BETA10 0x10190530
// LegoMeshUnkComponent::`scalar deleting destructor'
// VTABLE: LEGO1 0x100dd228 // VTABLE: LEGO1 0x100dd228
// VTABLE: BETA10 0x101c39c4
// SIZE 0x24 // SIZE 0x24
class LegoMesh { class LegoMesh {
public: public:
@ -48,18 +53,36 @@ class LegoMesh {
LegoMesh(); LegoMesh();
virtual ~LegoMesh(); virtual ~LegoMesh();
// FUNCTION: BETA10 0x1018e6f0
LegoColor GetColor() { return m_color; } LegoColor GetColor() { return m_color; }
void SetColor(LegoColor p_color) { m_color = p_color; } void SetColor(LegoColor p_color) { m_color = p_color; }
// FUNCTION: BETA10 0x1018e720
LegoFloat GetAlpha() { return m_alpha; } LegoFloat GetAlpha() { return m_alpha; }
// FUNCTION: BETA10 0x1018e740
LegoU8 GetShading() { return m_shading; } LegoU8 GetShading() { return m_shading; }
void SetShading(LegoU8 p_shading) { m_shading = p_shading; } void SetShading(LegoU8 p_shading) { m_shading = p_shading; }
// FUNCTION: BETA10 0x1018e760
LegoU8 GetUnknown0x0d() { return m_unk0x0d; } LegoU8 GetUnknown0x0d() { return m_unk0x0d; }
// FUNCTION: BETA10 0x1018e780
const LegoChar* GetTextureName() { return m_textureName; } const LegoChar* GetTextureName() { return m_textureName; }
// FUNCTION: BETA10 0x1018e7a0
const LegoChar* GetMaterialName() { return m_materialName; } const LegoChar* GetMaterialName() { return m_materialName; }
// FUNCTION: BETA10 0x1018e7c0
LegoBool GetUseAlias() { return m_useAlias; } LegoBool GetUseAlias() { return m_useAlias; }
LegoResult Read(LegoStorage* p_storage); LegoResult Read(LegoStorage* p_storage);
// SYNTHETIC: LEGO1 0x100d3840 // SYNTHETIC: LEGO1 0x100d3840
// SYNTHETIC: BETA10 0x101904f0
// LegoMesh::`scalar deleting destructor' // LegoMesh::`scalar deleting destructor'
protected: protected:

View File

@ -137,6 +137,7 @@
// ?__ArrayUnwind@@YGXPAXIHP6EX0@Z@Z // ?__ArrayUnwind@@YGXPAXIHP6EX0@Z@Z
// LIBRARY: LEGO1 0x1008c410 // LIBRARY: LEGO1 0x1008c410
// LIBRARY: BETA10 0x100fa340
// _strlwr // _strlwr
// LIBRARY: LEGO1 0x1008c570 // LIBRARY: LEGO1 0x1008c570

View File

@ -70,12 +70,14 @@ class BoundingSphere {
* a geometric object. * a geometric object.
*/ */
// VTABLE: LEGO1 0x100dbd90 // VTABLE: LEGO1 0x100dbd90
// VTABLE: BETA10 0x101c34c0
// SIZE 0x04 // SIZE 0x04
class LODObject { class LODObject {
public: public:
// LODObject(); // LODObject();
// FUNCTION: LEGO1 0x100a6f00 // FUNCTION: LEGO1 0x100a6f00
// FUNCTION: BETA10 0x10174c70
virtual ~LODObject() {} virtual ~LODObject() {}
virtual double AveragePolyArea() const = 0; // vtable+0x04 virtual double AveragePolyArea() const = 0; // vtable+0x04
@ -84,9 +86,13 @@ class LODObject {
virtual float VTable0x10() = 0; // vtable+0x10 virtual float VTable0x10() = 0; // vtable+0x10
// SYNTHETIC: LEGO1 0x100a6f10 // SYNTHETIC: LEGO1 0x100a6f10
// SYNTHETIC: BETA10 0x10174c90
// LODObject::`scalar deleting destructor' // LODObject::`scalar deleting destructor'
}; };
// SYNTHETIC: BETA10 0x1018e620
// LODObject::LODObject
/* /*
* A CompoundObject is simply a set of ROI objects which * A CompoundObject is simply a set of ROI objects which
* all together represent a single object with sub-parts. * all together represent a single object with sub-parts.

View File

@ -1,7 +1,11 @@
#include "viewlod.h" #include "viewlod.h"
// FUNCTION: LEGO1 0x100a5e40 // FUNCTION: LEGO1 0x100a5e40
// FUNCTION: BETA10 0x10171bdf
ViewLOD::~ViewLOD() ViewLOD::~ViewLOD()
{ {
delete m_meshBuilder; if (m_meshBuilder) {
delete m_meshBuilder;
}
// something else happens on BETA10 here
} }

View File

@ -10,6 +10,7 @@
// //
// VTABLE: LEGO1 0x100dbd70 // VTABLE: LEGO1 0x100dbd70
// VTABLE: BETA10 0x101c34a8
// SIZE 0x0c // SIZE 0x0c
class ViewLOD : public LODObject { class ViewLOD : public LODObject {
public: public:
@ -17,25 +18,33 @@ class ViewLOD : public LODObject {
c_hasMesh = 0x10 c_hasMesh = 0x10
}; };
// FUNCTION: BETA10 0x1018e570
ViewLOD(Tgl::Renderer* pRenderer) : m_meshBuilder(NULL), m_flags(3) {} ViewLOD(Tgl::Renderer* pRenderer) : m_meshBuilder(NULL), m_flags(3) {}
~ViewLOD() override; ~ViewLOD() override;
// FUNCTION: LEGO1 0x100a6f30 // FUNCTION: LEGO1 0x100a6f30
// FUNCTION: BETA10 0x10174db0
double AveragePolyArea() const override { return 2 * 3.14159 * 10.0 / NumPolys(); } // vtable+0x04 double AveragePolyArea() const override { return 2 * 3.14159 * 10.0 / NumPolys(); } // vtable+0x04
// FUNCTION: LEGO1 0x100a6f50 // FUNCTION: LEGO1 0x100a6f50
// FUNCTION: BETA10 0x10174de0
int NVerts() const override { return NumPolys() * 2; } // vtable+0x08 int NVerts() const override { return NumPolys() * 2; } // vtable+0x08
Tgl::MeshBuilder* GetMeshBuilder() { return m_meshBuilder; } Tgl::MeshBuilder* GetMeshBuilder() { return m_meshBuilder; }
const Tgl::MeshBuilder* GetMeshBuilder() const { return m_meshBuilder; } const Tgl::MeshBuilder* GetMeshBuilder() const { return m_meshBuilder; }
unsigned int GetFlags() { return m_flags; } unsigned int GetFlags() { return m_flags; }
// FUNCTION: BETA10 0x1018e600
unsigned char SkipReadingData() { return m_flags & 0xffffff04; } unsigned char SkipReadingData() { return m_flags & 0xffffff04; }
unsigned char IsExtraLOD() { return m_flags & 0xffffff08; } unsigned char IsExtraLOD() { return m_flags & 0xffffff08; }
void SetFlag(unsigned char p_flag) { m_flags |= p_flag; } void SetFlag(unsigned char p_flag) { m_flags |= p_flag; }
void ClearFlag(unsigned char p_flag) { m_flags &= ~p_flag; } void ClearFlag(unsigned char p_flag) { m_flags &= ~p_flag; }
// SYNTHETIC: LEGO1 0x100a6f60 // SYNTHETIC: LEGO1 0x100a6f60
// SYNTHETIC: BETA10 0x10174f10
// ViewLOD::`scalar deleting destructor' // ViewLOD::`scalar deleting destructor'
protected: protected:

View File

@ -35,7 +35,7 @@ float g_viewDistance = 0.000125F;
float g_elapsedSeconds = 0; float g_elapsedSeconds = 0;
inline void SetAppData(ViewROI* p_roi, LPD3DRM_APPDATA data); 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); inline undefined4 GetFrame(IDirect3DRMFrame2** frame, Tgl::Group* scene);
// STUB: BETA10 0x1017202e // STUB: BETA10 0x1017202e
@ -64,7 +64,7 @@ ViewManager::ViewManager(Tgl::Renderer* pRenderer, Tgl::Group* scene, const Orie
{ {
SetPOVSource(point_of_view); SetPOVSource(point_of_view);
prev_render_time = 0.09; prev_render_time = 0.09;
GetD3DRM(d3drm, pRenderer); GetD3DRM_viewmanager(d3drm, pRenderer);
GetFrame(&frame, scene); GetFrame(&frame, scene);
#ifdef BETA10 #ifdef BETA10
@ -601,7 +601,7 @@ inline void SetAppData(ViewROI* p_roi, LPD3DRM_APPDATA data)
} }
// FUNCTION: BETA10 0x10171f30 // 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); assert(p_tglRenderer);
TglImpl::RendererImpl* renderer = (TglImpl::RendererImpl*) p_tglRenderer; TglImpl::RendererImpl* renderer = (TglImpl::RendererImpl*) p_tglRenderer;

View File

@ -28,6 +28,7 @@ targets:
- LegoAct2 - LegoAct2
- LegoCarBuild - LegoCarBuild
- LegoCarBuildAnimPresenter - LegoCarBuildAnimPresenter
- LegoLOD
- LegoRace - LegoRace
- LegoWorld - LegoWorld
ignore-functions: ignore-functions:

View File

@ -23,6 +23,12 @@
#define sizeOfArray(arr) (sizeof(arr) / sizeof(arr[0])) #define sizeOfArray(arr) (sizeof(arr) / sizeof(arr[0]))
#endif #endif
#ifdef BETA10
#define assertIfBeta10(A) assert(A)
#else
#define assertIfBeta10(A)
#endif
typedef unsigned char undefined; typedef unsigned char undefined;
typedef unsigned short undefined2; typedef unsigned short undefined2;
typedef unsigned int undefined4; typedef unsigned int undefined4;