diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cedd429..6b663cb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,8 +72,10 @@ add_library(lego1 SHARED LEGO1/legojetski.cpp LEGO1/legoloadcachesoundpresenter.cpp LEGO1/legolocomotionanimpresenter.cpp + LEGO1/legometerpresenter.cpp LEGO1/legomodelpresenter.cpp LEGO1/legonavcontroller.cpp + LEGO1/legoobjectfactory.cpp LEGO1/legoomni.cpp LEGO1/legopalettepresenter.cpp LEGO1/legopartpresenter.cpp @@ -89,6 +91,8 @@ add_library(lego1 SHARED LEGO1/legostream.cpp LEGO1/legotexturepresenter.cpp LEGO1/legoutil.cpp + LEGO1/legounksavedatawriter.cpp + LEGO1/legovehiclebuildstate.cpp LEGO1/legovideomanager.cpp LEGO1/legoworld.cpp LEGO1/legoworldpresenter.cpp @@ -156,6 +160,7 @@ add_library(lego1 SHARED LEGO1/mxpresenterlist.cpp LEGO1/mxramstreamcontroller.cpp LEGO1/mxramstreamprovider.cpp + LEGO1/mxregion.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp LEGO1/mxsmkpresenter.cpp diff --git a/LEGO1/infocenterstate.cpp b/LEGO1/infocenterstate.cpp index d680eb43..fcd300ee 100644 --- a/LEGO1/infocenterstate.cpp +++ b/LEGO1/infocenterstate.cpp @@ -1,5 +1,7 @@ #include "infocenterstate.h" +DECOMP_SIZE_ASSERT(InfocenterState, 0x94); + // OFFSET: LEGO1 0x10071600 STUB InfocenterState::InfocenterState() { diff --git a/LEGO1/infocenterstate.h b/LEGO1/infocenterstate.h index 4f09d496..cbd2bd34 100644 --- a/LEGO1/infocenterstate.h +++ b/LEGO1/infocenterstate.h @@ -3,6 +3,8 @@ #include "legostate.h" +#include "decomp.h" + // VTABLE 0x100d93a8 // SIZE 0x94 class InfocenterState : public LegoState @@ -23,6 +25,40 @@ class InfocenterState : public LegoState { return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name); } + + inline MxU32 GetInfocenterBufferElement(MxS32 p_index) { return m_buffer[p_index]; } + +private: + // Members should be renamed with their offsets before use + /* + struct UnkStruct + { + undefined4 unk1; + undefined2 unk2; + undefined2 unk3; + undefined2 unk4; + }; + + undefined2 unk1; + undefined2 unk2; + undefined4 unk3; + undefined4 padding1; + void *unk4; + undefined2 unk5; + undefined2 unk6; + undefined2 unk7; + undefined2 padding2; + void *unk8; + undefined2 unk9; + undefined2 unk10; + undefined2 unk11; + undefined2 padding3; + UnkStruct unk12[6]; + undefined4 unk13; + */ + + undefined pad[0x70]; + MxU32 m_buffer[7]; // 0x78 }; #endif // INFOCENTERSTATE_H diff --git a/LEGO1/legoentity.cpp b/LEGO1/legoentity.cpp index e7601cc2..c4e52dd1 100644 --- a/LEGO1/legoentity.cpp +++ b/LEGO1/legoentity.cpp @@ -36,14 +36,17 @@ void LegoEntity::Reset() m_unk59 = 4; } -// OFFSET: LEGO1 0x100107e0 STUB -void LegoEntity::vtable18() +// OFFSET: LEGO1 0x100107e0 +MxResult LegoEntity::InitFromMxDSObject(MxDSObject& p_object) { - + m_mxEntityId = p_object.GetObjectId(); + m_atom = p_object.GetAtomId(); + AddToCurrentWorld(); + return SUCCESS; } // OFFSET: LEGO1 0x10010810 STUB -void LegoEntity::Destroy(MxBool) +void LegoEntity::Destroy(MxBool p_fromDestructor) { if (m_unk54) { // TODO @@ -53,6 +56,16 @@ void LegoEntity::Destroy(MxBool) Reset(); } +// OFFSET: LEGO1 0x10010880 STUB +void LegoEntity::AddToCurrentWorld() +{ + LegoWorld* world = GetCurrentWorld(); + if (world != NULL && world != (LegoWorld*)this) + { + // TODO: world->vtable58(this); + } +} + // OFFSET: LEGO1 0x10010e10 void LegoEntity::ParseAction(char *p_extra) { diff --git a/LEGO1/legoentity.h b/LEGO1/legoentity.h index 79acca27..fc5117ea 100644 --- a/LEGO1/legoentity.h +++ b/LEGO1/legoentity.h @@ -5,6 +5,7 @@ #include "mxvector.h" #include "extra.h" #include "decomp.h" +#include "mxdsobject.h" // VTABLE 0x100d4858 // SIZE 0x68 (probably) @@ -34,12 +35,13 @@ class LegoEntity : public MxEntity return !strcmp(name, LegoEntity::ClassName()) || MxEntity::IsA(name); } - virtual void vtable18(); // vtable+0x18 - virtual void Destroy(MxBool); // vtable+0x1c + virtual MxResult InitFromMxDSObject(MxDSObject& p_object); // vtable+0x18 + virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c virtual void ParseAction(char *); // vtable+0x20 protected: void Reset(); + void AddToCurrentWorld(); undefined m_unk10; undefined m_unk11; diff --git a/LEGO1/legogamestate.cpp b/LEGO1/legogamestate.cpp index a08ce8e2..ca1595c7 100644 --- a/LEGO1/legogamestate.cpp +++ b/LEGO1/legogamestate.cpp @@ -1,17 +1,77 @@ #include "legogamestate.h" #include "legoomni.h" +#include "legostate.h" +#include "infocenterstate.h" +#include "legostream.h" +#include "mxobjectfactory.h" #include "mxvariabletable.h" -#include "decomp.h" +#include "mxstring.h" // Based on the highest dword offset (0x42c) referenced in the constructor. // There may be other members that come after. DECOMP_SIZE_ASSERT(LegoGameState, 0x430) +// GLOBAL OFFSET: LEGO1 0x100f3e40 +const char *g_fileExtensionGS = ".GS"; + +// GLOBAL OFFSET: LEGO1 0x100f3e58 +ColorStringStruct g_colorSaveData[43] = { + {"c_dbbkfny0", "lego red"}, + {"c_dbbkxly0", "lego white"}, + {"c_chbasey0", "lego black"}, + {"c_chbacky0", "lego black"}, + {"c_chdishy0", "lego white"}, + {"c_chhorny0", "lego black"}, + {"c_chljety1", "lego black"}, + {"c_chrjety1", "lego black"}, + {"c_chmidly0", "lego black"}, + {"c_chmotry0", "lego blue"}, + {"c_chsidly0", "lego black"}, + {"c_chsidry0", "lego black"}, + {"c_chstuty0", "lego black"}, + {"c_chtaily0", "lego black"}, + {"c_chwindy1", "lego black"}, + {"c_dbfbrdy0", "lego red"}, + {"c_dbflagy0", "lego yellow"}, + {"c_dbfrfny4", "lego red"}, + {"c_dbfrxly0", "lego white"}, + {"c_dbhndly0", "lego white"}, + {"c_dbltbry0", "lego white"}, + {"c_jsdashy0", "lego white"}, + {"c_jsexhy0", "lego black"}, + {"c_jsfrnty5", "lego black"}, + {"c_jshndly0", "lego red"}, + {"c_jslsidy0", "lego black"}, + {"c_jsrsidy0", "lego black"}, + {"c_jsskiby0", "lego red"}, + {"c_jswnshy5", "lego white"}, + {"c_rcbacky6", "lego green"}, + {"c_rcedgey0", "lego green"}, + {"c_rcfrmey0", "lego red"}, + {"c_rcfrnty6", "lego green"}, + {"c_rcmotry0", "lego white"}, + {"c_rcsidey0", "lego green"}, + {"c_rcstery0", "lego white"}, + {"c_rcstrpy0", "lego yellow"}, + {"c_rctailya", "lego white"}, + {"c_rcwhl1y0", "lego white"}, + {"c_rcwhl2y0", "lego white"}, + {"c_jsbasey0", "lego white"}, + {"c_chblady0", "lego black"}, + {"c_chseaty0", "lego white"}, +}; + +// NOTE: This offset = the end of the variables table, the last entry +// in that table is a special entry, the string "END_OF_VARIABLES" +// GLOBAL OFFSET: LEGO1 0x100f3e50 +extern const char *s_endOfVariables; + // OFFSET: LEGO1 0x10039550 LegoGameState::LegoGameState() { // TODO + m_stateCount = 0; m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68"); VariableTable()->SetVariable(m_backgroundColor); @@ -25,33 +85,93 @@ LegoGameState::LegoGameState() SerializeScoreHistory(1); } -// OFFSET: LEGO1 0x10039720 +// OFFSET: LEGO1 0x10039720 STUB LegoGameState::~LegoGameState() { // TODO } -// OFFSET: LEGO1 0x10039c60 +// OFFSET: LEGO1 0x10039c60 STUB MxResult LegoGameState::Load(MxULong) { // TODO return 0; } -// OFFSET: LEGO1 0x10039980 -MxResult LegoGameState::Save(MxULong p) +// OFFSET: LEGO1 0x1003a170 +void LegoGameState::GetFileSavePath(MxString *p_outPath, MxULong p_slotn) { - // TODO - return 0; + char baseForSlot[2] = "0"; + char path[1024] = ""; + + // Save path base + if (m_savePath != NULL) + strcpy(path, m_savePath); + + // Slot: "G0", "G1", ... + strcat(path, "G"); + baseForSlot[0] += p_slotn; + strcat(path, baseForSlot); + + // Extension: ".GS" + strcat(path, g_fileExtensionGS); + *p_outPath = MxString(path); } -// OFFSET: LEGO1 0x1003a2e0 +// OFFSET: LEGO1 0x1003a020 +MxResult LegoGameState::WriteEndOfVariables(LegoStream *p_stream) +{ + MxU8 len = strlen(s_endOfVariables); + if (p_stream->Write(&len, 1) == SUCCESS) + return p_stream->Write(s_endOfVariables, len); + return FAILURE; +} + +// OFFSET: LEGO1 0x10039980 +MxResult LegoGameState::Save(MxULong p_slot) +{ + MxResult result; + InfocenterState *infocenterState = (InfocenterState *)GameState()->GetState("InfocenterState"); + if (!infocenterState || infocenterState->GetInfocenterBufferElement(0) == 0) + result = SUCCESS; + else { + result = FAILURE; + MxVariableTable *variableTable = VariableTable(); + MxString savePath; + GetFileSavePath(&savePath, p_slot); + LegoFileStream fileStream; + if (fileStream.Open(savePath.GetData(), LegoStream::WriteBit) != FAILURE) { + MxU32 maybeVersion = 0x1000C; + fileStream.Write(&maybeVersion, 4); + fileStream.Write(&m_unk24, 2); + fileStream.Write(&m_unk10, 2); + fileStream.Write(&m_unkC, 1); + + for (MxS32 i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) { + if (LegoStream::WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) + return result; + } + + if (LegoStream::WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) { + if (LegoStream::WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE) { + WriteEndOfVariables(&fileStream); + + // TODO: Calls down to more aggregate writing functions + return SUCCESS; + } + } + } + } + return result; +} + +// OFFSET: LEGO1 0x1003a2e0 STUB void LegoGameState::SerializePlayersInfo(MxS16 p) { // TODO } -// OFFSET: LEGO1 0x1003cdd0 +// OFFSET: LEGO1 0x1003cdd0 STUB void LegoGameState::SerializeScoreHistory(MxS16 p) { // TODO @@ -61,16 +181,56 @@ void LegoGameState::SerializeScoreHistory(MxS16 p) void LegoGameState::SetSavePath(char *p_savePath) { if (m_savePath != NULL) - { delete[] m_savePath; - } - if (p_savePath) - { + + if (p_savePath) { m_savePath = new char[strlen(p_savePath) + 1]; strcpy(m_savePath, p_savePath); } else - { m_savePath = NULL; - } } + +// OFFSET: LEGO1 0x1003bbb0 +LegoState *LegoGameState::GetState(char *p_stateName) +{ + for (MxS32 i = 0; i < m_stateCount; ++i) + if (m_stateArray[i]->IsA(p_stateName)) + return m_stateArray[i]; + return NULL; +} + +// OFFSET: LEGO1 0x1003bc00 +LegoState *LegoGameState::CreateState(char *p_stateName) +{ + LegoState* newState = (LegoState*)ObjectFactory()->Create(p_stateName); + RegisterState(newState); + + return newState; +} + +// OFFSET: LEGO1 0x1003bc30 +void LegoGameState::RegisterState(LegoState *p_state) +{ + MxS32 targetIndex; + for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex) + if (m_stateArray[targetIndex]->IsA(p_state->ClassName())) + break; + + if (targetIndex == m_stateCount) { + LegoState **newBuffer = new LegoState*[m_stateCount + 1]; + + if (m_stateCount != 0) { + memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*)); + delete[] m_stateArray; + } + + newBuffer[m_stateCount++] = p_state; + m_stateArray = newBuffer; + return; + } + + if (m_stateArray[targetIndex]) + delete m_stateArray[targetIndex]; + m_stateArray[targetIndex] = p_state; +} \ No newline at end of file diff --git a/LEGO1/legogamestate.h b/LEGO1/legogamestate.h index b1cd8b60..8dc0be4a 100644 --- a/LEGO1/legogamestate.h +++ b/LEGO1/legogamestate.h @@ -6,6 +6,17 @@ #include "legobackgroundcolor.h" #include "legofullscreenmovie.h" +class LegoState; +class LegoStream; +class MxVariable; +class MxString; + +struct ColorStringStruct +{ + const char *m_targetName; + const char *m_colorName; +}; + // SIZE 0x430 (at least) class LegoGameState { @@ -18,13 +29,27 @@ class LegoGameState __declspec(dllexport) void SerializeScoreHistory(MxS16 p); __declspec(dllexport) void SetSavePath(char *p); + LegoState *GetState(char *p_stateName); + LegoState *CreateState(char *p_stateName); + + void GetFileSavePath(MxString *p_outPath, MxULong p_slotn); + +private: + void RegisterState(LegoState *p_state); + MxResult WriteEndOfVariables(LegoStream *p_stream); + private: char *m_savePath; // 0x0 - undefined m_unk04[20]; + MxS16 m_stateCount; + LegoState **m_stateArray; + MxU8 m_unkC; + MxU32 m_unk10; + undefined4 m_unk0x14; LegoBackgroundColor *m_backgroundColor; // 0x18 LegoBackgroundColor *m_tempBackgroundColor; // 0x1c LegoFullScreenMovie *m_fullScreenMovie; // 0x20 - undefined m_unk24[1036]; + MxU16 m_unk24; // 0x24 + undefined m_unk28[1032]; }; #endif // LEGOGAMESTATE_H diff --git a/LEGO1/legometerpresenter.cpp b/LEGO1/legometerpresenter.cpp new file mode 100644 index 00000000..6fed7419 --- /dev/null +++ b/LEGO1/legometerpresenter.cpp @@ -0,0 +1,6 @@ +#include "legometerpresenter.h" + +#include "decomp.h" + +// Uncomment when member class variables are fleshed out. +// DECOMP_SIZE_ASSERT(LegoMeterPresenter, 0x94); // 0x1000a163 \ No newline at end of file diff --git a/LEGO1/legometerpresenter.h b/LEGO1/legometerpresenter.h new file mode 100644 index 00000000..6e5bae00 --- /dev/null +++ b/LEGO1/legometerpresenter.h @@ -0,0 +1,14 @@ +#ifndef LEGOMETERPRESENTER_H +#define LEGOMETERPRESENTER_H + +#include "mxstillpresenter.h" + +// VTABLE 0x100d7ac8 +// SIZE 0x94 (from 0x1000a163) +class LegoMeterPresenter : public MxStillPresenter +{ +public: + // MxStillPresenter's `::ClassName` and `::IsA` are used. +}; + +#endif // LEGOMETERPRESENTER_H diff --git a/LEGO1/legoobjectfactory.cpp b/LEGO1/legoobjectfactory.cpp new file mode 100644 index 00000000..222569ea --- /dev/null +++ b/LEGO1/legoobjectfactory.cpp @@ -0,0 +1,35 @@ +#include "legoobjectfactory.h" + +#include "infocenterstate.h" +#include "decomp.h" + +// TODO: Uncomment once we have all the relevant types ready +// DECOMP_SIZE_ASSERT(LegoObjectFactory, 0x1c8); + +// OFFSET: LEGO1 0x10006e40 +LegoObjectFactory::LegoObjectFactory() +{ +#define X(V) this->m_id##V = MxAtomId(#V, LookupMode_Exact); + FOR_LEGOOBJECTFACTORY_OBJECTS(X) +#undef X +} + +// OFFSET: LEGO1 0x10009a90 +MxCore *LegoObjectFactory::Create(const char *p_name) +{ + MxAtomId atom(p_name, LookupMode_Exact); + + if (0) { +#define X(V) } else if (this->m_id##V == atom) { return new V; + FOR_LEGOOBJECTFACTORY_OBJECTS(X) +#undef X + } else { + return MxObjectFactory::Create(p_name); + } +} + +// OFFSET: LEGO1 0x1000fb30 STUB +void LegoObjectFactory::Destroy(MxCore *p_object) +{ + // TODO +} diff --git a/LEGO1/legoobjectfactory.h b/LEGO1/legoobjectfactory.h new file mode 100644 index 00000000..f21e6053 --- /dev/null +++ b/LEGO1/legoobjectfactory.h @@ -0,0 +1,22 @@ +#ifndef LEGOOBJECTFACTORY_H +#define LEGOOBJECTFACTORY_H + +#include "mxobjectfactory.h" + +#define FOR_LEGOOBJECTFACTORY_OBJECTS(X) \ + X(InfocenterState) + +// VTABLE 0x100d4768 +class LegoObjectFactory : public MxObjectFactory +{ +public: + LegoObjectFactory(); + virtual MxCore *Create(const char *p_name) override; // vtable 0x14 + virtual void Destroy(MxCore *p_object) override; // vtable 0x18 +private: +#define X(V) MxAtomId m_id##V; + FOR_LEGOOBJECTFACTORY_OBJECTS(X) +#undef X +}; + +#endif // LEGOOBJECTFACTORY_H diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 33f88a58..7e306af1 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -4,6 +4,7 @@ #include "mxdsfile.h" #include "legogamestate.h" #include "legoutil.h" +#include "legoobjectfactory.h" // 0x100f4588 MxAtomId *g_nocdSourceName = NULL; @@ -261,7 +262,7 @@ void LegoOmni::Init() m_currentWorld = NULL; m_unk80 = FALSE; m_isle = NULL; - m_unk8c = 0; + m_unkLegoSaveDataWriter = NULL; m_plantManager = NULL; m_gameState = NULL; m_animationManager = NULL; @@ -271,11 +272,12 @@ void LegoOmni::Init() m_transitionManager = NULL; } -// OFFSET: LEGO1 0x10058e70 +// OFFSET: LEGO1 0x10058e70 STUB MxResult LegoOmni::Create(COMPAT_CONST MxOmniCreateParam &p) { - // FIXME: Stub MxOmni::Create(p); + + m_objectFactory = new LegoObjectFactory(); m_gameState = new LegoGameState(); m_bkgAudioManager = new MxBackgroundAudioManager(); diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index e4074463..37d3ef4b 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -16,6 +16,7 @@ class LegoPathBoundary; class LegoPlantManager; class LegoROI; class LegoSoundManager; +class LegoUnkSaveDataWriter; class LegoVideoManager; class LegoWorld; class MxAtomId; @@ -77,8 +78,8 @@ class LegoOmni : public MxOmni LegoWorld *GetCurrentWorld() { return m_currentWorld; } private: - int m_unk68; - int m_unk6c; + undefined4 m_unk68; + undefined4 m_unk6c; LegoInputManager *m_inputMgr; // 0x70 undefined4 m_unk74; undefined4 m_unk78; @@ -86,7 +87,7 @@ class LegoOmni : public MxOmni MxBool m_unk80; LegoNavController *m_navController; // 0x84 Isle* m_isle; // 0x88 - undefined4 m_unk8c; + LegoUnkSaveDataWriter* m_unkLegoSaveDataWriter; LegoPlantManager* m_plantManager; // 0x90 LegoAnimationManager* m_animationManager; LegoBuildingManager* m_buildingManager; // 0x98 diff --git a/LEGO1/legostream.cpp b/LEGO1/legostream.cpp index 1fd2bf11..0bc24db9 100644 --- a/LEGO1/legostream.cpp +++ b/LEGO1/legostream.cpp @@ -4,6 +4,14 @@ #include #include +#include "mxvariabletable.h" + +// This is a pointer to the end of the global variable name table, which has +// the text "END_OF_VARIABLES" in it. +// TODO: make s_endOfVariables reference the actual end of the variable array. +// GLOBAL OFFSET: LEGO1 0x100f3e50 +const char *s_endOfVariables = "END_OF_VARIABLES"; + // Very likely but not certain sizes. // The classes are only used on the stack in functions we have not 100% matched // yet, we can confirm the size once we have. @@ -38,7 +46,7 @@ LegoFileStream::~LegoFileStream() } // OFFSET: LEGO1 0x100992c0 -MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size) +MxResult LegoFileStream::Read(void* p_buffer, MxU32 p_size) { if (m_hFile == NULL) return FAILURE; @@ -47,7 +55,7 @@ MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size) } // OFFSET: LEGO1 0x10099300 -MxResult LegoFileStream::Write(char* p_buffer, MxU32 p_size) +MxResult LegoFileStream::Write(const void* p_buffer, MxU32 p_size) { if (m_hFile == NULL) return FAILURE; @@ -117,7 +125,7 @@ LegoMemoryStream::LegoMemoryStream(char* p_buffer) } // OFFSET: LEGO1 0x10099160 -MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size) +MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size) { memcpy(p_buffer, m_buffer + m_offset, p_size); m_offset += p_size; @@ -125,7 +133,7 @@ MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size) } // OFFSET: LEGO1 0x10099190 -MxResult LegoMemoryStream::Write(char* p_buffer, MxU32 p_size) +MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size) { memcpy(m_buffer + m_offset, p_buffer, p_size); m_offset += p_size; @@ -146,4 +154,51 @@ MxResult LegoMemoryStream::Seek(MxU32 p_offset) return SUCCESS; } +// OFFSET: LEGO1 0x10039f70 +MxResult LegoStream::WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName) +{ + MxResult result = FAILURE; + const char *variableValue = p_from->GetVariable(p_variableName); + if (variableValue) { + MxU8 length = strlen(p_variableName); + if (p_stream->Write((char*)&length, 1) == SUCCESS) { + if (p_stream->Write(p_variableName, length) == SUCCESS) { + length = strlen(variableValue); + if (p_stream->Write((char*)&length, 1) == SUCCESS) + result = p_stream->Write((char *)variableValue, length); + } + } + } + return result; +} + +// 95% match, just some instruction ordering differences on the call to +// MxVariableTable::SetVariable at the end. +// OFFSET: LEGO1 0x1003a080 +MxS32 LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to) +{ + MxS32 result = 1; + MxU8 length; + + if (p_stream->Read((char*)&length, 1) == SUCCESS) { + char nameBuffer[256]; + if (p_stream->Read(nameBuffer, length) == SUCCESS) { + nameBuffer[length] = '\0'; + if (strcmp(nameBuffer, s_endOfVariables) == 0) + // 2 -> "This was the last entry, done reading." + result = 2; + else { + if (p_stream->Read((char*)&length, 1) == SUCCESS) { + char valueBuffer[256]; + if (p_stream->Read(valueBuffer, length) == SUCCESS) { + result = 0; + valueBuffer[length] = '\0'; + p_to->SetVariable(nameBuffer, valueBuffer); + } + } + } + } + } + return result; +} diff --git a/LEGO1/legostream.h b/LEGO1/legostream.h index ca110f01..220d1b6d 100644 --- a/LEGO1/legostream.h +++ b/LEGO1/legostream.h @@ -10,6 +10,8 @@ #define LEGOSTREAM_MODE_READ 1 #define LEGOSTREAM_MODE_WRITE 2 +class MxVariableTable; + // VTABLE 0x100d7d80 class LegoStream { @@ -17,8 +19,8 @@ class LegoStream LegoStream() : m_mode(0) {} inline virtual ~LegoStream() {}; - virtual MxResult Read(char* p_buffer, MxU32 p_size) = 0; - virtual MxResult Write(char* p_buffer, MxU32 p_size) = 0; + virtual MxResult Read(void* p_buffer, MxU32 p_size) = 0; + virtual MxResult Write(const void* p_buffer, MxU32 p_size) = 0; virtual MxResult Tell(MxU32* p_offset) = 0; virtual MxResult Seek(MxU32 p_offset) = 0; @@ -32,6 +34,9 @@ class LegoStream BinaryBit = 4, }; + static MxResult __stdcall WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName); + static MxS32 __stdcall ReadVariable(LegoStream* p_stream, MxVariableTable* p_to); + protected: MxU8 m_mode; }; @@ -43,8 +48,8 @@ class LegoFileStream : public LegoStream LegoFileStream(); virtual ~LegoFileStream(); - MxResult Read(char* p_buffer, MxU32 p_size) override; - MxResult Write(char* p_buffer, MxU32 p_size) override; + MxResult Read(void* p_buffer, MxU32 p_size) override; + MxResult Write(const void* p_buffer, MxU32 p_size) override; MxResult Tell(MxU32* p_offset) override; MxResult Seek(MxU32 p_offset) override; @@ -61,8 +66,8 @@ class LegoMemoryStream : public LegoStream LegoMemoryStream(char* p_buffer); ~LegoMemoryStream() {} - MxResult Read(char* p_buffer, MxU32 p_size) override; - MxResult Write(char* p_buffer, MxU32 p_size) override; + MxResult Read(void* p_buffer, MxU32 p_size) override; + MxResult Write(const void* p_buffer, MxU32 p_size) override; MxResult Tell(MxU32* p_offset) override; MxResult Seek(MxU32 p_offset) override; diff --git a/LEGO1/legounksavedatawriter.cpp b/LEGO1/legounksavedatawriter.cpp new file mode 100644 index 00000000..61b41f28 --- /dev/null +++ b/LEGO1/legounksavedatawriter.cpp @@ -0,0 +1,48 @@ + +#include "legounksavedatawriter.h" +#include "legogamestate.h" +#include "legostream.h" + +DECOMP_SIZE_ASSERT(LegoSaveDataEntry3, 0x108); + +// GLOBAL OFFSET: LEGO1 0x10104f20 +LegoSaveDataEntry3 g_saveData3[66]; + +// OFFSET: LEGO1 0x10083310 +MxResult LegoUnkSaveDataWriter::WriteSaveData3(LegoStream *p_stream) +{ + MxResult result = FAILURE; + + // This should probably be a for loop but I can't figure out how to + // make it match as a for loop. + LegoSaveDataEntry3 *entry = g_saveData3; + const LegoSaveDataEntry3 *end = &g_saveData3[66]; + + while (TRUE) { + if (p_stream->Write(&entry->m_savePart1, 4) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart2, 4) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart3, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_currentFrame, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart5, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart6, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart7, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart8, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart9, 1) != SUCCESS) + break; + if (p_stream->Write(&entry->m_savePart10, 1) != SUCCESS) + break; + if (++entry >= end) { + result = SUCCESS; + break; + } + } + return result; +} diff --git a/LEGO1/legounksavedatawriter.h b/LEGO1/legounksavedatawriter.h new file mode 100644 index 00000000..0280077a --- /dev/null +++ b/LEGO1/legounksavedatawriter.h @@ -0,0 +1,40 @@ +#ifndef LEGOUNKSAVEDATAWRITER_H +#define LEGOUNKSAVEDATAWRITER_H + +#include "mxtypes.h" +#include "decomp.h" + +class LegoStream; + +struct LegoSaveDataEntry3 +{ + char *m_name; + void *m_unk0x04; + void *m_unk0x08; + MxS32 m_savePart1; + MxS32 m_savePart2; + MxU8 m_savePart3; + undefined4 m_unk0x18[6]; + MxU8 m_frameOffsetInDwords; // 0x30 + MxS32 *m_pFrameData; + MxU8 m_currentFrame; + undefined4 m_unk0x3c[2]; + MxU8 m_savePart5; // 0x44 + undefined4 m_unk0x48[5]; + MxU8 m_savePart6; // 0x5c + undefined4 m_unk0x60[11]; + MxU8 m_savePart7; // 0x8c + undefined4 m_unk0x90[5]; + MxU8 m_savePart8; // 0xa4 + undefined4 m_unk0xa8[17]; + MxU8 m_savePart9; // 0xec + undefined4 m_unk0xf0[5]; + MxU8 m_savePart10; // 0x104 +}; + +class LegoUnkSaveDataWriter +{ + MxResult WriteSaveData3(LegoStream *p_stream); +}; + +#endif // LEGOUNKSAVEDATAWRITER_H diff --git a/LEGO1/legovehiclebuildstate.cpp b/LEGO1/legovehiclebuildstate.cpp new file mode 100644 index 00000000..12e862a1 --- /dev/null +++ b/LEGO1/legovehiclebuildstate.cpp @@ -0,0 +1,25 @@ +#include "legovehiclebuildstate.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50); // 1000acd7 +DECOMP_SIZE_ASSERT(LegoVehicleBuildState::UnkStruct, 0xc); + +// OFFSET: LEGO1 0x10025f30 +LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType) +{ + this->m_className = p_classType; + this->m_unk4c = 0; + this->m_unk4d = 0; + this->m_unk4e = 0; + this->m_placedPartCount = 0; +} + +// OFFSET: LEGO1 10017c00 +LegoVehicleBuildState::UnkStruct::UnkStruct() +{ + m_unk04 = 0; + m_unk00 = 0; + m_unk06 = 0; + m_unk08 = 0; +} diff --git a/LEGO1/legovehiclebuildstate.h b/LEGO1/legovehiclebuildstate.h new file mode 100644 index 00000000..c3c2aae2 --- /dev/null +++ b/LEGO1/legovehiclebuildstate.h @@ -0,0 +1,60 @@ +#ifndef LEGOVEHICLEBUILDSTATE_H +#define LEGOVEHICLEBUILDSTATE_H + +#include "legostate.h" +#include "mxstring.h" +#include "decomp.h" + +#include "decomp.h" + +// VTABLE 0x100d66e0 +// SIZE 0x50 (from 1000acd7) +class LegoVehicleBuildState : public LegoState +{ +public: + LegoVehicleBuildState(char* p_classType); + + // OFFSET: LEGO1 0x10025ff0 + inline virtual const char *ClassName() const override // vtable+0x0c + { + return this->m_className.GetData(); + } + + // OFFSET: LEGO1 0x10026000 + inline virtual MxBool IsA(const char *p_name) const override // vtable+0x10 + { + return !strcmp(p_name, this->m_className.GetData()) || LegoState::IsA(p_name); + } + +public: + struct UnkStruct + { + undefined4 m_unk00; + undefined2 m_unk04; + undefined2 m_unk06; + undefined2 m_unk08; + + UnkStruct(); + }; +private: + UnkStruct m_unk08[4]; // 0x08 + + // This can be one of the following: + // * LegoRaceCarBuildState + // * LegoCopterBuildState + // * LegoDuneCarBuildState + // * LegoJetskiBuildState + MxString m_className; // 0x38 + + // Known States: + // * 1 == enter(ing) build screen + // * 3 == cutscene/dialogue + // * 6 == exit(ing) build screen + MxU32 m_animationState; // 0x48 + undefined m_unk4c; // 0x4c + undefined m_unk4d; // 0x4d + undefined m_unk4e; // 0x4e + MxU8 m_placedPartCount; // 0x4f +}; + +#endif // LEGOVEHICLEBUILDSTATE_H diff --git a/LEGO1/mxaudiomanager.cpp b/LEGO1/mxaudiomanager.cpp index bb358e47..e14d5090 100644 --- a/LEGO1/mxaudiomanager.cpp +++ b/LEGO1/mxaudiomanager.cpp @@ -14,7 +14,7 @@ MxAudioManager::MxAudioManager() // OFFSET: LEGO1 0x100b8d90 MxAudioManager::~MxAudioManager() { - LockedReinitialize(TRUE); + Destroy(TRUE); } // OFFSET: LEGO1 0x100b8df0 @@ -38,14 +38,14 @@ void MxAudioManager::SetVolume(MxS32 p_volume) } // OFFSET: LEGO1 0x100b8e00 -void MxAudioManager::LockedReinitialize(MxBool p_skipDestroy) +void MxAudioManager::Destroy(MxBool p_fromDestructor) { this->m_criticalSection.Enter(); g_unkCount--; Init(); this->m_criticalSection.Leave(); - if (!p_skipDestroy) + if (!p_fromDestructor) MxMediaManager::Destroy(); } @@ -74,5 +74,5 @@ MxResult MxAudioManager::InitPresenters() // OFFSET: LEGO1 0x100b8e90 void MxAudioManager::Destroy() { - LockedReinitialize(FALSE); + Destroy(FALSE); } \ No newline at end of file diff --git a/LEGO1/mxaudiomanager.h b/LEGO1/mxaudiomanager.h index 1ba5b6fd..b5458da8 100644 --- a/LEGO1/mxaudiomanager.h +++ b/LEGO1/mxaudiomanager.h @@ -17,7 +17,7 @@ class MxAudioManager : public MxMediaManager virtual void SetVolume(MxS32 p_volume); // vtable+2c private: - void LockedReinitialize(MxBool p_skipDestroy); + void Destroy(MxBool p_fromDestructor); static MxS32 g_unkCount; diff --git a/LEGO1/mxdsaction.cpp b/LEGO1/mxdsaction.cpp index 153a6498..3ba421e5 100644 --- a/LEGO1/mxdsaction.cpp +++ b/LEGO1/mxdsaction.cpp @@ -15,7 +15,7 @@ MxU16 g_unkSep = TWOCC(',', ' '); // OFFSET: LEGO1 0x100ad810 MxDSAction::MxDSAction() { - this->m_flags = 32; + this->m_flags = MxDSAction::Flag_Enabled; this->m_startTime = INT_MIN; this->m_extraData = NULL; this->m_extraLength = 0; @@ -29,7 +29,7 @@ MxDSAction::MxDSAction() this->m_unk84 = 0; this->m_unk88 = 0; this->m_omni = NULL; - this->m_someTimingField = INT_MIN; + this->m_unkTimingField = INT_MIN; } // OFFSET: LEGO1 0x100ada80 @@ -55,7 +55,7 @@ void MxDSAction::CopyFrom(MxDSAction &p_dsAction) this->m_unk84 = p_dsAction.m_unk84; this->m_unk88 = p_dsAction.m_unk88; this->m_omni = p_dsAction.m_omni; - this->m_someTimingField = p_dsAction.m_someTimingField; + this->m_unkTimingField = p_dsAction.m_unkTimingField; } // OFFSET: LEGO1 0x100adc10 @@ -153,7 +153,7 @@ void MxDSAction::MergeFrom(MxDSAction &p_dsAction) if (p_dsAction.m_direction[1] != FLT_MAX) this->m_direction[1] = p_dsAction.m_direction[1]; if (p_dsAction.m_direction[2] != FLT_MAX) - this->m_direction[2] = p_dsAction.m_direction[2]; + this->m_direction[2] = p_dsAction.m_up[2]; // This is correct if (p_dsAction.m_up[0] != FLT_MAX) this->m_up[0] = p_dsAction.m_up[0]; @@ -162,9 +162,13 @@ void MxDSAction::MergeFrom(MxDSAction &p_dsAction) if (p_dsAction.m_up[2] != FLT_MAX) this->m_up[2] = p_dsAction.m_up[2]; - // TODO MxU16 extraLength = p_dsAction.m_extraLength; char *extraData = p_dsAction.m_extraData; + + // Taking those references forces the compiler to move the values onto the stack. + // The original code most likely looked different, but this yields a 100% match. + MxU16 &_extraLength = extraLength; + char *&_extraData = extraData; if (extraLength && extraData) { if (!this->m_extraData || !strncmp("XXX", this->m_extraData, 3)) { delete[] this->m_extraData; @@ -181,15 +185,15 @@ MxBool MxDSAction::HasId(MxU32 p_objectId) } // OFFSET: LEGO1 0x100ada40 -void MxDSAction::SetSomeTimingField(MxLong p_someTimingField) +void MxDSAction::SetUnkTimingField(MxLong p_unkTimingField) { - this->m_someTimingField = p_someTimingField; + this->m_unkTimingField = p_unkTimingField; } // OFFSET: LEGO1 0x100ada50 -MxLong MxDSAction::GetSomeTimingField() +MxLong MxDSAction::GetUnkTimingField() { - return this->m_someTimingField; + return this->m_unkTimingField; } // Win32 defines GetCurrentTime to GetTickCount @@ -198,7 +202,7 @@ MxLong MxDSAction::GetSomeTimingField() // OFFSET: LEGO1 0x100adcd0 MxLong MxDSAction::GetCurrentTime() { - return Timer()->GetTime() - this->m_someTimingField; + return Timer()->GetTime() - this->m_unkTimingField; } // OFFSET: LEGO1 0x100ade60 diff --git a/LEGO1/mxdsaction.h b/LEGO1/mxdsaction.h index 57d1f200..868ae002 100644 --- a/LEGO1/mxdsaction.h +++ b/LEGO1/mxdsaction.h @@ -48,8 +48,8 @@ class MxDSAction : public MxDSObject virtual MxDSAction *Clone(); // vtable+2c; virtual void MergeFrom(MxDSAction &p_dsAction); // vtable+30; virtual MxBool HasId(MxU32 p_objectId); // vtable+34; - virtual void SetSomeTimingField(MxLong p_someTimingField); // vtable+38; - virtual MxLong GetSomeTimingField(); // vtable+3c; + virtual void SetUnkTimingField(MxLong p_unkTimingField); // vtable+38; + virtual MxLong GetUnkTimingField(); // vtable+3c; virtual MxLong GetCurrentTime(); // vtable+40; void AppendData(MxU16 p_extraLength, const char *p_extraData); @@ -87,7 +87,7 @@ class MxDSAction : public MxDSObject MxOmni *m_omni; // 0x8c protected: - MxLong m_someTimingField; // 0x90 + MxLong m_unkTimingField; // 0x90 }; #endif // MXDSACTION_H diff --git a/LEGO1/mxdschunk.cpp b/LEGO1/mxdschunk.cpp index 63c43ba2..84f45c19 100644 --- a/LEGO1/mxdschunk.cpp +++ b/LEGO1/mxdschunk.cpp @@ -4,16 +4,16 @@ MxDSChunk::MxDSChunk() { this->m_length = 0; - this->m_pStuff = NULL; + this->m_unk18 = NULL; this->m_buffer = -1; - this->m_long1FromHeader = 0; - this->m_long2FromHeader = 0; + this->m_unk10 = 0; + this->m_unk14 = 0; } // OFFSET: LEGO1 0x100be170 MxDSChunk::~MxDSChunk() { if ((this->m_length & 1) != 0) { - delete this->m_pStuff; + delete this->m_unk18; } } diff --git a/LEGO1/mxdschunk.h b/LEGO1/mxdschunk.h index 367dcb4d..b8ee0d60 100644 --- a/LEGO1/mxdschunk.h +++ b/LEGO1/mxdschunk.h @@ -26,10 +26,10 @@ class MxDSChunk : public MxCore private: MxS16 m_length; // 0x8 MxLong m_buffer; // 0xc - MxLong m_long1FromHeader; // 0x10 - MxLong m_long2FromHeader; // 0x14 - void* m_pStuff; // 0x18 - void* m_pSomething; // 0x1c + MxLong m_unk10; // 0x10 + MxLong m_unk14; // 0x14 + void* m_unk18; // 0x18 + void* m_unk1c; // 0x1c }; #endif // MXDSCHUNK_H diff --git a/LEGO1/mxdsmultiaction.cpp b/LEGO1/mxdsmultiaction.cpp index 2580b813..b4ad3377 100644 --- a/LEGO1/mxdsmultiaction.cpp +++ b/LEGO1/mxdsmultiaction.cpp @@ -40,14 +40,14 @@ MxDSMultiAction &MxDSMultiAction::operator=(MxDSMultiAction &p_dsMultiAction) } // OFFSET: LEGO1 0x100ca290 -void MxDSMultiAction::SetSomeTimingField(MxLong p_someTimingField) +void MxDSMultiAction::SetUnkTimingField(MxLong p_unkTimingField) { - this->m_someTimingField = p_someTimingField; + this->m_unkTimingField = p_unkTimingField; MxDSActionListCursor cursor(this->m_actions); MxDSAction *action; while (cursor.Next(action)) - action->SetSomeTimingField(p_someTimingField); + action->SetUnkTimingField(p_unkTimingField); } // OFFSET: LEGO1 0x100ca370 diff --git a/LEGO1/mxdsmultiaction.h b/LEGO1/mxdsmultiaction.h index 4e516333..e1174089 100644 --- a/LEGO1/mxdsmultiaction.h +++ b/LEGO1/mxdsmultiaction.h @@ -35,7 +35,7 @@ class MxDSMultiAction : public MxDSAction virtual MxDSAction *Clone() override; // vtable+2c; virtual void MergeFrom(MxDSAction &p_dsAction) override; // vtable+30; virtual MxBool HasId(MxU32 p_objectId) override; // vtable+34; - virtual void SetSomeTimingField(MxLong p_someTimingField) override; // vtable+38; + virtual void SetUnkTimingField(MxLong p_unkTimingField) override; // vtable+38; protected: MxU32 m_sizeOnDisk; diff --git a/LEGO1/mxdssource.cpp b/LEGO1/mxdssource.cpp index 86c4f9fb..0ede6402 100644 --- a/LEGO1/mxdssource.cpp +++ b/LEGO1/mxdssource.cpp @@ -1,9 +1,9 @@ #include "mxdssource.h" // OFFSET: LEGO1 0x100bffd0 -void MxDSSource::SomethingWhichCallsRead(void* pUnknownObject) +void MxDSSource::FUN_100bffd0(void* p_unk) { - // TODO: Calls read, reading into a buffer somewhere in pUnknownObject. + // TODO: Calls read, reading into a buffer somewhere in p_unk. Read(NULL, 0); } diff --git a/LEGO1/mxdssource.h b/LEGO1/mxdssource.h index 626eaf37..2891f426 100644 --- a/LEGO1/mxdssource.h +++ b/LEGO1/mxdssource.h @@ -28,7 +28,7 @@ class MxDSSource : public MxCore virtual MxLong Open(MxULong) = 0; virtual MxLong Close() = 0; - virtual void SomethingWhichCallsRead(void* pUnknownObject); + virtual void FUN_100bffd0(void* p_unk); virtual MxResult Read(unsigned char *, MxULong) = 0; virtual MxLong Seek(MxLong, int) = 0; virtual MxULong GetBufferSize() = 0; diff --git a/LEGO1/mxentity.h b/LEGO1/mxentity.h index 44afd9c4..2585f342 100644 --- a/LEGO1/mxentity.h +++ b/LEGO1/mxentity.h @@ -28,7 +28,7 @@ class MxEntity : public MxCore } virtual MxResult SetEntityId(MxS32 p_id, const MxAtomId &p_atom); // vtable+0x14 -private: +protected: MxS32 m_mxEntityId; // 0x8 MxAtomId m_atom; // 0xc }; diff --git a/LEGO1/mxeventmanager.cpp b/LEGO1/mxeventmanager.cpp index 0861af77..9f9e8779 100644 --- a/LEGO1/mxeventmanager.cpp +++ b/LEGO1/mxeventmanager.cpp @@ -13,7 +13,7 @@ MxEventManager::MxEventManager() // OFFSET: LEGO1 0x100c03f0 MxEventManager::~MxEventManager() { - TerminateThread(TRUE); + Destroy(TRUE); } // OFFSET: LEGO1 0x100c0450 @@ -22,45 +22,54 @@ void MxEventManager::Init() // This is intentionally left blank } +// OFFSET: LEGO1 0x100c0460 +void MxEventManager::Destroy(MxBool p_fromDestructor) +{ + if (m_thread != NULL) { + m_thread->Terminate(); + delete m_thread; + } + else + TickleManager()->UnregisterClient(this); + + if (!p_fromDestructor) + MxMediaManager::Destroy(); +} + // OFFSET: LEGO1 0x100c04a0 -MxResult MxEventManager::CreateEventThread(MxU32 p_frequencyMS, MxBool p_noRegister) +MxResult MxEventManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { MxResult status = FAILURE; MxBool locked = FALSE; MxResult result = MxMediaManager::InitPresenters(); - if (result == SUCCESS) - { - if (p_noRegister) - { + if (result == SUCCESS) { + if (p_createThread) { this->m_criticalSection.Enter(); locked = TRUE; this->m_thread = new MxTickleThread(this, p_frequencyMS); - if (this->m_thread) - { - if (this->m_thread->Start(0, 0) == SUCCESS) - { - status = SUCCESS; - } - } + if (!this->m_thread || this->m_thread->Start(0, 0) != SUCCESS) + goto done; } else - { TickleManager()->RegisterClient(this, p_frequencyMS); - status = SUCCESS; - } + + status = SUCCESS; } +done: if (status != SUCCESS) - { Destroy(); - } if (locked) - { this->m_criticalSection.Leave(); - } return status; } + +// OFFSET: LEGO1 0x100c0590 +void MxEventManager::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/mxeventmanager.h b/LEGO1/mxeventmanager.h index 1ef43748..acf4d417 100644 --- a/LEGO1/mxeventmanager.h +++ b/LEGO1/mxeventmanager.h @@ -11,9 +11,13 @@ class MxEventManager : public MxMediaManager public: MxEventManager(); virtual ~MxEventManager() override; - virtual MxResult CreateEventThread(MxU32 p_frequencyMS, MxBool p_noRegister); // vtable+28 + + virtual void Destroy() override; // vtable+18 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+28 + private: void Init(); + void Destroy(MxBool p_fromDestructor); }; #endif // MXEVENTMANAGER_H diff --git a/LEGO1/mxloopingflcpresenter.cpp b/LEGO1/mxloopingflcpresenter.cpp index 58b066f6..f525e31e 100644 --- a/LEGO1/mxloopingflcpresenter.cpp +++ b/LEGO1/mxloopingflcpresenter.cpp @@ -25,7 +25,7 @@ void MxLoopingFlcPresenter::Init() } // OFFSET: LEGO1 0x100b4432 STUB -void MxLoopingFlcPresenter::Destroy(MxBool p_param) +void MxLoopingFlcPresenter::Destroy(MxBool p_fromDestructor) { // TODO } diff --git a/LEGO1/mxloopingflcpresenter.h b/LEGO1/mxloopingflcpresenter.h index 209e2a53..449a0a86 100644 --- a/LEGO1/mxloopingflcpresenter.h +++ b/LEGO1/mxloopingflcpresenter.h @@ -22,7 +22,7 @@ class MxLoopingFlcPresenter : public MxFlcPresenter private: void Init(); - void Destroy(MxBool); + void Destroy(MxBool p_fromDestructor); undefined4 m_unk68; }; diff --git a/LEGO1/mxloopingsmkpresenter.cpp b/LEGO1/mxloopingsmkpresenter.cpp index f51e2750..ff85c5ff 100644 --- a/LEGO1/mxloopingsmkpresenter.cpp +++ b/LEGO1/mxloopingsmkpresenter.cpp @@ -25,7 +25,6 @@ void MxLoopingSmkPresenter::Init() } // OFFSET: LEGO1 0x100b49d0 STUB -void MxLoopingSmkPresenter::Destroy(MxBool p_bool) +void MxLoopingSmkPresenter::Destroy(MxBool p_fromDestructor) { - // TODO - theres a chain of destroy and free function calls here (FUN_100b4300 -> FUN_100b3900 -> FUN_100c5d40 -> function at 0x100b27b0) } diff --git a/LEGO1/mxloopingsmkpresenter.h b/LEGO1/mxloopingsmkpresenter.h index ae9cfa05..4b903598 100644 --- a/LEGO1/mxloopingsmkpresenter.h +++ b/LEGO1/mxloopingsmkpresenter.h @@ -22,7 +22,7 @@ class MxLoopingSmkPresenter : public MxSmkPresenter private: void Init(); - void Destroy(MxBool); + void Destroy(MxBool p_fromDestructor); undefined4 m_unk720; }; diff --git a/LEGO1/mxmatrix.cpp b/LEGO1/mxmatrix.cpp index 1cc3c550..27b39319 100644 --- a/LEGO1/mxmatrix.cpp +++ b/LEGO1/mxmatrix.cpp @@ -175,7 +175,7 @@ void MxMatrix::ToQuaternion(MxVector4 *p_outQuat) // No idea what this function is doing and it will be hard to tell until // we have a confirmed usage site. // OFFSET: LEGO1 0x10002710 STUB -MxResult MxMatrix::DoSomethingWithLength(const MxVector3 *p_vec) +MxResult MxMatrix::FUN_10002710(const MxVector3 *p_vec) { return FAILURE; } diff --git a/LEGO1/mxmatrix.h b/LEGO1/mxmatrix.h index 0dcb20cb..f7b5f9ef 100644 --- a/LEGO1/mxmatrix.h +++ b/LEGO1/mxmatrix.h @@ -36,7 +36,7 @@ class MxMatrix // vtable + 0x40 virtual void ToQuaternion(MxVector4 *p_resultQuat); - virtual MxResult DoSomethingWithLength(const MxVector3 *p_vec); + virtual MxResult FUN_10002710(const MxVector3 *p_vec); private: float *m_data; diff --git a/LEGO1/mxmediamanager.cpp b/LEGO1/mxmediamanager.cpp index c992cd42..a798e52d 100644 --- a/LEGO1/mxmediamanager.cpp +++ b/LEGO1/mxmediamanager.cpp @@ -98,23 +98,4 @@ void MxMediaManager::StopPresenters() while (cursor.Next(presenter)) presenter->EndAction(); -} - -// OFFSET: LEGO1 0x100c0460 -void MxMediaManager::TerminateThread(MxBool p_reinit) -{ - if(m_thread != NULL) - { - m_thread->Terminate(); - delete m_thread; - } - else - { - TickleManager()->UnregisterClient(this); - } - - if(!p_reinit) - { - MxMediaManager::Destroy(); - } -} +} \ No newline at end of file diff --git a/LEGO1/mxmediamanager.h b/LEGO1/mxmediamanager.h index c17ab300..db8d9056 100644 --- a/LEGO1/mxmediamanager.h +++ b/LEGO1/mxmediamanager.h @@ -23,7 +23,6 @@ class MxMediaManager : public MxCore virtual void StopPresenters(); // vtable+24 MxResult Init(); - void TerminateThread(MxBool p_reinit); protected: MxPresenterList *m_presenters; diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index 00a2b851..2fb6b57c 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -25,7 +25,7 @@ void MxMediaPresenter::Init() } // OFFSET: LEGO1 0x100b54f0 STUB -void MxMediaPresenter::Destroy(MxBool p_destroy) +void MxMediaPresenter::Destroy(MxBool p_fromDestructor) { // TODO } @@ -57,7 +57,7 @@ void MxMediaPresenter::Enable(MxBool p_enable) } // OFFSET: LEGO1 0x1000c5b0 -void MxMediaPresenter::InitVirtual() +void MxMediaPresenter::Destroy() { Destroy(FALSE); } diff --git a/LEGO1/mxmediapresenter.h b/LEGO1/mxmediapresenter.h index 6b8fd552..d0a5efe4 100644 --- a/LEGO1/mxmediapresenter.h +++ b/LEGO1/mxmediapresenter.h @@ -33,7 +33,7 @@ class MxMediaPresenter : public MxPresenter virtual void StreamingTickle() override; virtual void RepeatingTickle() override; virtual void DoneTickle() override; - virtual void InitVirtual() override; + virtual void Destroy() override; virtual MxLong StartAction(MxStreamController *, MxDSAction *) override; virtual void EndAction() override; virtual void Enable(MxBool p_enable) override; @@ -43,10 +43,10 @@ class MxMediaPresenter : public MxPresenter undefined4 m_unk44; undefined4 m_unk48; undefined4 m_unk4c; -protected: - void Destroy(MxBool); private: void Init(); +protected: + void Destroy(MxBool p_fromDestructor); }; diff --git a/LEGO1/mxmidipresenter.cpp b/LEGO1/mxmidipresenter.cpp index 98868f8a..c0669220 100644 --- a/LEGO1/mxmidipresenter.cpp +++ b/LEGO1/mxmidipresenter.cpp @@ -1,16 +1,39 @@ #include "mxmidipresenter.h" #include "decomp.h" +#include "legoomni.h" +#include "mxmusicmanager.h" DECOMP_SIZE_ASSERT(MxMIDIPresenter, 0x58); // OFFSET: LEGO1 0x100c25e0 -MxMIDIPresenter::MxMIDIPresenter() { +MxMIDIPresenter::MxMIDIPresenter() +{ Init(); } +// OFFSET: LEGO1 0x100c27c0 +MxMIDIPresenter::~MxMIDIPresenter() +{ + Destroy(TRUE); +} + // OFFSET: LEGO1 0x100c2820 void MxMIDIPresenter::Init() { m_unk54 = 0; } + +// OFFSET: LEGO1 0x100c2830 STUB +void MxMIDIPresenter::Destroy(MxBool p_fromDestructor) +{ + // TODO +} + +// OFFSET: LEGO1 0x100c2940 +void MxMIDIPresenter::DoneTickle() +{ + if (!MusicManager()->GetMIDIInitialized()) { + this->EndAction(); + } +} \ No newline at end of file diff --git a/LEGO1/mxmidipresenter.h b/LEGO1/mxmidipresenter.h index 07fc55a2..9fa3e0a6 100644 --- a/LEGO1/mxmidipresenter.h +++ b/LEGO1/mxmidipresenter.h @@ -8,6 +8,7 @@ class MxMIDIPresenter : public MxMusicPresenter { public: MxMIDIPresenter(); + virtual ~MxMIDIPresenter() override; // OFFSET: LEGO1 0x100c2650 inline virtual const char *ClassName() const override // vtable+0xc @@ -22,8 +23,12 @@ class MxMIDIPresenter : public MxMusicPresenter return !strcmp(name, MxMIDIPresenter::ClassName()) || MxMusicPresenter::IsA(name); } + virtual void DoneTickle() override; // vtable+0x2c + private: void Init(); + void Destroy(MxBool); + undefined4 m_unk54; }; diff --git a/LEGO1/mxmusicmanager.cpp b/LEGO1/mxmusicmanager.cpp index 6f49adcc..e481ec8e 100644 --- a/LEGO1/mxmusicmanager.cpp +++ b/LEGO1/mxmusicmanager.cpp @@ -15,7 +15,7 @@ MxMusicManager::MxMusicManager() // OFFSET: LEGO1 0x100c0630 MxMusicManager::~MxMusicManager() { - LockedReinitialize(TRUE); + Destroy(TRUE); } // OFFSET: LEGO1 0x100c0b20 @@ -23,47 +23,47 @@ void MxMusicManager::DeinitializeMIDI() { m_criticalSection.Enter(); - if (this->m_MIDIInitialized) + if (m_MIDIInitialized) { - this->m_MIDIInitialized = FALSE; - midiStreamStop(this->m_MIDIStreamH); - midiOutUnprepareHeader(this->m_MIDIStreamH, this->m_MIDIHdrP, sizeof(MIDIHDR)); - midiOutSetVolume(this->m_MIDIStreamH, this->m_MIDIVolume); - midiStreamClose(this->m_MIDIStreamH); - delete this->m_MIDIHdrP; - this->InitData(); + m_MIDIInitialized = FALSE; + midiStreamStop(m_MIDIStreamH); + midiOutUnprepareHeader(m_MIDIStreamH, m_MIDIHdrP, sizeof(MIDIHDR)); + midiOutSetVolume(m_MIDIStreamH, m_MIDIVolume); + midiStreamClose(m_MIDIStreamH); + delete m_MIDIHdrP; + InitData(); } - this->m_criticalSection.Leave(); + m_criticalSection.Leave(); } // OFFSET: LEGO1 0x100c0690 void MxMusicManager::Init() { - this->m_multiplier = 100; + m_multiplier = 100; InitData(); } // OFFSET: LEGO1 0x100c06a0 void MxMusicManager::InitData() { - this->m_MIDIStreamH = 0; - this->m_MIDIInitialized = FALSE; - this->m_unk38 = 0; - this->m_unk3c = 0; - this->m_unk40 = 0; - this->m_unk44 = 0; - this->m_unk48 = 0; - this->m_MIDIHdrP = NULL; + m_MIDIStreamH = 0; + m_MIDIInitialized = FALSE; + m_unk38 = 0; + m_unk3c = 0; + m_unk40 = 0; + m_unk44 = 0; + m_unk48 = 0; + m_MIDIHdrP = NULL; } // OFFSET: LEGO1 0x100c06c0 -void MxMusicManager::LockedReinitialize(MxBool p_skipDestroy) +void MxMusicManager::Destroy(MxBool p_fromDestructor) { - if (this->m_thread) + if (m_thread) { - this->m_thread->Terminate(); - if (this->m_thread) + m_thread->Terminate(); + if (m_thread) { delete m_thread; } @@ -73,12 +73,12 @@ void MxMusicManager::LockedReinitialize(MxBool p_skipDestroy) TickleManager()->UnregisterClient(this); } - this->m_criticalSection.Enter(); + m_criticalSection.Enter(); DeinitializeMIDI(); Init(); - this->m_criticalSection.Leave(); + m_criticalSection.Leave(); - if (!p_skipDestroy) + if (!p_fromDestructor) { MxAudioManager::Destroy(); } @@ -87,7 +87,7 @@ void MxMusicManager::LockedReinitialize(MxBool p_skipDestroy) // OFFSET: LEGO1 0x100c0930 void MxMusicManager::Destroy() { - LockedReinitialize(FALSE); + Destroy(FALSE); } // OFFSET: LEGO1 0x100c09a0 @@ -100,8 +100,8 @@ MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume) // OFFSET: LEGO1 0x100c07f0 void MxMusicManager::SetMIDIVolume() { - MxS32 result = (this->m_volume * this->m_multiplier) / 0x64; - HMIDISTRM streamHandle = this->m_MIDIStreamH; + MxS32 result = (m_volume * m_multiplier) / 0x64; + HMIDISTRM streamHandle = m_MIDIStreamH; if (streamHandle) { @@ -114,50 +114,38 @@ void MxMusicManager::SetMIDIVolume() void MxMusicManager::SetVolume(MxS32 p_volume) { MxAudioManager::SetVolume(p_volume); - this->m_criticalSection.Enter(); + m_criticalSection.Enter(); SetMIDIVolume(); - this->m_criticalSection.Leave(); + m_criticalSection.Leave(); } // OFFSET: LEGO1 0x100c0840 -MxResult MxMusicManager::StartMIDIThread(MxU32 p_frequencyMS, MxBool p_noRegister) +MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { MxResult status = FAILURE; MxBool locked = FALSE; - MxResult result = MxAudioManager::InitPresenters(); - if (result == SUCCESS) - { - if (p_noRegister) - { - this->m_criticalSection.Enter(); + if (MxAudioManager::InitPresenters() == SUCCESS) { + if (p_createThread) { + m_criticalSection.Enter(); locked = TRUE; - this->m_thread = new MxTickleThread(this, p_frequencyMS); + m_thread = new MxTickleThread(this, p_frequencyMS); - if (this->m_thread) - { - if (this->m_thread->Start(0, 0) == SUCCESS) - { - status = SUCCESS; - } - } + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) + goto done; } else - { TickleManager()->RegisterClient(this, p_frequencyMS); - status = SUCCESS; - } + + status = SUCCESS; } +done: if (status != SUCCESS) - { Destroy(); - } if (locked) - { - this->m_criticalSection.Leave(); - } + m_criticalSection.Leave(); return status; } \ No newline at end of file diff --git a/LEGO1/mxmusicmanager.h b/LEGO1/mxmusicmanager.h index 1a828c84..96031104 100644 --- a/LEGO1/mxmusicmanager.h +++ b/LEGO1/mxmusicmanager.h @@ -14,10 +14,12 @@ class MxMusicManager : public MxAudioManager virtual void Destroy() override; // vtable+18 virtual void SetVolume(MxS32 p_volume) override; // vtable+2c - virtual MxResult StartMIDIThread(MxU32 p_frequencyMS, MxU8 p_noRegister); // vtable+30 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+30 + + inline MxBool GetMIDIInitialized() { return m_MIDIInitialized; } private: - void LockedReinitialize(MxBool p_skipDestroy); + void Destroy(MxBool p_fromDestructor); void DeinitializeMIDI(); MxS32 CalculateVolume(MxS32 p_volume); diff --git a/LEGO1/mxmusicpresenter.cpp b/LEGO1/mxmusicpresenter.cpp index f376c64f..6ae73b6e 100644 --- a/LEGO1/mxmusicpresenter.cpp +++ b/LEGO1/mxmusicpresenter.cpp @@ -24,7 +24,7 @@ void MxMusicPresenter::Init() } // OFFSET: LEGO1 0x100c2550 -void MxMusicPresenter::Destroy(MxBool p_reinit) +void MxMusicPresenter::Destroy(MxBool p_fromDestructor) { if (MusicManager()) { MusicManager()->RemovePresenter(*this); @@ -32,13 +32,13 @@ void MxMusicPresenter::Destroy(MxBool p_reinit) m_criticalSection.Enter(); Init(); m_criticalSection.Leave(); - if (!p_reinit) { + if (!p_fromDestructor) { MxMediaPresenter::Destroy(FALSE); } } // OFFSET: LEGO1 0x100c25a0 -MxResult MxMusicPresenter::AddToMusicManager() +MxResult MxMusicPresenter::AddToManager() { MxResult result = FAILURE; if (MusicManager()) { @@ -49,8 +49,7 @@ MxResult MxMusicPresenter::AddToMusicManager() } // OFFSET: LEGO1 0x100c25d0 -void MxMusicPresenter::vtable38() +void MxMusicPresenter::Destroy() { - // TODO: Name this function when we know what the argument to Destroy does Destroy(FALSE); } diff --git a/LEGO1/mxmusicpresenter.h b/LEGO1/mxmusicpresenter.h index ff765786..653e3330 100644 --- a/LEGO1/mxmusicpresenter.h +++ b/LEGO1/mxmusicpresenter.h @@ -24,12 +24,12 @@ class MxMusicPresenter : public MxAudioPresenter MxMusicPresenter(); virtual ~MxMusicPresenter() override; - virtual MxResult AddToMusicManager(); // vtable+0x34 - virtual void vtable38(); // vtable+0x38 + virtual MxResult AddToManager() override; // vtable+0x34 + virtual void Destroy() override; // vtable+0x38 private: void Init(); - void Destroy(MxBool p_reinit); + void Destroy(MxBool p_fromDestructor); }; #endif // MXMUSICPRESENTER_H diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index 017df73d..e241789e 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -72,7 +72,7 @@ MxResult MxNotificationManager::Tickle() } // OFFSET: LEGO1 0x100ac600 -MxResult MxNotificationManager::Create(MxS32 p_unk1, MxS32 p_unk2) +MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { MxResult result = SUCCESS; m_queue = new MxNotificationPtrList(); diff --git a/LEGO1/mxnotificationmanager.h b/LEGO1/mxnotificationmanager.h index 89908871..adcd6876 100644 --- a/LEGO1/mxnotificationmanager.h +++ b/LEGO1/mxnotificationmanager.h @@ -45,7 +45,7 @@ class MxNotificationManager : public MxCore virtual MxResult Tickle(); // vtable+0x8 // TODO: Where does this method come from? - virtual MxResult Create(MxS32 p_unk1, MxS32 p_unk2); // vtable+0x14 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x14 void Register(MxCore *p_listener); void Unregister(MxCore *p_listener); MxResult Send(MxCore *p_listener, MxNotificationParam *p_param); diff --git a/LEGO1/mxobjectfactory.cpp b/LEGO1/mxobjectfactory.cpp index d52e4dac..bf31bf68 100644 --- a/LEGO1/mxobjectfactory.cpp +++ b/LEGO1/mxobjectfactory.cpp @@ -26,20 +26,22 @@ MxObjectFactory::MxObjectFactory() } // OFFSET: LEGO1 0x100b12c0 -MxCore *MxObjectFactory::Create(const char *name) +MxCore *MxObjectFactory::Create(const char *p_name) { - MxAtomId atom(name, LookupMode_Exact); + MxCore* object = NULL; + MxAtomId atom(p_name, LookupMode_Exact); - if (0) { -#define X(V) } else if (this->m_id##V == atom) { return new V; + if (0) {} +#define X(V) else if (this->m_id##V == atom) { object = new V; } FOR_MXOBJECTFACTORY_OBJECTS(X) #undef X - } else { - return NULL; - } + else {} + + return object; } -// OFFSET: LEGO1 0x100b1a30 STUB -void MxObjectFactory::vtable18(void *) { - // FIXME +// OFFSET: LEGO1 0x100b1a30 +void MxObjectFactory::Destroy(MxCore *p_object) +{ + delete p_object; } diff --git a/LEGO1/mxobjectfactory.h b/LEGO1/mxobjectfactory.h index 53aee2cb..078761f4 100644 --- a/LEGO1/mxobjectfactory.h +++ b/LEGO1/mxobjectfactory.h @@ -23,8 +23,22 @@ class MxObjectFactory : public MxCore { public: MxObjectFactory(); - virtual MxCore *Create(const char *name); // vtable 0x14 - virtual void vtable18(void *); // vtable 0x18 + + // OFFSET: LEGO1 0x10008f70 + inline virtual const char *ClassName() const override // vtable+0xc + { + // 0x100f0730 + return "MxObjectFactory"; + } + + // OFFSET: LEGO1 0x10008f80 + inline virtual MxBool IsA(const char *name) const override // vtable+0x10 + { + return !strcmp(name, MxObjectFactory::ClassName()) || MxCore::IsA(name); + } + + virtual MxCore *Create(const char *p_name); // vtable 0x14 + virtual void Destroy(MxCore *p_object); // vtable 0x18 private: #define X(V) MxAtomId m_id##V; FOR_MXOBJECTFACTORY_OBJECTS(X) diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 43b9578a..88e4bf02 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -189,119 +189,87 @@ void MxOmni::SetInstance(MxOmni *instance) MxResult MxOmni::Create(MxOmniCreateParam &p) { MxResult result = FAILURE; - m_atomIdCounterSet = new MxAtomIdCounterSet(); - if (m_atomIdCounterSet == NULL) - { - goto failure; - } + + if (!(m_atomIdCounterSet = new MxAtomIdCounterSet())) + goto done; + m_mediaPath = p.GetMediaPath(); m_windowHandle = p.GetWindowHandle(); - if (p.CreateFlags().CreateObjectFactory()) - { - MxObjectFactory *objectFactory = new MxObjectFactory(); - this->m_objectFactory = objectFactory; - if (objectFactory == NULL) - goto failure; + if (p.CreateFlags().CreateObjectFactory()) { + if (!(m_objectFactory = new MxObjectFactory())) + goto done; } - if (p.CreateFlags().CreateVariableTable()) - { - MxVariableTable *variableTable = new MxVariableTable(); - this->m_variableTable = variableTable; - - if (variableTable == NULL) - goto failure; + if (p.CreateFlags().CreateVariableTable()) { + if (!(m_variableTable = new MxVariableTable())) + goto done; } - if (p.CreateFlags().CreateTimer()) - { - MxTimer *timer = new MxTimer(); - this->m_timer = timer; - - if (timer == NULL) - return FAILURE; + if (p.CreateFlags().CreateTimer()) { + if (!(m_timer = new MxTimer())) + goto done; } - if (p.CreateFlags().CreateTickleManager()) - { - this->m_tickleManager = new MxTickleManager(); - - if (m_tickleManager == NULL) - goto failure; + if (p.CreateFlags().CreateTickleManager()) { + if (!(m_tickleManager = new MxTickleManager())) + goto done; } - if (p.CreateFlags().CreateNotificationManager()) - { - MxNotificationManager *notificationManager = new MxNotificationManager(); - this->m_notificationManager = notificationManager; - - if (notificationManager == NULL || notificationManager->Create(100, 0) != SUCCESS) - goto failure; + if (p.CreateFlags().CreateNotificationManager()) { + if (m_notificationManager = new MxNotificationManager()) { + if (m_notificationManager->Create(100, 0) != SUCCESS) + goto done; + } + else + goto done; } - if (p.CreateFlags().CreateStreamer()) - { - MxStreamer *streamer = new MxStreamer(); - this->m_streamer = streamer; - - if (streamer == NULL || streamer->Init() != SUCCESS) - goto failure; + if (p.CreateFlags().CreateStreamer()) { + if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS) + goto done; } - if (p.CreateFlags().CreateVideoManager()) - { - MxVideoManager *videoManager = new MxVideoManager(); - this->m_videoManager = videoManager; - - if (videoManager != NULL && videoManager->vtable0x2c(p.GetVideoParam(), 100, 0) != SUCCESS) - { - delete m_videoManager; - m_videoManager = NULL; + if (p.CreateFlags().CreateVideoManager()) { + if (m_videoManager = new MxVideoManager()) { + if (m_videoManager->Create(p.GetVideoParam(), 100, 0) != SUCCESS) { + delete m_videoManager; + m_videoManager = NULL; + } } } - if (p.CreateFlags().CreateSoundManager()) - { - MxSoundManager *soundManager = new MxSoundManager(); - this->m_soundManager = soundManager; - - //TODO - if (soundManager != NULL && soundManager->StartDirectSound(10, 0) != SUCCESS) - { - delete m_soundManager; - m_soundManager = NULL; + if (p.CreateFlags().CreateSoundManager()) { + if (m_soundManager = new MxSoundManager()) { + if (m_soundManager->Create(10, 0) != SUCCESS) { + delete m_soundManager; + m_soundManager = NULL; + } } } - if (p.CreateFlags().CreateMusicManager()) - { - MxMusicManager *musicManager = new MxMusicManager(); - this->m_musicManager = musicManager; - if (musicManager != NULL && musicManager->StartMIDIThread(50, 0) != SUCCESS) - { - delete m_musicManager; - m_musicManager = NULL; + if (p.CreateFlags().CreateMusicManager()) { + if (m_musicManager = new MxMusicManager()) { + if (m_musicManager->Create(50, 0) != SUCCESS) { + delete m_musicManager; + m_musicManager = NULL; + } } } - if (p.CreateFlags().CreateEventManager()) - { - MxEventManager *eventManager = new MxEventManager(); - this->m_eventManager = eventManager; - if (m_eventManager != NULL && m_eventManager->CreateEventThread(50, 0) != SUCCESS) - { - delete m_eventManager; - m_eventManager = NULL; + if (p.CreateFlags().CreateEventManager()) { + if (m_eventManager = new MxEventManager()) { + if (m_eventManager->Create(50, 0) != SUCCESS) { + delete m_eventManager; + m_eventManager = NULL; + } } } result = SUCCESS; - failure: +done: if (result != SUCCESS) - { Destroy(); - } return result; } diff --git a/LEGO1/mxomni.h b/LEGO1/mxomni.h index 265db29b..ab07d2bd 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -93,7 +93,9 @@ __declspec(dllexport) MxVariableTable * VariableTable(); __declspec(dllexport) MxMusicManager * MusicManager(); __declspec(dllexport) MxEventManager * EventManager(); __declspec(dllexport) MxNotificationManager * NotificationManager(); -MxVideoManager * MVideoManager(); -MxAtomIdCounterSet* AtomIdCounterSet(); + +MxVideoManager *MVideoManager(); +MxAtomIdCounterSet *AtomIdCounterSet(); +MxObjectFactory *ObjectFactory(); #endif // MXOMNI_H diff --git a/LEGO1/mxomnicreateparam.h b/LEGO1/mxomnicreateparam.h index d4984b24..ec8a3de1 100644 --- a/LEGO1/mxomnicreateparam.h +++ b/LEGO1/mxomnicreateparam.h @@ -14,7 +14,7 @@ class MxOmniCreateParam : public MxParam __declspec(dllexport) MxOmniCreateParam(const char *mediaPath, struct HWND__ *windowHandle, MxVideoParam &vparam, MxOmniCreateFlags flags); const MxOmniCreateFlags& CreateFlags() const { return this->m_createFlags; } - const MxString GetMediaPath() const { return m_mediaPath; } + const MxString& GetMediaPath() const { return m_mediaPath; } const HWND GetWindowHandle() const { return m_windowHandle; } MxVideoParam& GetVideoParam() { return m_videoParam; } diff --git a/LEGO1/mxpresenter.cpp b/LEGO1/mxpresenter.cpp index 86e4ae26..9f0b55c4 100644 --- a/LEGO1/mxpresenter.cpp +++ b/LEGO1/mxpresenter.cpp @@ -29,7 +29,6 @@ void MxPresenter::Init() // OFFSET: LEGO1 0x100b4fc0 void MxPresenter::ParseExtra() { - MxAutoLocker lock(&m_criticalSection); MxU32 len = m_action->GetExtraLength(); char *extraData = m_action->GetExtraData(); @@ -47,15 +46,13 @@ void MxPresenter::ParseExtra() strcpy(t_token, token); token = strtok(NULL, g_parseExtraTokens); - int val = token ? atoi(token) : 0; - - int result = MxOmni::GetInstance()->vtable0x30(t_token, val, this); + MxS32 val = token ? atoi(token) : 0; + MxS32 result = MxOmni::GetInstance()->vtable0x30(t_token, val, this); m_action->SetFlags(m_action->GetFlags() | MxDSAction::Flag_Parsed); if (result) SendTo_unkPresenter(MxOmni::GetInstance()); - } } } @@ -128,8 +125,8 @@ MxLong MxPresenter::StartAction(MxStreamController *, MxDSAction *p_action) const MxVector3Data& location = this->m_action->GetLocation(); MxS32 previousTickleState = this->m_currentTickleState; - this->m_location = MxPoint32(location[0], location[1]); - this->m_displayZ = location[2]; + this->m_location = MxPoint32(this->m_action->GetLocation()[0], this->m_action->GetLocation()[1]); + this->m_displayZ = this->m_action->GetLocation()[2]; this->m_previousTickleStates |= 1 << (unsigned char)previousTickleState; this->m_currentTickleState = TickleState_Ready; @@ -279,13 +276,13 @@ void MxPresenter::DoneTickle() } // OFFSET: LEGO1 0x1000bf70 -undefined4 MxPresenter::VTable0x34() +MxResult MxPresenter::AddToManager() { - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x1000bf80 -void MxPresenter::InitVirtual() +void MxPresenter::Destroy() { Init(); } diff --git a/LEGO1/mxpresenter.h b/LEGO1/mxpresenter.h index bcdc5aac..09c53298 100644 --- a/LEGO1/mxpresenter.h +++ b/LEGO1/mxpresenter.h @@ -56,8 +56,8 @@ class MxPresenter : public MxCore __declspec(dllexport) virtual void ParseExtra(); // vtable+0x30 public: - virtual undefined4 VTable0x34(); // vtable+0x34 - virtual void InitVirtual(); // vtable+0x38 + virtual MxResult AddToManager(); // vtable+0x34 + virtual void Destroy(); // vtable+0x38 __declspec(dllexport) virtual MxLong StartAction(MxStreamController *, MxDSAction *); // vtable+0x3c __declspec(dllexport) virtual void EndAction(); // vtable+0x40 virtual void SetTickleState(TickleState p_tickleState); // vtable+0x44 diff --git a/LEGO1/mxregion.cpp b/LEGO1/mxregion.cpp new file mode 100644 index 00000000..8b275e24 --- /dev/null +++ b/LEGO1/mxregion.cpp @@ -0,0 +1,39 @@ +#include "mxregion.h" + +DECOMP_SIZE_ASSERT(MxRegion, 0x1c); + +// OFFSET: LEGO1 0x100c31c0 STUB +MxRegion::MxRegion() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c3690 STUB +MxRegion::~MxRegion() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c3700 STUB +void MxRegion::Reset() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c3750 STUB +void MxRegion::vtable18() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c3e20 STUB +void MxRegion::vtable1c() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c3660 STUB +void MxRegion::vtable20() +{ + // TODO +} \ No newline at end of file diff --git a/LEGO1/mxregion.h b/LEGO1/mxregion.h index 717be924..92493c32 100644 --- a/LEGO1/mxregion.h +++ b/LEGO1/mxregion.h @@ -2,6 +2,7 @@ #define MXREGION_H #include "mxcore.h" +#include "decomp.h" // VTABLE 0x100dcae8 // SIZE 0x1c @@ -21,6 +22,7 @@ class MxRegion : public MxCore // MxList *m_rects; // 4 coordinates (could be MxRect32) // MxS32 left, top, right, bottom; + undefined pad[0x14]; }; #endif // MXREGION_H diff --git a/LEGO1/mxsoundmanager.cpp b/LEGO1/mxsoundmanager.cpp index e34534f9..51336843 100644 --- a/LEGO1/mxsoundmanager.cpp +++ b/LEGO1/mxsoundmanager.cpp @@ -24,7 +24,7 @@ void MxSoundManager::Init() } // OFFSET: LEGO1 0x100ae840 -void MxSoundManager::Destroy(MxBool p_param) +void MxSoundManager::Destroy(MxBool p_fromDestructor) { if (this->m_thread) { this->m_thread->Terminate(); @@ -43,15 +43,15 @@ void MxSoundManager::Destroy(MxBool p_param) Init(); this->m_criticalSection.Leave(); - if (!p_param) { + if (!p_fromDestructor) { MxAudioManager::Destroy(); } } // OFFSET: LEGO1 0x100ae8b0 STUB -MxResult MxSoundManager::StartDirectSound(undefined4 p_unknown1, MxBool p_unknown2) +MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { - // TODO STUB + // TODO return FAILURE; } diff --git a/LEGO1/mxsoundmanager.h b/LEGO1/mxsoundmanager.h index 46eef2e7..3bd41085 100644 --- a/LEGO1/mxsoundmanager.h +++ b/LEGO1/mxsoundmanager.h @@ -14,13 +14,13 @@ class MxSoundManager : public MxAudioManager MxSoundManager(); virtual ~MxSoundManager() override; // vtable+0x0 - virtual MxResult StartDirectSound(undefined4 p_unknown1, MxBool p_unknown2); //vtable+0x30 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); //vtable+0x30 virtual void vtable0x34(); // vtable+0x34 virtual void vtable0x38(); // vtable+0x38 private: void Init(); - void Destroy(MxBool); + void Destroy(MxBool p_fromDestructor); undefined4 m_unk30; LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x34 diff --git a/LEGO1/mxstreamer.cpp b/LEGO1/mxstreamer.cpp index e95e4558..84d1b7b9 100644 --- a/LEGO1/mxstreamer.cpp +++ b/LEGO1/mxstreamer.cpp @@ -16,7 +16,7 @@ MxStreamer::MxStreamer() } // OFFSET: LEGO1 0x100b9190 -MxResult MxStreamer::Init() +MxResult MxStreamer::Create() { undefined *b = new undefined[m_subclass1.GetSize() * 0x5800]; m_subclass1.SetBuffer(b); diff --git a/LEGO1/mxstreamer.h b/LEGO1/mxstreamer.h index 529a564a..b5d86e4d 100644 --- a/LEGO1/mxstreamer.h +++ b/LEGO1/mxstreamer.h @@ -90,7 +90,7 @@ class MxStreamer : public MxCore return !strcmp(p_name, MxStreamer::ClassName()) || MxCore::IsA(p_name); } - virtual MxResult Init(); // vtable+0x14 + virtual MxResult Create(); // vtable+0x14 MxStreamController *GetOpenStream(const char *p_name); diff --git a/LEGO1/mxstring.cpp b/LEGO1/mxstring.cpp index fe221f94..e0c34a8a 100644 --- a/LEGO1/mxstring.cpp +++ b/LEGO1/mxstring.cpp @@ -56,7 +56,7 @@ void MxString::ToLowerCase() } // OFFSET: LEGO1 0x100ae4b0 -MxString &MxString::operator=(MxString ¶m) +MxString &MxString::operator=(const MxString ¶m) { if (this->m_data != param.m_data) { diff --git a/LEGO1/mxstring.h b/LEGO1/mxstring.h index ec20f879..c1f8498a 100644 --- a/LEGO1/mxstring.h +++ b/LEGO1/mxstring.h @@ -15,7 +15,7 @@ class MxString : public MxCore MxString(const char *); void ToUpperCase(); void ToLowerCase(); - MxString& operator=(MxString &); + MxString& operator=(const MxString &); MxString operator+(const char *); MxString& operator+=(const char *); diff --git a/LEGO1/mxticklemanager.h b/LEGO1/mxticklemanager.h index cc7b6282..f0aad4cb 100644 --- a/LEGO1/mxticklemanager.h +++ b/LEGO1/mxticklemanager.h @@ -53,14 +53,13 @@ class MxTickleClient MxU16 m_flags; // 0xc }; -class MxTickleClientPtrList : public list -{}; +typedef list MxTickleClientPtrList; // VTABLE 0x100d86d8 class MxTickleManager : public MxCore { public: - inline MxTickleManager() : MxCore(), m_clients() {} + inline MxTickleManager() {} virtual ~MxTickleManager(); // vtable+0x0 (scalar deleting destructor) virtual MxResult Tickle(); // vtable+0x8 diff --git a/LEGO1/mxtransitionmanager.cpp b/LEGO1/mxtransitionmanager.cpp index 12d989c8..9b6ff913 100644 --- a/LEGO1/mxtransitionmanager.cpp +++ b/LEGO1/mxtransitionmanager.cpp @@ -127,34 +127,34 @@ void MxTransitionManager::Transition_Dissolve() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); } if (res == DD_OK) { SubmitCopyRect(&ddsd); - for (MxS32 i = 0; i < 640; i++) { + for (MxS32 col = 0; col < 640; col++) { // Select 16 columns on each tick - if (m_animationTimer * 16 > m_columnOrder[i]) + if (m_animationTimer * 16 > m_columnOrder[col]) continue; - if (m_animationTimer * 16 + 15 < m_columnOrder[i]) + if (m_animationTimer * 16 + 15 < m_columnOrder[col]) continue; - for (MxS32 j = 0; j < 480; j++) { + for (MxS32 row = 0; row < 480; row++) { // Shift the chosen column a different amount at each scanline. // We use the same shift for that scanline each time. // By the end, every pixel gets hit. - MxS32 ofs = (m_randomShift[j] + i) % 640; + MxS32 x_shift = (m_randomShift[row] + col) % 640; // Set the chosen pixel to black if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) { - ((MxU8*)ddsd.lpSurface)[j * ddsd.lPitch + ofs] = 0; + ((MxU8*)ddsd.lpSurface)[row * ddsd.lPitch + x_shift] = 0; } else { - ((MxU16*)ddsd.lpSurface)[j * ddsd.lPitch + ofs] = 0; + ((MxU16*)ddsd.lpSurface)[row * ddsd.lPitch + x_shift] = 0; } } } @@ -164,7 +164,7 @@ void MxTransitionManager::Transition_Dissolve() if (VideoManager()->GetVideoParam().flags().GetFlipSurfaces()) { LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1(); - surf->BltFast(NULL, NULL, m_ddSurface, &g_fullScreenRect, 0x10); + surf->BltFast(NULL, NULL, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); } m_animationTimer++; @@ -230,23 +230,192 @@ void MxTransitionManager::Transition_None() EndTransition(TRUE); } -// OFFSET: LEGO1 0x1004bed0 STUB +// OFFSET: LEGO1 0x1004bed0 void MxTransitionManager::Transition_Pixelation() { - // TODO + if (m_animationTimer == 16) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + if (m_animationTimer == 0) { + // Same init/shuffle steps as the dissolve transition, except that + // we are using big blocky pixels and only need 64 columns. + for (MxS32 i = 0; i < 64; i++) { + m_columnOrder[i] = i; + } + + for (i = 0; i < 64; i++) { + MxS32 swap = rand() % 64; + MxU16 t = m_columnOrder[i]; + m_columnOrder[i] = m_columnOrder[swap]; + m_columnOrder[swap] = t; + } + + // The same is true here. We only need 48 rows. + for (i = 0; i < 48; i++) { + m_randomShift[i] = rand() % 64; + } + } + + // Run one tick of the animation + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + for (MxS32 col = 0; col < 64; col++) { + // Select 4 columns on each tick + if (m_animationTimer * 4 > m_columnOrder[col]) + continue; + + if (m_animationTimer * 4 + 3 < m_columnOrder[col]) + continue; + + for (MxS32 row = 0; row < 48; row++) { + MxS32 x_shift = 10 * ((m_randomShift[row] + col) % 64); + + // To do the pixelation, we subdivide the 640x480 surface into + // 10x10 pixel blocks. At the chosen block, we sample the top-leftmost + // color and set the other 99 pixels to that value. + + // Find the pixel to sample + MxS32 sample_ofs = 10 * row * ddsd.lPitch + x_shift; + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + // Save this cast from void* to save time. + // Seems to help accuracy doing it this way. + MxU8 *surface = (MxU8*)ddsd.lpSurface; + MxU8 *source = surface + sample_ofs * bytesPerPixel; + + MxU32 sample = bytesPerPixel == 1 ? *source + : *(MxU16*)source; + + for (MxS32 k = 10*row; k < 10*row + 10; k++) { + if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) { + // TODO: This block and the next don't match, but they are + // hopefully correct in principle. + MxU16 color_word = MAKEWORD(LOBYTE(sample), LOBYTE(sample)); + MxU32 new_color = MAKELONG(color_word, color_word); + + MxU8 *pos = surface + k * ddsd.lPitch + x_shift; + MxU32 *dest = (MxU32*)pos; + + // Sets 10 pixels (10 bytes) + dest[0] = new_color; + dest[1] = new_color; + MxU16 *half = (MxU16*)(dest+2); + *half = new_color; + } else { + MxU32 new_color = MAKELONG(sample, sample); + + // You might expect a cast to MxU16* instead, but lPitch is + // bytes/scanline, not pixels/scanline. Therefore, we just + // need to double the x_shift to get to the right spot. + MxU8 *pos = surface + k * ddsd.lPitch + 2*x_shift; + MxU32 *dest = (MxU32*)pos; + // Sets 10 pixels (20 bytes) + dest[0] = new_color; + dest[1] = new_color; + dest[2] = new_color; + dest[3] = new_color; + dest[4] = new_color; + } + } + } + } + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + if (VideoManager()->GetVideoParam().flags().GetFlipSurfaces()) { + LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1(); + surf->BltFast(NULL, NULL, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); + } + + m_animationTimer++; + } + } - -// OFFSET: LEGO1 0x1004c270 STUB +// OFFSET: LEGO1 0x1004c270 void MxTransitionManager::Transition_Windows() { - // TODO + if (m_animationTimer == 240) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + MxU8 *line = (MxU8 *) ddsd.lpSurface + m_animationTimer * ddsd.lPitch; + + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + MxS32 bytesPerLine = bytesPerPixel * 640; + + memset(line, 0, bytesPerLine); + + for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer; i++) { + line += ddsd.lPitch; + + memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel); + memset(line + 640 + (-1 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel); + } + + line += ddsd.lPitch; + memset(line, 0, bytesPerLine); + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + m_animationTimer++; + } } -// OFFSET: LEGO1 0x1004c3e0 STUB +// OFFSET: LEGO1 0x1004c3e0 void MxTransitionManager::Transition_Broken() { - // TODO + // This function has no actual animation logic. + // It also never calls EndTransition to + // properly terminate the transition, so + // the game just hangs forever. + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + } } // OFFSET: LEGO1 0x1004c170 @@ -263,10 +432,10 @@ void MxTransitionManager::Transition_Wipe() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); } if (res == DD_OK) { diff --git a/LEGO1/mxvideomanager.cpp b/LEGO1/mxvideomanager.cpp index e1ac9b10..3581add8 100644 --- a/LEGO1/mxvideomanager.cpp +++ b/LEGO1/mxvideomanager.cpp @@ -1,6 +1,8 @@ #include "mxvideomanager.h" #include "mxautolocker.h" #include "mxpresenter.h" +#include "mxticklemanager.h" +#include "legoomni.h" // OFFSET: LEGO1 0x100be1f0 MxVideoManager::MxVideoManager() @@ -8,10 +10,10 @@ MxVideoManager::MxVideoManager() Init(); } -// OFFSET: LEGO1 0x100be2a0 STUB +// OFFSET: LEGO1 0x100be2a0 MxVideoManager::~MxVideoManager() { - // TODO + Destroy(TRUE); } // OFFSET: LEGO1 0x100bea90 @@ -50,6 +52,41 @@ MxResult MxVideoManager::Init() return SUCCESS; } +// OFFSET: LEGO1 0x100be340 +void MxVideoManager::Destroy(MxBool p_fromDestructor) +{ + if (m_thread) { + m_thread->Terminate(); + delete m_thread; + } + else + TickleManager()->UnregisterClient(this); + + m_criticalSection.Enter(); + + if (m_displaySurface) + delete m_displaySurface; + + if (m_region) + delete m_region; + + if (m_videoParam.GetPalette()) + delete m_videoParam.GetPalette(); + + if (m_unk60) { + if (m_pDirectDraw) + m_pDirectDraw->Release(); + if (m_pDDSurface) + m_pDDSurface->Release(); + } + + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) + MxMediaManager::Destroy(); +} + // OFFSET: LEGO1 0x100be440 void MxVideoManager::SortPresenterList() { @@ -89,6 +126,12 @@ void MxVideoManager::UpdateRegion() // TODO } +// OFFSET: LEGO1 0x100bea50 +void MxVideoManager::Destroy() +{ + Destroy(FALSE); +} + // OFFSET: LEGO1 0x100bea60 STUB void MxVideoManager::InvalidateRect(MxRect32 &p_rect) { @@ -96,7 +139,7 @@ void MxVideoManager::InvalidateRect(MxRect32 &p_rect) } // OFFSET: LEGO1 0x100bebe0 -MxLong MxVideoManager::RealizePalette(MxPalette *p_palette) +MxResult MxVideoManager::RealizePalette(MxPalette *p_palette) { PALETTEENTRY paletteEntries[256]; @@ -109,19 +152,151 @@ MxLong MxVideoManager::RealizePalette(MxPalette *p_palette) } this->m_criticalSection.Leave(); - return 0; + return SUCCESS; } -// OFFSET: LEGO1 0x100be600 STUB -void MxVideoManager::vtable0x28() +// OFFSET: LEGO1 0x100be600 +MxResult MxVideoManager::vtable0x28( + MxVideoParam &p_videoParam, + LPDIRECTDRAW p_pDirectDraw, + LPDIRECTDRAWSURFACE p_pDDSurface, + LPDIRECTDRAWSURFACE p_ddSurface1, + LPDIRECTDRAWSURFACE p_ddSurface2, + LPDIRECTDRAWCLIPPER p_ddClipper, + MxU32 p_frequencyMS, + MxBool p_createThread) { + MxBool locked = FALSE; + MxResult status = FAILURE; + m_unk60 = FALSE; + + if (MxMediaManager::InitPresenters() != SUCCESS) + goto done; + + m_criticalSection.Enter(); + locked = TRUE; + + m_videoParam = p_videoParam; + m_region = new MxRegion(); + + if (!m_region) + goto done; + + m_pDirectDraw = p_pDirectDraw; + m_pDDSurface = p_pDDSurface; + + MxPalette *palette; + if (p_videoParam.GetPalette() == NULL) { + palette = new MxPalette(); + m_videoParam.SetPalette(palette); + + if (!palette) + goto done; + } + else { + palette = p_videoParam.GetPalette()->Clone(); + m_videoParam.SetPalette(palette); + + if (!palette) + goto done; + } + + m_displaySurface = new MxDisplaySurface(); + if (m_displaySurface && m_displaySurface->Init(m_videoParam, p_ddSurface1, p_ddSurface2, p_ddClipper) == SUCCESS) { + m_displaySurface->SetPalette(m_videoParam.GetPalette()); + + if (p_createThread) { + m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) + goto done; + } + else + TickleManager()->RegisterClient(this, p_frequencyMS); + + status = SUCCESS; + } + +done: + if (status != SUCCESS) + Destroy(); + + if (locked) + m_criticalSection.Leave(); + + return status; } -// OFFSET: LEGO1 0x100bebe0 STUB -MxResult MxVideoManager::vtable0x2c(MxVideoParam& p_videoParam, undefined4 p_unknown1, MxU8 p_unknown2) +// OFFSET: LEGO1 0x100be820 +MxResult MxVideoManager::Create( + MxVideoParam &p_videoParam, + MxU32 p_frequencyMS, + MxBool p_createThread) { - return FAILURE; + MxBool locked = FALSE; + MxResult status = FAILURE; + + m_unk60 = TRUE; + + if (MxMediaManager::InitPresenters() != SUCCESS) + goto done; + + m_criticalSection.Enter(); + locked = TRUE; + + m_videoParam = p_videoParam; + m_region = new MxRegion(); + + if (!m_region) + goto done; + + if (DirectDrawCreate(NULL, &m_pDirectDraw, NULL) != DD_OK) + goto done; + + if (m_pDirectDraw->SetCooperativeLevel(MxOmni::GetInstance()->GetWindowHandle(), DDSCL_NORMAL) != DD_OK) + goto done; + + MxPalette *palette; + if (p_videoParam.GetPalette() == NULL) { + palette = new MxPalette(); + m_videoParam.SetPalette(palette); + + if (!palette) + goto done; + } + else { + palette = p_videoParam.GetPalette()->Clone(); + m_videoParam.SetPalette(palette); + + if (!palette) + goto done; + } + + m_displaySurface = new MxDisplaySurface(); + if (m_displaySurface && m_displaySurface->Create(m_videoParam) == SUCCESS) { + m_displaySurface->SetPalette(m_videoParam.GetPalette()); + + if (p_createThread) { + m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) + goto done; + } + else + TickleManager()->RegisterClient(this, p_frequencyMS); + + status = SUCCESS; + } + +done: + if (status != SUCCESS) + Destroy(); + + if (locked) + m_criticalSection.Leave(); + + return status; } // OFFSET: LEGO1 0x100be270 diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h index 8b2a6bcc..4631e85c 100644 --- a/LEGO1/mxvideomanager.h +++ b/LEGO1/mxvideomanager.h @@ -12,19 +12,30 @@ class MxVideoManager : public MxMediaManager { public: - virtual ~MxVideoManager(); + virtual ~MxVideoManager() override; virtual MxResult Tickle() override; // vtable+0x8 - virtual void vtable0x28(); // vtable+0x28 (TODO ARGUMENTS) - virtual MxResult vtable0x2c(MxVideoParam& p_videoParam, undefined4 p_unknown1, MxU8 p_unknown2); // vtable+0x2c + virtual void Destroy() override; // vtable+0x18 + virtual MxResult vtable0x28( + MxVideoParam& p_videoParam, + LPDIRECTDRAW p_pDirectDraw, + LPDIRECTDRAWSURFACE p_pDDSurface, + LPDIRECTDRAWSURFACE p_ddSurface1, + LPDIRECTDRAWSURFACE p_ddSurface2, + LPDIRECTDRAWCLIPPER p_ddClipper, + MxU32 p_frequencyMS, + MxBool p_createThread + ); // vtable+0x28 + virtual MxResult Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x2c __declspec(dllexport) void InvalidateRect(MxRect32 &); - __declspec(dllexport) virtual MxLong RealizePalette(MxPalette *); // vtable+0x30 + __declspec(dllexport) virtual MxResult RealizePalette(MxPalette *); // vtable+0x30 virtual void vtable0x34(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height); MxVideoManager(); MxResult Init(); + void Destroy(MxBool p_fromDestructor); void SortPresenterList(); void UpdateRegion(); diff --git a/LEGO1/mxvideoparam.cpp b/LEGO1/mxvideoparam.cpp index 6f74f7a9..aa285106 100644 --- a/LEGO1/mxvideoparam.cpp +++ b/LEGO1/mxvideoparam.cpp @@ -65,11 +65,11 @@ MxVideoParam &MxVideoParam::operator=(const MxVideoParam &p_videoParam) void MxVideoParam::SetDeviceName(char *id) { if (this->m_deviceId != 0) - free(this->m_deviceId); + delete[] this->m_deviceId; if (id != 0) { - this->m_deviceId = (char *)malloc(strlen(id) + 1); + this->m_deviceId = new char[strlen(id) + 1]; if (this->m_deviceId != 0) { strcpy(this->m_deviceId, id); @@ -84,5 +84,5 @@ void MxVideoParam::SetDeviceName(char *id) MxVideoParam::~MxVideoParam() { if (this->m_deviceId != 0) - free(this->m_deviceId); + delete[] this->m_deviceId; } diff --git a/LEGO1/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index ce7e9287..8e65bcce 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -34,7 +34,7 @@ MxVideoPresenter::~MxVideoPresenter() } // OFFSET: LEGO1 0x1000c7a0 -void MxVideoPresenter::InitVirtual() +void MxVideoPresenter::Destroy() { Destroy(FALSE); } @@ -85,7 +85,7 @@ void MxVideoPresenter::Init() } // OFFSET: LEGO1 0x100b27b0 -void MxVideoPresenter::Destroy(MxBool p_reinit) +void MxVideoPresenter::Destroy(MxBool p_fromDestructor) { MxRect32 rect; if (MVideoManager() != NULL) diff --git a/LEGO1/mxvideopresenter.h b/LEGO1/mxvideopresenter.h index 5e7a5c66..6caeabc2 100644 --- a/LEGO1/mxvideopresenter.h +++ b/LEGO1/mxvideopresenter.h @@ -31,9 +31,9 @@ class MxVideoPresenter : public MxMediaPresenter } void Init(); - void Destroy(MxBool); + void Destroy(MxBool p_fromDestructor); - virtual void InitVirtual() override; // vtable+0x38 + virtual void Destroy() override; // vtable+0x38 virtual void VTable0x5c(undefined4 p_unknown1); // vtable+0x5c virtual void VTable0x60(); // vtable+0x60