From b281866ea6068b853a7b8bba67f105d309b249c7 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 24 Feb 2024 11:48:16 -0500 Subject: [PATCH] Implement/match LegoModelPresenter::CreateROI (#591) * Implement/match LegoModelPresenter::CreateROI * Match * Use inline function * Note about Get() --- LEGO1/lego/legoomni/include/legoomni.h | 2 + LEGO1/lego/legoomni/src/main/legoomni.cpp | 6 + .../legoomni/src/video/legomodelpresenter.cpp | 154 +++++++++++++++++- LEGO1/lego/sources/misc/legocontainer.cpp | 4 +- LEGO1/lego/sources/misc/legocontainer.h | 42 ++++- LEGO1/lego/sources/misc/legostorage.cpp | 14 -- LEGO1/lego/sources/misc/legostorage.h | 16 +- LEGO1/lego/sources/misc/version.h | 2 +- LEGO1/lego/sources/roi/legoroi.cpp | 18 ++ LEGO1/lego/sources/roi/legoroi.h | 12 ++ LEGO1/mxdirectx/mxdirect3d.h | 1 + LEGO1/mxgeometry/mxgeometry3d.h | 4 + 12 files changed, 248 insertions(+), 27 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoomni.h b/LEGO1/lego/legoomni/include/legoomni.h index a8b27b4d..c66df6fc 100644 --- a/LEGO1/lego/legoomni/include/legoomni.h +++ b/LEGO1/lego/legoomni/include/legoomni.h @@ -213,6 +213,7 @@ class LegoOmni : public MxOmni { LegoSoundManager* GetSoundManager() { return (LegoSoundManager*) m_soundManager; } LegoInputManager* GetInputManager() { return m_inputManager; } LegoTextureContainer* GetTextureContainer() { return m_textureContainer; } + ViewLODListManager* GetViewLODListManager() { return m_viewLODListManager; } LegoWorld* GetCurrentWorld() { return m_currentWorld; } LegoNavController* GetNavController() { return m_navController; } IslePathActor* GetCurrentVehicle() { return m_currentVehicle; } @@ -276,6 +277,7 @@ LegoPlantManager* PlantManager(); LegoWorld* CurrentWorld(); LegoUnkSaveDataWriter* UnkSaveDataWriter(); LegoTextureContainer* TextureContainer(); +ViewLODListManager* GetViewLODListManager(); void FUN_10015820(MxBool p_disable, MxU16 p_flags); void SetROIUnknown0x0c(const char* p_name, undefined p_unk0x0c); LegoWorld* FindWorld(const MxAtomId& p_atom, MxS32 p_entityid); diff --git a/LEGO1/lego/legoomni/src/main/legoomni.cpp b/LEGO1/lego/legoomni/src/main/legoomni.cpp index 0ea4607d..f0081e2c 100644 --- a/LEGO1/lego/legoomni/src/main/legoomni.cpp +++ b/LEGO1/lego/legoomni/src/main/legoomni.cpp @@ -220,6 +220,12 @@ LegoTextureContainer* TextureContainer() return LegoOmni::GetInstance()->GetTextureContainer(); } +// FUNCTION: LEGO1 0x10015810 +ViewLODListManager* GetViewLODListManager() +{ + return LegoOmni::GetInstance()->GetViewLODListManager(); +} + // FUNCTION: LEGO1 0x10015820 void FUN_10015820(MxBool p_disable, MxU16 p_flags) { diff --git a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp index abc43b4e..ad3199e2 100644 --- a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp @@ -1,5 +1,6 @@ #include "legomodelpresenter.h" +#include "anim/legoanim.h" #include "define.h" #include "legoentity.h" #include "legoentitypresenter.h" @@ -7,6 +8,9 @@ #include "legounksavedatawriter.h" #include "legovideomanager.h" #include "legoworld.h" +#include "misc/legocontainer.h" +#include "misc/legotexture.h" +#include "misc/version.h" #include "mxcompositepresenter.h" #include "mxutil.h" #include "roi/legoroi.h" @@ -47,11 +51,155 @@ void LegoModelPresenter::Destroy(MxBool p_fromDestructor) } } -// STUB: LEGO1 0x1007f6b0 +// FUNCTION: LEGO1 0x1007f6b0 MxResult LegoModelPresenter::CreateROI(MxStreamChunk* p_chunk) { - // TODO - return FAILURE; + MxResult result = FAILURE; + LegoU32 numROIs; + Mx3DPointFloat vect; + LegoMemory storage(p_chunk->GetData()); + LegoAnim anim; + LegoU32 version, textureInfoOffset, i, numTextures, skipTextures; + MxMatrix mat; + LegoChar* textureName = NULL; + LegoTexture* texture = NULL; + LegoS32 hardwareMode = VideoManager()->GetDirect3D()->AssignedDevice()->GetHardwareMode(); + + if (m_roi) { + delete m_roi; + } + if (!(m_roi = new LegoROI(VideoManager()->GetRenderer()))) { + goto done; + } + if (storage.Read(&version, sizeof(version)) != SUCCESS) { + goto done; + } + if (version != MODEL_VERSION) { + goto done; + } + if (storage.Read(&textureInfoOffset, sizeof(textureInfoOffset)) != SUCCESS) { + goto done; + } + + storage.SetPosition(textureInfoOffset); + + if (storage.Read(&numTextures, sizeof(numTextures)) != SUCCESS) { + goto done; + } + if (storage.Read(&skipTextures, sizeof(skipTextures)) != SUCCESS) { + goto done; + } + + for (i = 0; i < numTextures; i++) { + LegoU32 textureNameLength; + + storage.Read(&textureNameLength, sizeof(textureNameLength)); + textureName = new LegoChar[textureNameLength + 1]; + storage.Read(textureName, textureNameLength); + textureName[textureNameLength] = '\0'; + + strlwr(textureName); + + if (textureName[0] == '^') { + strcpy(textureName, textureName + 1); + + if (g_modelPresenterConfig) { + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + + LegoTexture* discardTexture = new LegoTexture(); + if (discardTexture->Read(&storage, FALSE) != SUCCESS) { + goto done; + } + delete discardTexture; + } + else { + LegoTexture* discardTexture = new LegoTexture(); + if (discardTexture->Read(&storage, FALSE) != SUCCESS) { + goto done; + } + delete discardTexture; + + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + } + } + else { + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + } + + if (!skipTextures) { + if (TextureContainer()->Get(textureName) == NULL) { + LegoTextureInfo* textureInfo = LegoTextureInfo::Create(textureName, texture); + + if (textureInfo == NULL) { + goto done; + } + + TextureContainer()->Add(textureName, textureInfo); + } + + delete[] textureName; + textureName = NULL; + delete texture; + texture = NULL; + } + } + + storage.SetPosition(8); + + if (storage.Read(&numROIs, sizeof(numROIs)) != SUCCESS) { + goto done; + } + if (anim.Read(&storage, FALSE) != SUCCESS) { + goto done; + } + if (m_roi->Read(NULL, VideoManager()->GetRenderer(), GetViewLODListManager(), TextureContainer(), &storage) != + SUCCESS) { + goto done; + } + if (m_roi->SetFrame(&anim, 0) != SUCCESS) { + goto done; + } + + // Get scripted location, direction and up vectors + + CalcLocalTransform( + Mx3DPointFloat(m_action->GetLocation().GetX(), m_action->GetLocation().GetY(), m_action->GetLocation().GetZ()), + Mx3DPointFloat( + m_action->GetDirection().GetX(), + m_action->GetDirection().GetY(), + m_action->GetDirection().GetZ() + ), + Mx3DPointFloat(m_action->GetUp().GetX(), m_action->GetUp().GetY(), m_action->GetUp().GetZ()), + mat + ); + m_roi->FUN_100a46b0(mat); + + result = SUCCESS; + +done: + if (textureName != NULL) { + delete[] textureName; + } + if (texture != NULL) { + delete texture; + } + if (result != SUCCESS) { + if (m_roi) { + delete m_roi; + m_roi = NULL; + } + } + + return result; } // FUNCTION: LEGO1 0x10080050 diff --git a/LEGO1/lego/sources/misc/legocontainer.cpp b/LEGO1/lego/sources/misc/legocontainer.cpp index aebfc96d..7ccaf2d1 100644 --- a/LEGO1/lego/sources/misc/legocontainer.cpp +++ b/LEGO1/lego/sources/misc/legocontainer.cpp @@ -14,7 +14,7 @@ LegoTextureContainer::~LegoTextureContainer() } // FUNCTION: LEGO1 0x100998e0 -LegoTextureInfo* LegoTextureContainer::Insert(LegoTextureInfo* p_textureInfo) +LegoTextureInfo* LegoTextureContainer::AddToList(LegoTextureInfo* p_textureInfo) { DDSURFACEDESC desc, newDesc; DWORD width, height; @@ -110,7 +110,7 @@ LegoTextureInfo* LegoTextureContainer::Insert(LegoTextureInfo* p_textureInfo) } // FUNCTION: LEGO1 0x10099cc0 -void LegoTextureContainer::Erase(LegoTextureInfo* p_textureInfo) +void LegoTextureContainer::EraseFromList(LegoTextureInfo* p_textureInfo) { if (p_textureInfo == NULL) { return; diff --git a/LEGO1/lego/sources/misc/legocontainer.h b/LEGO1/lego/sources/misc/legocontainer.h index a1b869f1..561c2cbd 100644 --- a/LEGO1/lego/sources/misc/legocontainer.h +++ b/LEGO1/lego/sources/misc/legocontainer.h @@ -13,7 +13,7 @@ #pragma warning(disable : 4237) struct LegoContainerInfoComparator { - bool operator()(const char* const& p_key0, const char* const& p_key1) const { return strcmp(p_key0, p_key1) > 0; } + LegoU8 operator()(const char* const& p_key0, const char* const& p_key1) const { return strcmp(p_key0, p_key1) > 0; } }; // SIZE 0x10 @@ -44,16 +44,45 @@ class LegoContainer { inline T* Get(const char* p_name) { + // TODO: Score::Paint matches better with no `value` on the stack, + // while LegoModelPresenter::CreateROI only matches with `value` + T* value = NULL; + #ifdef COMPAT_MODE typename LegoContainerInfo::iterator it = m_map.find(p_name); #else LegoContainerInfo::iterator it = m_map.find(p_name); #endif + if (it != m_map.end()) { - return (*it).second; + value = (*it).second; } - return NULL; + return value; + } + + inline void Add(const char* p_name, T* p_value) + { +#ifdef COMPAT_MODE + typename LegoContainerInfo::iterator it = m_map.find(p_name); +#else + LegoContainerInfo::iterator it = m_map.find(p_name); +#endif + + char* name; + if (it != m_map.end()) { + name = const_cast((*it).first); + + if (m_ownership) { + delete (*it).second; + } + } + else { + name = new char[strlen(p_name) + 1]; + strcpy(name, p_name); + } + + m_map[name] = p_value; } inline void SetOwnership(LegoBool p_ownership) { m_ownership = p_ownership; } @@ -76,8 +105,8 @@ class LegoTextureContainer : public LegoContainer { LegoTextureContainer() { m_ownership = TRUE; } ~LegoTextureContainer() override; - LegoTextureInfo* Insert(LegoTextureInfo* p_textureInfo); - void Erase(LegoTextureInfo* p_textureInfo); + LegoTextureInfo* AddToList(LegoTextureInfo* p_textureInfo); + void EraseFromList(LegoTextureInfo* p_textureInfo); protected: LegoTextureList m_list; // 0x18 @@ -90,6 +119,9 @@ class LegoTextureContainer : public LegoContainer { // TEMPLATE: LEGO1 0x10001cc0 // _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Lbound +// TEMPLATE: LEGO1 0x1004f960 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::iterator::_Dec + // TEMPLATE: LEGO1 0x1004f9b0 // _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Insert diff --git a/LEGO1/lego/sources/misc/legostorage.cpp b/LEGO1/lego/sources/misc/legostorage.cpp index 8fa71553..7da93569 100644 --- a/LEGO1/lego/sources/misc/legostorage.cpp +++ b/LEGO1/lego/sources/misc/legostorage.cpp @@ -126,17 +126,3 @@ LegoResult LegoFile::Open(const char* p_name, LegoU32 p_mode) } return SUCCESS; } - -// FUNCTION: LEGO1 0x100994a0 -LegoResult LegoMemory::GetPosition(LegoU32& p_position) -{ - p_position = m_position; - return SUCCESS; -} - -// FUNCTION: LEGO1 0x100994b0 -LegoResult LegoMemory::SetPosition(LegoU32 p_position) -{ - m_position = p_position; - return SUCCESS; -} diff --git a/LEGO1/lego/sources/misc/legostorage.h b/LEGO1/lego/sources/misc/legostorage.h index e975c347..2e7eb30b 100644 --- a/LEGO1/lego/sources/misc/legostorage.h +++ b/LEGO1/lego/sources/misc/legostorage.h @@ -47,8 +47,20 @@ class LegoMemory : public LegoStorage { LegoMemory(void* p_buffer); LegoResult Read(void* p_buffer, LegoU32 p_size) override; LegoResult Write(const void* p_buffer, LegoU32 p_size) override; - LegoResult GetPosition(LegoU32& p_position) override; - LegoResult SetPosition(LegoU32 p_position) override; + + // FUNCTION: LEGO1 0x100994a0 + LegoResult GetPosition(LegoU32& p_position) override + { + p_position = m_position; + return SUCCESS; + } + + // FUNCTION: LEGO1 0x100994b0 + LegoResult SetPosition(LegoU32 p_position) override + { + m_position = p_position; + return SUCCESS; + } // SYNTHETIC: LEGO1 0x10045a80 // LegoMemory::~LegoMemory diff --git a/LEGO1/lego/sources/misc/version.h b/LEGO1/lego/sources/misc/version.h index 1eaa84af..7f88091c 100644 --- a/LEGO1/lego/sources/misc/version.h +++ b/LEGO1/lego/sources/misc/version.h @@ -1,6 +1,6 @@ #ifndef __VERSION_H #define __VERSION_H -#define MODEL_VERSION 3 +#define MODEL_VERSION 19 #endif // __VERSION_H diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp index bc0131f7..3463022e 100644 --- a/LEGO1/lego/sources/roi/legoroi.cpp +++ b/LEGO1/lego/sources/roi/legoroi.cpp @@ -96,6 +96,24 @@ LegoROI::~LegoROI() } } +// STUB: LEGO1 0x100a84a0 +LegoResult LegoROI::Read( + OrientableROI* p_unk0xd4, + Tgl::Renderer* p_renderer, + ViewLODListManager* p_viewLODListManager, + LegoTextureContainer* p_textureContainer, + LegoStorage* p_storage +) +{ + return SUCCESS; +} + +// STUB: LEGO1 0x100a90f0 +LegoResult LegoROI::SetFrame(LegoAnim* p_anim, LegoTime p_time) +{ + return SUCCESS; +} + // FUNCTION: LEGO1 0x100a9a50 TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, int p_time) : LegoROI(p_renderer, p_lodList) { diff --git a/LEGO1/lego/sources/roi/legoroi.h b/LEGO1/lego/sources/roi/legoroi.h index 8b6c78ce..ab2b45d1 100644 --- a/LEGO1/lego/sources/roi/legoroi.h +++ b/LEGO1/lego/sources/roi/legoroi.h @@ -7,6 +7,9 @@ typedef unsigned char (*ROIHandler)(char*, char*, unsigned int); class LegoEntity; +class LegoTextureContainer; +class LegoStorage; +class LegoAnim; // VTABLE: LEGO1 0x100dbe38 // SIZE 0x108 @@ -16,6 +19,15 @@ class LegoROI : public ViewROI { LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList); ~LegoROI() override; + LegoResult Read( + OrientableROI* p_unk0xd4, + Tgl::Renderer* p_renderer, + ViewLODListManager* p_viewLODListManager, + LegoTextureContainer* p_textureContainer, + LegoStorage* p_storage + ); + LegoResult SetFrame(LegoAnim* p_anim, LegoTime p_time); + float IntrinsicImportance() const override; // vtable+0x04 void UpdateWorldBoundingVolumes() override; // vtable+0x18 diff --git a/LEGO1/mxdirectx/mxdirect3d.h b/LEGO1/mxdirectx/mxdirect3d.h index 341f9c69..bbfe7e3b 100644 --- a/LEGO1/mxdirectx/mxdirect3d.h +++ b/LEGO1/mxdirectx/mxdirect3d.h @@ -22,6 +22,7 @@ class MxAssignedDevice { ~MxAssignedDevice(); inline unsigned int GetFlags() { return m_flags; } + inline BOOL GetHardwareMode() { return ((int) m_flags << 31) >> 31; } inline D3DDEVICEDESC& GetDesc() { return m_desc; } friend class MxDirect3D; diff --git a/LEGO1/mxgeometry/mxgeometry3d.h b/LEGO1/mxgeometry/mxgeometry3d.h index bdb3f191..48c46fcf 100644 --- a/LEGO1/mxgeometry/mxgeometry3d.h +++ b/LEGO1/mxgeometry/mxgeometry3d.h @@ -15,6 +15,10 @@ class Mx3DPointFloat : public Vector3 { m_elements[2] = p_z; } + inline float GetX() { return m_data[0]; } + inline float GetY() { return m_data[1]; } + inline float GetZ() { return m_data[2]; } + // FUNCTION: LEGO1 0x100343a0 inline Mx3DPointFloat(const Mx3DPointFloat& p_other) : Vector3(m_elements) { EqualsImpl(p_other.m_data); }