diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d02143c..e14f01d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,6 +70,11 @@ jobs: path: legobin key: legobin + - name: Build isledecomp library + shell: bash + run: | + pip install tools/isledecomp + - name: Summarize Accuracy shell: bash run: | diff --git a/.github/workflows/order.yml b/.github/workflows/order.yml new file mode 100644 index 00000000..6a0ee029 --- /dev/null +++ b/.github/workflows/order.yml @@ -0,0 +1,20 @@ +name: Check order + +on: [push, pull_request] + +jobs: + checkorder: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Build isledecomp library + run: | + pip install tools/isledecomp + + - name: Run checkorder.py + run: | + pip install -r tools/checkorder/requirements.txt + python3 tools/checkorder/checkorder.py --verbose --enforce ISLE + python3 tools/checkorder/checkorder.py --verbose --enforce LEGO1 diff --git a/.gitignore b/.gitignore index c41df18b..4e1970c2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ build/ *.swp LEGO1PROGRESS.HTML LEGO1PROGRESS.SVG +*.pyc diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 775f038c..b3c1ae05 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -281,6 +281,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine return msg.wParam; } +// OFFSET: ISLE 0x401c40 TEMPLATE +// MxDSObject::SetAtomId + // OFFSET: ISLE 0x401ca0 BOOL FindExistingInstance(void) { diff --git a/LEGO1/legobuildingmanager.cpp b/LEGO1/legobuildingmanager.cpp index b4450e2e..6cbd14fb 100644 --- a/LEGO1/legobuildingmanager.cpp +++ b/LEGO1/legobuildingmanager.cpp @@ -3,6 +3,12 @@ // 0x100f37cc int g_buildingManagerConfig = 1; +// OFFSET: LEGO1 0x1002f8b0 +void LegoBuildingManager::configureLegoBuildingManager(int param_1) +{ + g_buildingManagerConfig = param_1; +} + // OFFSET: LEGO1 0x1002f8c0 LegoBuildingManager::LegoBuildingManager() { @@ -20,9 +26,3 @@ void LegoBuildingManager::Init() { // TODO } - -// OFFSET: LEGO1 0x1002f8b0 -void LegoBuildingManager::configureLegoBuildingManager(int param_1) -{ - g_buildingManagerConfig = param_1; -} diff --git a/LEGO1/legocarbuild.cpp b/LEGO1/legocarbuild.cpp index e6f6ab36..faf504d8 100644 --- a/LEGO1/legocarbuild.cpp +++ b/LEGO1/legocarbuild.cpp @@ -12,14 +12,6 @@ LegoCarBuild::~LegoCarBuild() // TODO } -// OFFSET: LEGO1 0x10024050 STUB -MxLong LegoCarBuild::Notify(MxParam& p) -{ - // TODO - - return 0; -} - // OFFSET: LEGO1 0x100238b0 STUB MxResult LegoCarBuild::Tickle() { @@ -27,3 +19,11 @@ MxResult LegoCarBuild::Tickle() return 0; } + +// OFFSET: LEGO1 0x10024050 STUB +MxLong LegoCarBuild::Notify(MxParam& p) +{ + // TODO + + return 0; +} diff --git a/LEGO1/legocontrolmanager.cpp b/LEGO1/legocontrolmanager.cpp index 0da55e46..70a3502c 100644 --- a/LEGO1/legocontrolmanager.cpp +++ b/LEGO1/legocontrolmanager.cpp @@ -12,14 +12,6 @@ LegoControlManager::~LegoControlManager() // TODO } -// OFFSET: LEGO1 0x10029600 STUB -MxResult LegoControlManager::Tickle() -{ - // TODO - - return 0; -} - // OFFSET: LEGO1 0x10028e10 STUB void LegoControlManager::Register(MxCore* p_listener) { @@ -31,3 +23,11 @@ void LegoControlManager::Unregister(MxCore* p_listener) { // TODO } + +// OFFSET: LEGO1 0x10029600 STUB +MxResult LegoControlManager::Tickle() +{ + // TODO + + return 0; +} diff --git a/LEGO1/legoentity.cpp b/LEGO1/legoentity.cpp index f5c6477c..497cb9e3 100644 --- a/LEGO1/legoentity.cpp +++ b/LEGO1/legoentity.cpp @@ -7,6 +7,9 @@ DECOMP_SIZE_ASSERT(LegoEntity, 0x68) +// OFFSET: LEGO1 0x10001090 TEMPLATE +// LegoEntity::SetWorldSpeed + // OFFSET: LEGO1 0x1000c290 LegoEntity::~LegoEntity() { diff --git a/LEGO1/legoentity.h b/LEGO1/legoentity.h index 0c559fb7..a15eaffb 100644 --- a/LEGO1/legoentity.h +++ b/LEGO1/legoentity.h @@ -38,15 +38,14 @@ class LegoEntity : public MxEntity { virtual void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2); // vtable+0x24 virtual void SetWorldTransform(Vector3Impl& p_loc, Vector3Impl& p_dir, Vector3Impl& p_up); // vtable+0x28 virtual void ResetWorldTransform(MxBool p_inVehicle); // vtable+0x2c - // OFFSET: LEGO1 0x10001090 - virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 - virtual void VTable0x34(); // vtable+0x34 - virtual void VTable0x38(); // vtable+0x38 - virtual void VTable0x3c(); // vtable+0x3c - virtual void VTable0x40(); // vtable+0x40 - virtual void VTable0x44(); // vtable+0x44 - virtual void VTable0x48(); // vtable+0x48 - virtual void VTable0x4c(); // vtable+0x4c + virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 + virtual void VTable0x34(); // vtable+0x34 + virtual void VTable0x38(); // vtable+0x38 + virtual void VTable0x3c(); // vtable+0x3c + virtual void VTable0x40(); // vtable+0x40 + virtual void VTable0x44(); // vtable+0x44 + virtual void VTable0x48(); // vtable+0x48 + virtual void VTable0x4c(); // vtable+0x4c protected: void Init(); diff --git a/LEGO1/legogamestate.cpp b/LEGO1/legogamestate.cpp index e95a7470..dfdfcde2 100644 --- a/LEGO1/legogamestate.cpp +++ b/LEGO1/legogamestate.cpp @@ -78,42 +78,6 @@ LegoGameState::~LegoGameState() delete[] m_savePath; } -// OFFSET: LEGO1 0x10039c60 STUB -MxResult LegoGameState::Load(MxULong) -{ - // TODO - return 0; -} - -// OFFSET: LEGO1 0x1003a170 -void LegoGameState::GetFileSavePath(MxString* p_outPath, MxULong p_slotn) -{ - 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 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) { @@ -152,22 +116,11 @@ MxResult LegoGameState::Save(MxULong p_slot) return result; } -// OFFSET: LEGO1 0x1003a2e0 STUB -void LegoGameState::SerializePlayersInfo(MxS16 p) +// OFFSET: LEGO1 0x10039c60 STUB +MxResult LegoGameState::Load(MxULong) { // TODO -} - -// OFFSET: LEGO1 0x1003cdd0 STUB -void LegoGameState::SerializeScoreHistory(MxS16 p) -{ - // TODO -} - -// OFFSET: LEGO1 0x1003cea0 -void LegoGameState::SetSomeEnumState(undefined4 p_state) -{ - m_unk10 = p_state; + return 0; } // OFFSET: LEGO1 0x10039f00 @@ -184,6 +137,53 @@ void LegoGameState::SetSavePath(char* p_savePath) m_savePath = NULL; } +// 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 0x1003a170 +void LegoGameState::GetFileSavePath(MxString* p_outPath, MxULong p_slotn) +{ + 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 STUB +void LegoGameState::SerializePlayersInfo(MxS16 p) +{ + // TODO +} + +// OFFSET: LEGO1 0x1003a720 STUB +void LegoGameState::FUN_1003a720(MxU32 p_unk) +{ + // TODO +} + +// OFFSET: LEGO1 0x1003b060 STUB +void LegoGameState::HandleAction(MxU32 p_unk) +{ + // TODO +} + // OFFSET: LEGO1 0x1003bac0 void LegoGameState::SetROIHandlerFunction() { @@ -255,14 +255,14 @@ void LegoGameState::RegisterState(LegoState* p_state) m_stateArray[targetIndex] = p_state; } -// OFFSET: LEGO1 0x1003a720 STUB -void LegoGameState::FUN_1003a720(MxU32 p_unk) +// OFFSET: LEGO1 0x1003cdd0 STUB +void LegoGameState::SerializeScoreHistory(MxS16 p) { // TODO } -// OFFSET: LEGO1 0x1003b060 STUB -void LegoGameState::HandleAction(MxU32 p_unk) +// OFFSET: LEGO1 0x1003cea0 +void LegoGameState::SetSomeEnumState(undefined4 p_state) { - // TODO + m_unk10 = p_state; } diff --git a/LEGO1/legonavcontroller.cpp b/LEGO1/legonavcontroller.cpp index eefbbed1..0ba619e6 100644 --- a/LEGO1/legonavcontroller.cpp +++ b/LEGO1/legonavcontroller.cpp @@ -30,62 +30,6 @@ float g_turnSensitivity = 0.4f; // 0x100f4c54 MxBool g_turnUseVelocity = FALSE; -// OFFSET: LEGO1 0x10054d40 -void LegoNavController::GetDefaults( - int* p_mouseDeadzone, - float* p_movementMaxSpeed, - float* p_turnMaxSpeed, - float* p_movementMaxAccel, - float* p_turnMaxAccel, - float* p_movementDecel, - float* p_turnDecel, - float* p_movementMinAccel, - float* p_turnMinAccel, - float* p_turnSensitivity, - MxBool* p_turnUseVelocity -) -{ - *p_mouseDeadzone = g_mouseDeadzone; - *p_movementMaxSpeed = g_movementMaxSpeed; - *p_turnMaxSpeed = g_turnMaxSpeed; - *p_movementMaxAccel = g_movementMaxAccel; - *p_turnMaxAccel = g_turnMaxAccel; - *p_movementDecel = g_movementDecel; - *p_turnDecel = g_turnDecel; - *p_movementMinAccel = g_movementMinAccel; - *p_turnMinAccel = g_turnMinAccel; - *p_turnSensitivity = g_turnSensitivity; - *p_turnUseVelocity = g_turnUseVelocity; -} - -// OFFSET: LEGO1 0x10054dd0 -void LegoNavController::SetDefaults( - int p_mouseDeadzone, - float p_movementMaxSpeed, - float p_turnMaxSpeed, - float p_movementMaxAccel, - float p_turnMaxAccel, - float p_movementDecel, - float p_turnDecel, - float p_movementMinAccel, - float p_turnMinAccel, - float p_turnSensitivity, - MxBool p_turnUseVelocity -) -{ - g_mouseDeadzone = p_mouseDeadzone; - g_movementMaxSpeed = p_movementMaxSpeed; - g_turnMaxSpeed = p_turnMaxSpeed; - g_movementMaxAccel = p_movementMaxAccel; - g_turnMaxAccel = p_turnMaxAccel; - g_movementDecel = p_movementDecel; - g_turnDecel = p_turnDecel; - g_movementMinAccel = p_movementMinAccel; - g_turnMinAccel = p_turnMinAccel; - g_turnSensitivity = p_turnSensitivity; - g_turnUseVelocity = p_turnUseVelocity; -} - // OFFSET: LEGO1 0x10054ac0 LegoNavController::LegoNavController() { @@ -145,6 +89,62 @@ void LegoNavController::ResetToDefault() this->m_turnSensitivity = g_turnSensitivity; } +// OFFSET: LEGO1 0x10054d40 +void LegoNavController::GetDefaults( + int* p_mouseDeadzone, + float* p_movementMaxSpeed, + float* p_turnMaxSpeed, + float* p_movementMaxAccel, + float* p_turnMaxAccel, + float* p_movementDecel, + float* p_turnDecel, + float* p_movementMinAccel, + float* p_turnMinAccel, + float* p_turnSensitivity, + MxBool* p_turnUseVelocity +) +{ + *p_mouseDeadzone = g_mouseDeadzone; + *p_movementMaxSpeed = g_movementMaxSpeed; + *p_turnMaxSpeed = g_turnMaxSpeed; + *p_movementMaxAccel = g_movementMaxAccel; + *p_turnMaxAccel = g_turnMaxAccel; + *p_movementDecel = g_movementDecel; + *p_turnDecel = g_turnDecel; + *p_movementMinAccel = g_movementMinAccel; + *p_turnMinAccel = g_turnMinAccel; + *p_turnSensitivity = g_turnSensitivity; + *p_turnUseVelocity = g_turnUseVelocity; +} + +// OFFSET: LEGO1 0x10054dd0 +void LegoNavController::SetDefaults( + int p_mouseDeadzone, + float p_movementMaxSpeed, + float p_turnMaxSpeed, + float p_movementMaxAccel, + float p_turnMaxAccel, + float p_movementDecel, + float p_turnDecel, + float p_movementMinAccel, + float p_turnMinAccel, + float p_turnSensitivity, + MxBool p_turnUseVelocity +) +{ + g_mouseDeadzone = p_mouseDeadzone; + g_movementMaxSpeed = p_movementMaxSpeed; + g_turnMaxSpeed = p_turnMaxSpeed; + g_movementMaxAccel = p_movementMaxAccel; + g_turnMaxAccel = p_turnMaxAccel; + g_movementDecel = p_movementDecel; + g_turnDecel = p_turnDecel; + g_movementMinAccel = p_movementMinAccel; + g_turnMinAccel = p_turnMinAccel; + g_turnSensitivity = p_turnSensitivity; + g_turnUseVelocity = p_turnUseVelocity; +} + // OFFSET: LEGO1 0x10054e40 void LegoNavController::SetTargets(int p_hPos, int p_vPos, MxBool p_accel) { diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 0a9b6b31..50c800fa 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -109,124 +109,6 @@ const char* g_current = "current"; // 0x101020e8 void (*g_omniUserMessage)(const char*, int); -// OFFSET: LEGO1 0x10058a00 -LegoOmni::LegoOmni() -{ - Init(); -} - -// OFFSET: LEGO1 0x10058b50 -LegoOmni::~LegoOmni() -{ - Destroy(); -} - -// OFFSET: LEGO1 0x1005b560 -void LegoOmni::CreateBackgroundAudio() -{ - if (m_bkgAudioManager) - m_bkgAudioManager->Create(*g_jukeboxScript, 100); -} - -// OFFSET: LEGO1 0x1005af10 STUB -void LegoOmni::RemoveWorld(const MxAtomId& p1, MxLong p2) -{ - // TODO -} - -// OFFSET: LEGO1 0x1005b0c0 STUB -LegoEntity* LegoOmni::FindByEntityIdOrAtomId(const MxAtomId& p_atom, MxS32 p_entityid) -{ - // TODO - return NULL; -} - -// OFFSET: LEGO1 0x1005b400 STUB -int LegoOmni::GetCurrPathInfo(LegoPathBoundary**, int&) -{ - // TODO - return 0; -} - -// OFFSET: LEGO1 0x100b6ff0 -void MakeSourceName(char* p_output, const char* p_input) -{ - const char* cln = strchr(p_input, ':'); - if (cln) { - p_input = cln + 1; - } - - strcpy(p_output, p_input); - - strlwr(p_output); - - char* extLoc = strstr(p_output, ".si"); - if (extLoc) { - *extLoc = 0; - } -} - -// OFFSET: LEGO1 0x100b7050 -MxBool KeyValueStringParse(char* p_outputValue, const char* p_key, const char* p_source) -{ - MxBool didMatch = FALSE; - - MxS16 len = strlen(p_source); - char* temp = new char[len + 1]; - strcpy(temp, p_source); - - char* token = strtok(temp, ", \t\r\n:"); - while (token) { - len -= (strlen(token) + 1); - - if (strcmpi(token, p_key) == 0) { - if (p_outputValue && len > 0) { - char* cur = &token[strlen(p_key)]; - cur++; - while (*cur != ',') { - if (*cur == ' ' || *cur == '\0' || *cur == '\t' || *cur == '\n' || *cur == '\r') - break; - *p_outputValue++ = *cur++; - } - *p_outputValue = '\0'; - } - - didMatch = TRUE; - break; - } - - token = strtok(NULL, ", \t\r\n:"); - } - - delete[] temp; - return didMatch; -} - -// OFFSET: LEGO1 0x100b7210 -void SetOmniUserMessage(void (*p_userMsg)(const char*, int)) -{ - g_omniUserMessage = p_userMsg; -} - -// OFFSET: LEGO1 0x100acf50 -MxResult Start(MxDSAction* p_dsAction) -{ - return MxOmni::GetInstance()->Start(p_dsAction); -} - -// OFFSET: LEGO1 0x1005ad10 -LegoOmni* LegoOmni::GetInstance() -{ - return (LegoOmni*) MxOmni::GetInstance(); -} - -// OFFSET: LEGO1 0x1005ac90 -void LegoOmni::CreateInstance() -{ - MxOmni::DestroyInstance(); - MxOmni::SetInstance(new LegoOmni()); -} - // OFFSET: LEGO1 0x10015700 LegoOmni* Lego() { @@ -334,52 +216,10 @@ void PlayMusic(MxU32 p_index) LegoOmni::GetInstance()->GetBackgroundAudioManager()->PlayMusic(action, 5, 4); } -// OFFSET: LEGO1 0x100c0280 -MxDSObject* CreateStreamObject(MxDSFile* p_file, MxS16 p_ofs) -{ - char* buf; - _MMCKINFO tmp_chunk; - - if (p_file->Seek(((MxLong*) p_file->GetBuffer())[p_ofs], 0)) { - return NULL; - } - - if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'S', 't')) { - if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'O', 'b')) { - - buf = new char[tmp_chunk.cksize]; - if (!buf) { - return NULL; - } - - if (p_file->Read((MxU8*) buf, tmp_chunk.cksize) != 0) { - return NULL; - } - - // Save a copy so we can clean up properly, because - // this function will alter the pointer value. - char* copy = buf; - MxDSObject* obj = DeserializeDSObjectDispatch(&buf, -1); - delete[] copy; - return obj; - } - return NULL; - } - - return NULL; -} - -// OFFSET: LEGO1 0x10053430 -const char* GetNoCD_SourceName() -{ - return g_nocdSourceName->GetInternal(); -} - -// OFFSET: LEGO1 0x1005b5f0 STUB -MxLong LegoOmni::Notify(MxParam& p) +// OFFSET: LEGO1 0x1001a700 STUB +void FUN_1001a700() { // TODO - return 0; } // OFFSET: LEGO1 0x1003dd70 STUB @@ -396,180 +236,6 @@ LegoEntity* PickEntity(MxLong, MxLong) return NULL; } -// OFFSET: LEGO1 0x10058bd0 -void LegoOmni::Init() -{ - MxOmni::Init(); - m_unk68 = 0; - m_inputMgr = NULL; - m_unk6c = 0; - m_gifManager = NULL; - m_unk78 = 0; - m_currentWorld = NULL; - m_unk80 = FALSE; - m_currentVehicle = NULL; - m_unkLegoSaveDataWriter = NULL; - m_plantManager = NULL; - m_gameState = NULL; - m_animationManager = NULL; - m_buildingManager = NULL; - m_bkgAudioManager = NULL; - m_unk13c = TRUE; - m_transitionManager = NULL; -} - -// OFFSET: LEGO1 0x1001a700 STUB -void FUN_1001a700() -{ - // TODO -} - -// OFFSET: LEGO1 0x10058e70 -MxResult LegoOmni::Create(MxOmniCreateParam& p) -{ - MxResult result = FAILURE; - MxAutoLocker lock(&this->m_criticalsection); - - p.CreateFlags().CreateObjectFactory(FALSE); - p.CreateFlags().CreateVideoManager(FALSE); - p.CreateFlags().CreateSoundManager(FALSE); - p.CreateFlags().CreateTickleManager(FALSE); - - if (!(m_tickleManager = new MxTickleManager())) - return FAILURE; - - if (MxOmni::Create(p) != SUCCESS) - return FAILURE; - - m_objectFactory = new LegoObjectFactory(); - if (m_objectFactory == NULL) - return FAILURE; - - if (m_soundManager = new LegoSoundManager()) { - if (m_soundManager->Create(10, 0) != SUCCESS) { - delete m_soundManager; - m_soundManager = NULL; - return FAILURE; - } - } - - if (m_videoManager = new LegoVideoManager()) { - if (m_videoManager->Create(p.GetVideoParam(), 100, 0) != SUCCESS) { - delete m_videoManager; - m_videoManager = NULL; - } - } - - if (m_inputMgr = new LegoInputManager()) { - if (m_inputMgr->Create(p.GetWindowHandle()) != SUCCESS) { - delete m_inputMgr; - m_inputMgr = NULL; - } - } - - // TODO: there are a few more classes here - m_gifManager = new GifManager(); - m_plantManager = new LegoPlantManager(); - m_animationManager = new LegoAnimationManager(); - m_buildingManager = new LegoBuildingManager(); - m_gameState = new LegoGameState(); - // TODO: initialize list at m_unk78 - - if (m_unk6c && m_gifManager && m_unk78 && m_plantManager && m_animationManager && m_buildingManager) { - // TODO: initialize a bunch of MxVariables - RegisterScripts(); - FUN_1001a700(); - // todo: another function call. in legoomni maybe? - m_bkgAudioManager = new MxBackgroundAudioManager(); - if (m_bkgAudioManager != NULL) { - m_transitionManager = new MxTransitionManager(); - if (m_transitionManager != NULL) { - if (m_transitionManager->GetDDrawSurfaceFromVideoManager() == SUCCESS) { - m_notificationManager->Register(this); - SetAppCursor(1); - m_gameState->SetSomeEnumState(0); - return SUCCESS; - } - } - } - } - - return FAILURE; -} - -// OFFSET: LEGO1 0x10058c30 STUB -void LegoOmni::Destroy() -{ - // TODO -} - -// OFFSET: LEGO1 0x1005b580 -MxResult LegoOmni::Start(MxDSAction* action) -{ - MxResult result = MxOmni::Start(action); - this->m_action.SetAtomId(action->GetAtomId()); - this->m_action.SetObjectId(action->GetObjectId()); - this->m_action.SetUnknown24(action->GetUnknown24()); - return result; -} - -// OFFSET: LEGO1 0x1005b1d0 STUB -MxResult LegoOmni::DeleteObject(MxDSAction& ds) -{ - // TODO - return FAILURE; -} - -// OFFSET: LEGO1 0x1005b3c0 -MxBool LegoOmni::DoesEntityExist(MxDSAction& ds) -{ - if (MxOmni::DoesEntityExist(ds)) { - if (FindByEntityIdOrAtomId(ds.GetAtomId(), ds.GetObjectId()) == NULL) { - return TRUE; - } - } - return FALSE; -} - -// OFFSET: LEGO1 0x1005b2f0 -MxEntity* LegoOmni::FindWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter) -{ - LegoWorld* foundEntity = NULL; - if (strcmpi(p_id, g_current)) { - foundEntity = (LegoWorld*) FindByEntityIdOrAtomId(MxAtomId(p_id, LookupMode_LowerCase2), p_entityId); - } - else { - foundEntity = this->m_currentWorld; - } - - if (foundEntity != NULL) { - foundEntity->VTable0x58(p_presenter); - } - - return foundEntity; -} - -// OFFSET: LEGO1 0x1005b3a0 -void LegoOmni::NotifyCurrentEntity(MxNotificationParam* p_param) -{ - if (m_currentWorld) - NotificationManager()->Send(m_currentWorld, p_param); -} - -// OFFSET: LEGO1 0x1005b640 -void LegoOmni::StartTimer() -{ - MxOmni::StartTimer(); - SetAppCursor(2); -} - -// OFFSET: LEGO1 0x1005b650 -void LegoOmni::StopTimer() -{ - MxOmni::StopTimer(); - SetAppCursor(0); -} - // OFFSET: LEGO1 0x100528e0 void RegisterScripts() { @@ -665,3 +331,337 @@ void UnregisterScripts() g_creditsScript = NULL; g_nocdSourceName = NULL; } + +// OFFSET: LEGO1 0x10053430 +const char* GetNoCD_SourceName() +{ + return g_nocdSourceName->GetInternal(); +} + +// OFFSET: LEGO1 0x10058a00 +LegoOmni::LegoOmni() +{ + Init(); +} + +// OFFSET: LEGO1 0x10058b50 +LegoOmni::~LegoOmni() +{ + Destroy(); +} + +// OFFSET: LEGO1 0x10058bd0 +void LegoOmni::Init() +{ + MxOmni::Init(); + m_unk68 = 0; + m_inputMgr = NULL; + m_unk6c = 0; + m_gifManager = NULL; + m_unk78 = 0; + m_currentWorld = NULL; + m_unk80 = FALSE; + m_currentVehicle = NULL; + m_unkLegoSaveDataWriter = NULL; + m_plantManager = NULL; + m_gameState = NULL; + m_animationManager = NULL; + m_buildingManager = NULL; + m_bkgAudioManager = NULL; + m_unk13c = TRUE; + m_transitionManager = NULL; +} + +// OFFSET: LEGO1 0x10058c30 STUB +void LegoOmni::Destroy() +{ + // TODO +} + +// OFFSET: LEGO1 0x10058e70 +MxResult LegoOmni::Create(MxOmniCreateParam& p) +{ + MxResult result = FAILURE; + MxAutoLocker lock(&this->m_criticalsection); + + p.CreateFlags().CreateObjectFactory(FALSE); + p.CreateFlags().CreateVideoManager(FALSE); + p.CreateFlags().CreateSoundManager(FALSE); + p.CreateFlags().CreateTickleManager(FALSE); + + if (!(m_tickleManager = new MxTickleManager())) + return FAILURE; + + if (MxOmni::Create(p) != SUCCESS) + return FAILURE; + + m_objectFactory = new LegoObjectFactory(); + if (m_objectFactory == NULL) + return FAILURE; + + if (m_soundManager = new LegoSoundManager()) { + if (m_soundManager->Create(10, 0) != SUCCESS) { + delete m_soundManager; + m_soundManager = NULL; + return FAILURE; + } + } + + if (m_videoManager = new LegoVideoManager()) { + if (m_videoManager->Create(p.GetVideoParam(), 100, 0) != SUCCESS) { + delete m_videoManager; + m_videoManager = NULL; + } + } + + if (m_inputMgr = new LegoInputManager()) { + if (m_inputMgr->Create(p.GetWindowHandle()) != SUCCESS) { + delete m_inputMgr; + m_inputMgr = NULL; + } + } + + // TODO: there are a few more classes here + m_gifManager = new GifManager(); + m_plantManager = new LegoPlantManager(); + m_animationManager = new LegoAnimationManager(); + m_buildingManager = new LegoBuildingManager(); + m_gameState = new LegoGameState(); + // TODO: initialize list at m_unk78 + + if (m_unk6c && m_gifManager && m_unk78 && m_plantManager && m_animationManager && m_buildingManager) { + // TODO: initialize a bunch of MxVariables + RegisterScripts(); + FUN_1001a700(); + // todo: another function call. in legoomni maybe? + m_bkgAudioManager = new MxBackgroundAudioManager(); + if (m_bkgAudioManager != NULL) { + m_transitionManager = new MxTransitionManager(); + if (m_transitionManager != NULL) { + if (m_transitionManager->GetDDrawSurfaceFromVideoManager() == SUCCESS) { + m_notificationManager->Register(this); + SetAppCursor(1); + m_gameState->SetSomeEnumState(0); + return SUCCESS; + } + } + } + } + + return FAILURE; +} + +// OFFSET: LEGO1 0x1005ac90 +void LegoOmni::CreateInstance() +{ + MxOmni::DestroyInstance(); + MxOmni::SetInstance(new LegoOmni()); +} + +// OFFSET: LEGO1 0x1005ad10 +LegoOmni* LegoOmni::GetInstance() +{ + return (LegoOmni*) MxOmni::GetInstance(); +} + +// OFFSET: LEGO1 0x1005af10 STUB +void LegoOmni::RemoveWorld(const MxAtomId& p1, MxLong p2) +{ + // TODO +} + +// OFFSET: LEGO1 0x1005b0c0 STUB +LegoEntity* LegoOmni::FindByEntityIdOrAtomId(const MxAtomId& p_atom, MxS32 p_entityid) +{ + // TODO + return NULL; +} + +// OFFSET: LEGO1 0x1005b1d0 STUB +MxResult LegoOmni::DeleteObject(MxDSAction& ds) +{ + // TODO + return FAILURE; +} + +// OFFSET: LEGO1 0x1005b2f0 +MxEntity* LegoOmni::FindWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter) +{ + LegoWorld* foundEntity = NULL; + if (strcmpi(p_id, g_current)) { + foundEntity = (LegoWorld*) FindByEntityIdOrAtomId(MxAtomId(p_id, LookupMode_LowerCase2), p_entityId); + } + else { + foundEntity = this->m_currentWorld; + } + + if (foundEntity != NULL) { + foundEntity->VTable0x58(p_presenter); + } + + return foundEntity; +} + +// OFFSET: LEGO1 0x1005b3a0 +void LegoOmni::NotifyCurrentEntity(MxNotificationParam* p_param) +{ + if (m_currentWorld) + NotificationManager()->Send(m_currentWorld, p_param); +} + +// OFFSET: LEGO1 0x1005b3c0 +MxBool LegoOmni::DoesEntityExist(MxDSAction& ds) +{ + if (MxOmni::DoesEntityExist(ds)) { + if (FindByEntityIdOrAtomId(ds.GetAtomId(), ds.GetObjectId()) == NULL) { + return TRUE; + } + } + return FALSE; +} + +// OFFSET: LEGO1 0x1005b400 STUB +int LegoOmni::GetCurrPathInfo(LegoPathBoundary**, int&) +{ + // TODO + return 0; +} + +// OFFSET: LEGO1 0x1005b560 +void LegoOmni::CreateBackgroundAudio() +{ + if (m_bkgAudioManager) + m_bkgAudioManager->Create(*g_jukeboxScript, 100); +} + +// OFFSET: LEGO1 0x1005b580 +MxResult LegoOmni::Start(MxDSAction* action) +{ + MxResult result = MxOmni::Start(action); + this->m_action.SetAtomId(action->GetAtomId()); + this->m_action.SetObjectId(action->GetObjectId()); + this->m_action.SetUnknown24(action->GetUnknown24()); + return result; +} + +// OFFSET: LEGO1 0x1005b5f0 STUB +MxLong LegoOmni::Notify(MxParam& p) +{ + // TODO + return 0; +} + +// OFFSET: LEGO1 0x1005b640 +void LegoOmni::StartTimer() +{ + MxOmni::StartTimer(); + SetAppCursor(2); +} + +// OFFSET: LEGO1 0x1005b650 +void LegoOmni::StopTimer() +{ + MxOmni::StopTimer(); + SetAppCursor(0); +} + +// OFFSET: LEGO1 0x100acf50 +MxResult Start(MxDSAction* p_dsAction) +{ + return MxOmni::GetInstance()->Start(p_dsAction); +} + +// OFFSET: LEGO1 0x100b6ff0 +void MakeSourceName(char* p_output, const char* p_input) +{ + const char* cln = strchr(p_input, ':'); + if (cln) { + p_input = cln + 1; + } + + strcpy(p_output, p_input); + + strlwr(p_output); + + char* extLoc = strstr(p_output, ".si"); + if (extLoc) { + *extLoc = 0; + } +} + +// OFFSET: LEGO1 0x100b7050 +MxBool KeyValueStringParse(char* p_outputValue, const char* p_key, const char* p_source) +{ + MxBool didMatch = FALSE; + + MxS16 len = strlen(p_source); + char* temp = new char[len + 1]; + strcpy(temp, p_source); + + char* token = strtok(temp, ", \t\r\n:"); + while (token) { + len -= (strlen(token) + 1); + + if (strcmpi(token, p_key) == 0) { + if (p_outputValue && len > 0) { + char* cur = &token[strlen(p_key)]; + cur++; + while (*cur != ',') { + if (*cur == ' ' || *cur == '\0' || *cur == '\t' || *cur == '\n' || *cur == '\r') + break; + *p_outputValue++ = *cur++; + } + *p_outputValue = '\0'; + } + + didMatch = TRUE; + break; + } + + token = strtok(NULL, ", \t\r\n:"); + } + + delete[] temp; + return didMatch; +} + +// OFFSET: LEGO1 0x100b7210 +void SetOmniUserMessage(void (*p_userMsg)(const char*, int)) +{ + g_omniUserMessage = p_userMsg; +} + +// OFFSET: LEGO1 0x100c0280 +MxDSObject* CreateStreamObject(MxDSFile* p_file, MxS16 p_ofs) +{ + char* buf; + _MMCKINFO tmp_chunk; + + if (p_file->Seek(((MxLong*) p_file->GetBuffer())[p_ofs], 0)) { + return NULL; + } + + if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'S', 't')) { + if (p_file->Read((MxU8*) &tmp_chunk.ckid, 8) == 0 && tmp_chunk.ckid == FOURCC('M', 'x', 'O', 'b')) { + + buf = new char[tmp_chunk.cksize]; + if (!buf) { + return NULL; + } + + if (p_file->Read((MxU8*) buf, tmp_chunk.cksize) != 0) { + return NULL; + } + + // Save a copy so we can clean up properly, because + // this function will alter the pointer value. + char* copy = buf; + MxDSObject* obj = DeserializeDSObjectDispatch(&buf, -1); + delete[] copy; + return obj; + } + return NULL; + } + + return NULL; +} diff --git a/LEGO1/legophonemepresenter.cpp b/LEGO1/legophonemepresenter.cpp index b93acea6..445f94f3 100644 --- a/LEGO1/legophonemepresenter.cpp +++ b/LEGO1/legophonemepresenter.cpp @@ -8,6 +8,11 @@ LegoPhonemePresenter::LegoPhonemePresenter() Init(); } +// OFFSET: LEGO1 0x1004e340 +LegoPhonemePresenter::~LegoPhonemePresenter() +{ +} + // OFFSET: LEGO1 0x1004e3b0 void LegoPhonemePresenter::Init() { @@ -16,8 +21,3 @@ void LegoPhonemePresenter::Init() m_unk70 = 0; m_unk84 = 0; } - -// OFFSET: LEGO1 0x1004e340 -LegoPhonemePresenter::~LegoPhonemePresenter() -{ -} diff --git a/LEGO1/legoplantmanager.cpp b/LEGO1/legoplantmanager.cpp index b575407e..b93a20d8 100644 --- a/LEGO1/legoplantmanager.cpp +++ b/LEGO1/legoplantmanager.cpp @@ -12,6 +12,12 @@ LegoPlantManager::~LegoPlantManager() // TODO } +// OFFSET: LEGO1 0x10026330 STUB +void LegoPlantManager::Init() +{ + // TODO +} + // OFFSET: LEGO1 0x10026e00 STUB MxResult LegoPlantManager::Tickle() { @@ -19,9 +25,3 @@ MxResult LegoPlantManager::Tickle() return 0; } - -// OFFSET: LEGO1 0x10026330 STUB -void LegoPlantManager::Init() -{ - // TODO -} diff --git a/LEGO1/legosoundmanager.cpp b/LEGO1/legosoundmanager.cpp index 94bd9a29..dcc1012d 100644 --- a/LEGO1/legosoundmanager.cpp +++ b/LEGO1/legosoundmanager.cpp @@ -14,10 +14,11 @@ LegoSoundManager::~LegoSoundManager() Destroy(TRUE); } -// OFFSET: LEGO1 0x1002a390 -void LegoSoundManager::Destroy() +// OFFSET: LEGO1 0x100299a0 +void LegoSoundManager::Init() { - Destroy(FALSE); + unk0x40 = 0; + unk0x3c = 0; } // OFFSET: LEGO1 0x100299b0 STUB @@ -31,11 +32,10 @@ MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) return FAILURE; } -// OFFSET: LEGO1 0x100299a0 -void LegoSoundManager::Init() +// OFFSET: LEGO1 0x1002a390 +void LegoSoundManager::Destroy() { - unk0x40 = 0; - unk0x3c = 0; + Destroy(FALSE); } // OFFSET: LEGO1 0x1002a3a0 STUB diff --git a/LEGO1/legostream.cpp b/LEGO1/legostream.cpp index 3ba30ad9..608e38eb 100644 --- a/LEGO1/legostream.cpp +++ b/LEGO1/legostream.cpp @@ -19,6 +19,55 @@ DECOMP_SIZE_ASSERT(LegoStream, 0x8); DECOMP_SIZE_ASSERT(LegoFileStream, 0xC); DECOMP_SIZE_ASSERT(LegoMemoryStream, 0x10); +// 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; +} + // OFFSET: LEGO1 0x10045ae0 MxBool LegoStream::IsWriteMode() { @@ -31,6 +80,29 @@ MxBool LegoStream::IsReadMode() return m_mode == LEGOSTREAM_MODE_READ; } +// OFFSET: LEGO1 0x10099080 +LegoMemoryStream::LegoMemoryStream(char* p_buffer) : LegoStream() +{ + m_buffer = p_buffer; + m_offset = 0; +} + +// OFFSET: LEGO1 0x10099160 +MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size) +{ + memcpy(p_buffer, m_buffer + m_offset, p_size); + m_offset += p_size; + return SUCCESS; +} + +// OFFSET: LEGO1 0x10099190 +MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size) +{ + memcpy(m_buffer + m_offset, p_buffer, p_size); + m_offset += p_size; + return SUCCESS; +} + // OFFSET: LEGO1 0x100991c0 LegoFileStream::LegoFileStream() : LegoStream() { @@ -113,29 +185,6 @@ MxResult LegoFileStream::Open(const char* p_filename, OpenFlags p_mode) return (m_hFile = fopen(p_filename, modeString)) ? SUCCESS : FAILURE; } -// OFFSET: LEGO1 0x10099080 -LegoMemoryStream::LegoMemoryStream(char* p_buffer) : LegoStream() -{ - m_buffer = p_buffer; - m_offset = 0; -} - -// OFFSET: LEGO1 0x10099160 -MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size) -{ - memcpy(p_buffer, m_buffer + m_offset, p_size); - m_offset += p_size; - return SUCCESS; -} - -// OFFSET: LEGO1 0x10099190 -MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size) -{ - memcpy(m_buffer + m_offset, p_buffer, p_size); - m_offset += p_size; - return SUCCESS; -} - // OFFSET: LEGO1 0x100994a0 MxResult LegoMemoryStream::Tell(MxU32* p_offset) { @@ -149,52 +198,3 @@ MxResult LegoMemoryStream::Seek(MxU32 p_offset) m_offset = 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/legovehiclebuildstate.cpp b/LEGO1/legovehiclebuildstate.cpp index e4f61103..1829fd8d 100644 --- a/LEGO1/legovehiclebuildstate.cpp +++ b/LEGO1/legovehiclebuildstate.cpp @@ -5,6 +5,15 @@ DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50); // 1000acd7 DECOMP_SIZE_ASSERT(LegoVehicleBuildState::UnkStruct, 0xc); +// OFFSET: LEGO1 0x10017c00 +LegoVehicleBuildState::UnkStruct::UnkStruct() +{ + m_unk04 = 0; + m_unk00 = 0; + m_unk06 = 0; + m_unk08 = 0; +} + // OFFSET: LEGO1 0x10025f30 LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType) { @@ -14,12 +23,3 @@ LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType) 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/legovideomanager.cpp b/LEGO1/legovideomanager.cpp index 55f3da33..8bd46b8f 100644 --- a/LEGO1/legovideomanager.cpp +++ b/LEGO1/legovideomanager.cpp @@ -55,32 +55,6 @@ void LegoVideoManager::Destroy() delete[] m_prefCounter; } -// OFFSET: LEGO1 0x1007c560 STUB -int LegoVideoManager::EnableRMDevice() -{ - // TODO - return 0; -} - -// OFFSET: LEGO1 0x1007c740 STUB -int LegoVideoManager::DisableRMDevice() -{ - // TODO - return 0; -} - -// OFFSET: LEGO1 0x1007c300 -void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable) -{ - EnableFullScreenMovie(p_enable, TRUE); -} - -// OFFSET: LEGO1 0x1007c310 STUB -void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale) -{ - // TODO -} - // OFFSET: LEGO1 0x1007b6a0 void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY) { @@ -95,6 +69,18 @@ void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY) m_cursorY = 463; } +// OFFSET: LEGO1 0x1007c300 +void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable) +{ + EnableFullScreenMovie(p_enable, TRUE); +} + +// OFFSET: LEGO1 0x1007c310 STUB +void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale) +{ + // TODO +} + // OFFSET: LEGO1 0x1007c440 void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) { @@ -110,3 +96,17 @@ void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) // TODO 3d manager // m_3dManager->m_pViewport->vtable1c(red, green, blue) } + +// OFFSET: LEGO1 0x1007c560 STUB +int LegoVideoManager::EnableRMDevice() +{ + // TODO + return 0; +} + +// OFFSET: LEGO1 0x1007c740 STUB +int LegoVideoManager::DisableRMDevice() +{ + // TODO + return 0; +} diff --git a/LEGO1/legoworld.cpp b/LEGO1/legoworld.cpp index e4a2e6b4..5ad73fef 100644 --- a/LEGO1/legoworld.cpp +++ b/LEGO1/legoworld.cpp @@ -16,22 +16,55 @@ void LegoWorld::VTable0x60() { } +// OFFSET: LEGO1 0x10015820 STUB +void FUN_10015820(MxU32 p_unk1, MxU32 p_unk2) +{ + // TODO +} + +// OFFSET: LEGO1 0x10015910 STUB +void FUN_10015910(MxU32 p_unk1) +{ + // TODO +} + +// OFFSET: LEGO1 0x100159c0 +void SetIsWorldActive(MxBool p_isWorldActive) +{ + if (!p_isWorldActive) + LegoOmni::GetInstance()->GetInputManager()->SetCamera(NULL); + g_isWorldActive = p_isWorldActive; +} + // OFFSET: LEGO1 0x1001ca40 STUB LegoWorld::LegoWorld() { // TODO } +// OFFSET: LEGO1 0x1001d670 +MxBool LegoWorld::VTable0x5c() +{ + return FALSE; +} + +// OFFSET: LEGO1 0x1001d680 +MxBool LegoWorld::VTable0x64() +{ + return FALSE; +} + // OFFSET: LEGO1 0x1001dfa0 STUB LegoWorld::~LegoWorld() { // TODO } -// OFFSET: LEGO1 0x10022340 -void LegoWorld::Stop() +// OFFSET: LEGO1 0x1001e0b0 STUB +MxResult LegoWorld::SetAsCurrentWorld(MxDSObject& p_dsObject) { - TickleManager()->UnregisterClient(this); + // TODO + return SUCCESS; } // OFFSET: LEGO1 0x1001f5e0 @@ -58,27 +91,15 @@ void LegoWorld::VTable0x54() // TODO } -// OFFSET: LEGO1 0x10020f10 STUB -void LegoWorld::EndAction(MxPresenter* p_presenter) -{ -} - // OFFSET: LEGO1 0x10020220 STUB void LegoWorld::VTable0x58(MxCore* p_object) { // TODO } -// OFFSET: LEGO1 0x1001d670 -MxBool LegoWorld::VTable0x5c() +// OFFSET: LEGO1 0x10020f10 STUB +void LegoWorld::EndAction(MxPresenter* p_presenter) { - return FALSE; -} - -// OFFSET: LEGO1 0x1001d680 -MxBool LegoWorld::VTable0x64() -{ - return FALSE; } // OFFSET: LEGO1 0x10021a70 STUB @@ -87,29 +108,8 @@ void LegoWorld::VTable0x68(MxBool p_add) // TODO } -// OFFSET: LEGO1 0x1001e0b0 STUB -MxResult LegoWorld::SetAsCurrentWorld(MxDSObject& p_dsObject) +// OFFSET: LEGO1 0x10022340 +void LegoWorld::Stop() { - // TODO - return SUCCESS; -} - -// OFFSET: LEGO1 0x10015820 STUB -void FUN_10015820(MxU32 p_unk1, MxU32 p_unk2) -{ - // TODO -} - -// OFFSET: LEGO1 0x10015910 STUB -void FUN_10015910(MxU32 p_unk1) -{ - // TODO -} - -// OFFSET: LEGO1 0x100159c0 -void SetIsWorldActive(MxBool p_isWorldActive) -{ - if (!p_isWorldActive) - LegoOmni::GetInstance()->GetInputManager()->SetCamera(NULL); - g_isWorldActive = p_isWorldActive; + TickleManager()->UnregisterClient(this); } diff --git a/LEGO1/legoworldpresenter.cpp b/LEGO1/legoworldpresenter.cpp index 1e1d7558..cb135cda 100644 --- a/LEGO1/legoworldpresenter.cpp +++ b/LEGO1/legoworldpresenter.cpp @@ -3,6 +3,12 @@ // 0x100f75d4 undefined4 g_LegoWorldPresenterQuality = 1; +// OFFSET: LEGO1 0x100665b0 +void LegoWorldPresenter::configureLegoWorldPresenter(int p_quality) +{ + g_LegoWorldPresenterQuality = p_quality; +} + // OFFSET: LEGO1 0x100665c0 LegoWorldPresenter::LegoWorldPresenter() { @@ -14,9 +20,3 @@ LegoWorldPresenter::~LegoWorldPresenter() { // TODO } - -// OFFSET: LEGO1 0x100665b0 -void LegoWorldPresenter::configureLegoWorldPresenter(int p_quality) -{ - g_LegoWorldPresenterQuality = p_quality; -} diff --git a/LEGO1/mxaudiomanager.cpp b/LEGO1/mxaudiomanager.cpp index 759bc2c9..5ec3e046 100644 --- a/LEGO1/mxaudiomanager.cpp +++ b/LEGO1/mxaudiomanager.cpp @@ -5,6 +5,12 @@ DECOMP_SIZE_ASSERT(MxAudioManager, 0x30); // GLOBAL: LEGO1 0x10102108 MxS32 MxAudioManager::g_unkCount = 0; +// OFFSET: LEGO1 0x10029910 +MxS32 MxAudioManager::GetVolume() +{ + return this->m_volume; +} + // OFFSET: LEGO1 0x100b8d00 MxAudioManager::MxAudioManager() { @@ -23,20 +29,6 @@ void MxAudioManager::Init() this->m_volume = 100; } -// OFFSET: LEGO1 0x10029910 -MxS32 MxAudioManager::GetVolume() -{ - return this->m_volume; -} - -// OFFSET: LEGO1 0x100b8ea0 -void MxAudioManager::SetVolume(MxS32 p_volume) -{ - this->m_criticalSection.Enter(); - this->m_volume = p_volume; - this->m_criticalSection.Leave(); -} - // OFFSET: LEGO1 0x100b8e00 void MxAudioManager::Destroy(MxBool p_fromDestructor) { @@ -76,3 +68,11 @@ void MxAudioManager::Destroy() { Destroy(FALSE); } + +// OFFSET: LEGO1 0x100b8ea0 +void MxAudioManager::SetVolume(MxS32 p_volume) +{ + this->m_criticalSection.Enter(); + this->m_volume = p_volume; + this->m_criticalSection.Leave(); +} diff --git a/LEGO1/mxbackgroundaudiomanager.cpp b/LEGO1/mxbackgroundaudiomanager.cpp index 2099cbc4..15ba09c4 100644 --- a/LEGO1/mxbackgroundaudiomanager.cpp +++ b/LEGO1/mxbackgroundaudiomanager.cpp @@ -31,70 +31,6 @@ MxBackgroundAudioManager::~MxBackgroundAudioManager() DestroyMusic(); } -// OFFSET: LEGO1 0x1007f470 -void MxBackgroundAudioManager::Stop() -{ - if (m_action2.GetObjectId() != -1) - DeleteObject(m_action2); - - m_unk138 = 0; - m_action2.SetAtomId(MxAtomId()); - m_action2.SetObjectId(-1); - - if (m_action1.GetObjectId() != -1) - DeleteObject(m_action1); - - m_unka0 = 0; - m_action1.SetAtomId(MxAtomId()); - m_unk148 = 0; - m_action1.SetObjectId(-1); - m_unk13c = 0; -} - -// OFFSET: LEGO1 0x1007f570 -void MxBackgroundAudioManager::LowerVolume() -{ - if (m_unk148 == 0) { - if (m_unk13c == 0) { - m_unk13c = 2; - } - m_unk140 = 20; - } - m_unk148++; -} - -// OFFSET: LEGO1 0x1007f5b0 -void MxBackgroundAudioManager::RaiseVolume() -{ - if (m_unk148 != 0) { - m_unk148--; - if (m_unk148 == 0) { - if (m_unk13c == 0) { - m_unk13c = 2; - } - m_unk140 = 10; - } - } -} - -// OFFSET: LEGO1 0x1007f5f0 -void MxBackgroundAudioManager::Enable(MxBool p) -{ - if (this->m_musicEnabled != p) { - this->m_musicEnabled = p; - if (!p) { - Stop(); - } - } -} - -// OFFSET: LEGO1 0x1007f650 -void MxBackgroundAudioManager::Init() -{ - this->m_unka0 = 0; - this->m_unk13c = 0; -} - // OFFSET: LEGO1 0x1007ece0 MxResult MxBackgroundAudioManager::Create(MxAtomId& p_script, MxU32 p_frequencyMS) { @@ -137,80 +73,6 @@ void MxBackgroundAudioManager::DestroyMusic() } } -// OFFSET: LEGO1 0x1007f170 -MxLong MxBackgroundAudioManager::Notify(MxParam& p) -{ - switch (((MxNotificationParam&) p).GetNotification()) { - case c_notificationStartAction: - StartAction(p); - return 1; - case c_notificationEndAction: - StopAction(p); - return 1; - } - return 0; -} - -// OFFSET: LEGO1 0x1007f1b0 -void MxBackgroundAudioManager::StartAction(MxParam& p) -{ - // TODO: the sender is most likely a MxAudioPresenter? - m_unk138 = (MxAudioPresenter*) ((MxNotificationParam&) p).GetSender(); - m_action2.SetAtomId(m_unk138->GetAction()->GetAtomId()); - m_action2.SetObjectId(m_unk138->GetAction()->GetObjectId()); - m_targetVolume = ((MxDSSound*) (m_unk138->GetAction()))->GetVolume(); - m_unk138->SetVolume(0); -} - -// OFFSET: LEGO1 0x1007f200 -void MxBackgroundAudioManager::StopAction(MxParam& p) -{ - if (((MxNotificationParam&) p).GetSender() == m_unka0) { - m_unka0 = NULL; - m_action1.SetAtomId(MxAtomId()); - m_action1.SetObjectId(-1); - } - else if (((MxNotificationParam&) p).GetSender() == m_unk138) { - m_unk138 = NULL; - m_action2.SetAtomId(MxAtomId()); - m_action2.SetObjectId(-1); - } - - Lego()->HandleNotificationType2(p); -} - -// OFFSET: LEGO1 0x1007f2f0 -MxResult MxBackgroundAudioManager::PlayMusic(MxDSAction& p_action, undefined4 p_unknown, undefined4 p_unknown2) -{ - if (!m_musicEnabled) { - return SUCCESS; - } - if (m_action2.GetObjectId() == -1 && m_action1.GetObjectId() != p_action.GetObjectId()) { - MxDSAction action; - action.SetAtomId(GetCurrentAction().GetAtomId()); - action.SetObjectId(GetCurrentAction().GetObjectId()); - action.SetUnknown24(GetCurrentAction().GetUnknown24()); - - m_action2.SetAtomId(p_action.GetAtomId()); - m_action2.SetObjectId(p_action.GetObjectId()); - m_action2.SetUnknown84(this); - m_action2.SetUnknown8c(this); - - MxResult result = Start(&m_action2); - - GetCurrentAction().SetAtomId(action.GetAtomId()); - GetCurrentAction().SetObjectId(action.GetObjectId()); - GetCurrentAction().SetUnknown24(action.GetUnknown24()); - - if (result == SUCCESS) { - m_unk13c = p_unknown2; - m_unk140 = p_unknown; - } - return result; - } - return FAILURE; -} - // OFFSET: LEGO1 0x1007ee40 MxResult MxBackgroundAudioManager::Tickle() { @@ -324,3 +186,141 @@ void MxBackgroundAudioManager::FadeInOrFadeOut() m_unk13c = 0; } } + +// OFFSET: LEGO1 0x1007f170 +MxLong MxBackgroundAudioManager::Notify(MxParam& p) +{ + switch (((MxNotificationParam&) p).GetNotification()) { + case c_notificationStartAction: + StartAction(p); + return 1; + case c_notificationEndAction: + StopAction(p); + return 1; + } + return 0; +} + +// OFFSET: LEGO1 0x1007f1b0 +void MxBackgroundAudioManager::StartAction(MxParam& p) +{ + // TODO: the sender is most likely a MxAudioPresenter? + m_unk138 = (MxAudioPresenter*) ((MxNotificationParam&) p).GetSender(); + m_action2.SetAtomId(m_unk138->GetAction()->GetAtomId()); + m_action2.SetObjectId(m_unk138->GetAction()->GetObjectId()); + m_targetVolume = ((MxDSSound*) (m_unk138->GetAction()))->GetVolume(); + m_unk138->SetVolume(0); +} + +// OFFSET: LEGO1 0x1007f200 +void MxBackgroundAudioManager::StopAction(MxParam& p) +{ + if (((MxNotificationParam&) p).GetSender() == m_unka0) { + m_unka0 = NULL; + m_action1.SetAtomId(MxAtomId()); + m_action1.SetObjectId(-1); + } + else if (((MxNotificationParam&) p).GetSender() == m_unk138) { + m_unk138 = NULL; + m_action2.SetAtomId(MxAtomId()); + m_action2.SetObjectId(-1); + } + + Lego()->HandleNotificationType2(p); +} + +// OFFSET: LEGO1 0x1007f2f0 +MxResult MxBackgroundAudioManager::PlayMusic(MxDSAction& p_action, undefined4 p_unknown, undefined4 p_unknown2) +{ + if (!m_musicEnabled) { + return SUCCESS; + } + if (m_action2.GetObjectId() == -1 && m_action1.GetObjectId() != p_action.GetObjectId()) { + MxDSAction action; + action.SetAtomId(GetCurrentAction().GetAtomId()); + action.SetObjectId(GetCurrentAction().GetObjectId()); + action.SetUnknown24(GetCurrentAction().GetUnknown24()); + + m_action2.SetAtomId(p_action.GetAtomId()); + m_action2.SetObjectId(p_action.GetObjectId()); + m_action2.SetUnknown84(this); + m_action2.SetUnknown8c(this); + + MxResult result = Start(&m_action2); + + GetCurrentAction().SetAtomId(action.GetAtomId()); + GetCurrentAction().SetObjectId(action.GetObjectId()); + GetCurrentAction().SetUnknown24(action.GetUnknown24()); + + if (result == SUCCESS) { + m_unk13c = p_unknown2; + m_unk140 = p_unknown; + } + return result; + } + return FAILURE; +} + +// OFFSET: LEGO1 0x1007f470 +void MxBackgroundAudioManager::Stop() +{ + if (m_action2.GetObjectId() != -1) + DeleteObject(m_action2); + + m_unk138 = 0; + m_action2.SetAtomId(MxAtomId()); + m_action2.SetObjectId(-1); + + if (m_action1.GetObjectId() != -1) + DeleteObject(m_action1); + + m_unka0 = 0; + m_action1.SetAtomId(MxAtomId()); + m_unk148 = 0; + m_action1.SetObjectId(-1); + m_unk13c = 0; +} + +// OFFSET: LEGO1 0x1007f570 +void MxBackgroundAudioManager::LowerVolume() +{ + if (m_unk148 == 0) { + if (m_unk13c == 0) { + m_unk13c = 2; + } + m_unk140 = 20; + } + m_unk148++; +} + +// OFFSET: LEGO1 0x1007f5b0 +void MxBackgroundAudioManager::RaiseVolume() +{ + if (m_unk148 != 0) { + m_unk148--; + if (m_unk148 == 0) { + if (m_unk13c == 0) { + m_unk13c = 2; + } + m_unk140 = 10; + } + } +} + +// OFFSET: LEGO1 0x1007f5f0 +void MxBackgroundAudioManager::Enable(MxBool p) +{ + if (this->m_musicEnabled != p) { + this->m_musicEnabled = p; + if (!p) { + Stop(); + } + } +} + +// OFFSET: LEGO1 0x1007f650 +void MxBackgroundAudioManager::Init() +{ + this->m_unka0 = 0; + this->m_unk13c = 0; +} diff --git a/LEGO1/mxbitmap.cpp b/LEGO1/mxbitmap.cpp index ca1e8287..a036a05d 100644 --- a/LEGO1/mxbitmap.cpp +++ b/LEGO1/mxbitmap.cpp @@ -10,6 +10,28 @@ DECOMP_SIZE_ASSERT(MxBITMAPINFO, 0x428); // (1998) GLOBAL: LEGO1 0x10102184 MxU16 g_bitmapSignature = TWOCC('B', 'M'); +// Bit mask trick to round up to the nearest multiple of four. +// Pixel data may be stored with padding. +// https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride +inline MxLong AlignToFourByte(MxLong p_value) +{ + return (p_value + 3) & -4; +} + +// Same as the one from legoutil.h, but flipped the other way +// TODO: While it's not outside the realm of possibility that they +// reimplemented Abs for only this file, that seems odd, right? +inline MxLong _Abs(MxLong p_value) +{ + return p_value > 0 ? p_value : -p_value; +} + +// OFFSET: LEGO1 0x1004e0d0 +int MxBitmap::vtable28(int) +{ + return -1; +} + // OFFSET: LEGO1 0x100bc980 MxBitmap::MxBitmap() { @@ -32,118 +54,6 @@ MxBitmap::~MxBitmap() delete m_palette; } -// Bit mask trick to round up to the nearest multiple of four. -// Pixel data may be stored with padding. -// https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride -inline MxLong AlignToFourByte(MxLong p_value) -{ - return (p_value + 3) & -4; -} - -// Same as the one from legoutil.h, but flipped the other way -// TODO: While it's not outside the realm of possibility that they -// reimplemented Abs for only this file, that seems odd, right? -inline MxLong _Abs(MxLong p_value) -{ - return p_value > 0 ? p_value : -p_value; -} - -// OFFSET: LEGO1 0x100bcc40 -MxResult MxBitmap::ImportBitmap(MxBitmap* p_bitmap) -{ - MxResult result = FAILURE; - - this->m_info = new MxBITMAPINFO; - if (this->m_info) { - MxLong height = _Abs(p_bitmap->m_bmiHeader->biHeight); - this->m_data = new MxU8[AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height]; - if (this->m_data) { - memcpy(this->m_info, p_bitmap->m_info, sizeof(*this->m_info)); - height = _Abs(p_bitmap->m_bmiHeader->biHeight); - memcpy(this->m_data, p_bitmap->m_data, AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height); - - result = SUCCESS; - this->m_bmiHeader = &this->m_info->bmiHeader; - this->m_paletteData = this->m_info->bmiColors; - } - } - - if (result != SUCCESS) { - if (this->m_info) { - delete this->m_info; - this->m_info = NULL; - } - - if (this->m_data) { - delete this->m_data; - this->m_data = NULL; - } - } - - return result; -} - -// OFFSET: LEGO1 0x100bcba0 -MxResult MxBitmap::ImportBitmapInfo(MxBITMAPINFO* p_info) -{ - MxResult result = FAILURE; - MxLong width = p_info->bmiHeader.biWidth; - MxLong height = p_info->bmiHeader.biHeight; - MxLong size = AlignToFourByte(width) * height; - - this->m_info = new MxBITMAPINFO; - if (this->m_info) { - this->m_data = new MxU8[size]; - if (this->m_data) { - memcpy(this->m_info, p_info, sizeof(*this->m_info)); - this->m_bmiHeader = &this->m_info->bmiHeader; - this->m_paletteData = this->m_info->bmiColors; - result = SUCCESS; - } - } - - if (result != SUCCESS) { - if (this->m_info) { - delete this->m_info; - this->m_info = NULL; - } - - if (this->m_data) { - delete this->m_data; - this->m_data = NULL; - } - } - - return result; -} - -// OFFSET: LEGO1 0x100bd450 -MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette) -{ - MxResult ret = FAILURE; - PALETTEENTRY entries[256]; - - if (p_palette) { - if (p_palette->GetEntries(entries)) - return ret; - } - else { - MxPalette local_pal; - if (local_pal.GetEntries(entries)) - return ret; - } - - for (MxS32 i = 0; i < 256; i++) { - p_rgbquad[i].rgbRed = entries[i].peRed; - p_rgbquad[i].rgbGreen = entries[i].peGreen; - p_rgbquad[i].rgbBlue = entries[i].peBlue; - p_rgbquad[i].rgbReserved = 0; - } - - ret = SUCCESS; - return ret; -} - // OFFSET: LEGO1 0x100bcaa0 MxResult MxBitmap::SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette, MxBool p_isHighColor) { @@ -189,6 +99,91 @@ MxResult MxBitmap::SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette, return ret; } +// OFFSET: LEGO1 0x100bcba0 +MxResult MxBitmap::ImportBitmapInfo(MxBITMAPINFO* p_info) +{ + MxResult result = FAILURE; + MxLong width = p_info->bmiHeader.biWidth; + MxLong height = p_info->bmiHeader.biHeight; + MxLong size = AlignToFourByte(width) * height; + + this->m_info = new MxBITMAPINFO; + if (this->m_info) { + this->m_data = new MxU8[size]; + if (this->m_data) { + memcpy(this->m_info, p_info, sizeof(*this->m_info)); + this->m_bmiHeader = &this->m_info->bmiHeader; + this->m_paletteData = this->m_info->bmiColors; + result = SUCCESS; + } + } + + if (result != SUCCESS) { + if (this->m_info) { + delete this->m_info; + this->m_info = NULL; + } + + if (this->m_data) { + delete this->m_data; + this->m_data = NULL; + } + } + + return result; +} + +// OFFSET: LEGO1 0x100bcc40 +MxResult MxBitmap::ImportBitmap(MxBitmap* p_bitmap) +{ + MxResult result = FAILURE; + + this->m_info = new MxBITMAPINFO; + if (this->m_info) { + MxLong height = _Abs(p_bitmap->m_bmiHeader->biHeight); + this->m_data = new MxU8[AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height]; + if (this->m_data) { + memcpy(this->m_info, p_bitmap->m_info, sizeof(*this->m_info)); + height = _Abs(p_bitmap->m_bmiHeader->biHeight); + memcpy(this->m_data, p_bitmap->m_data, AlignToFourByte(p_bitmap->m_bmiHeader->biWidth) * height); + + result = SUCCESS; + this->m_bmiHeader = &this->m_info->bmiHeader; + this->m_paletteData = this->m_info->bmiColors; + } + } + + if (result != SUCCESS) { + if (this->m_info) { + delete this->m_info; + this->m_info = NULL; + } + + if (this->m_data) { + delete this->m_data; + this->m_data = NULL; + } + } + + return result; +} + +// OFFSET: LEGO1 0x100bcd10 +MxLong MxBitmap::Read(const char* p_filename) +{ + MxResult result = FAILURE; + HANDLE handle = + CreateFileA(p_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle != INVALID_HANDLE_VALUE && !LoadFile(handle)) + result = SUCCESS; + + if (handle) + CloseHandle(handle); + + return result; +} + // OFFSET: LEGO1 0x100bcd60 MxResult MxBitmap::LoadFile(HANDLE p_handle) { @@ -236,28 +231,6 @@ MxResult MxBitmap::LoadFile(HANDLE p_handle) return result; } -// OFFSET: LEGO1 0x100bcd10 -MxLong MxBitmap::Read(const char* p_filename) -{ - MxResult result = FAILURE; - HANDLE handle = - CreateFileA(p_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (handle != INVALID_HANDLE_VALUE && !LoadFile(handle)) - result = SUCCESS; - - if (handle) - CloseHandle(handle); - - return result; -} - -// OFFSET: LEGO1 0x1004e0d0 -int MxBitmap::vtable28(int) -{ - return -1; -} - // OFFSET: LEGO1 0x100bce70 STUB void MxBitmap::vtable2c(int, int, int, int, int, int, int) { @@ -393,3 +366,30 @@ MxResult MxBitmap::StretchBits( SRCCOPY ); } + +// OFFSET: LEGO1 0x100bd450 +MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette) +{ + MxResult ret = FAILURE; + PALETTEENTRY entries[256]; + + if (p_palette) { + if (p_palette->GetEntries(entries)) + return ret; + } + else { + MxPalette local_pal; + if (local_pal.GetEntries(entries)) + return ret; + } + + for (MxS32 i = 0; i < 256; i++) { + p_rgbquad[i].rgbRed = entries[i].peRed; + p_rgbquad[i].rgbGreen = entries[i].peGreen; + p_rgbquad[i].rgbBlue = entries[i].peBlue; + p_rgbquad[i].rgbReserved = 0; + } + + ret = SUCCESS; + return ret; +} diff --git a/LEGO1/mxcompositepresenter.cpp b/LEGO1/mxcompositepresenter.cpp index b702acda..1275f317 100644 --- a/LEGO1/mxcompositepresenter.cpp +++ b/LEGO1/mxcompositepresenter.cpp @@ -5,6 +5,14 @@ DECOMP_SIZE_ASSERT(MxCompositePresenter, 0x4c); +// OFFSET: LEGO1 0x1000caf0 +MxBool MxCompositePresenter::VTable0x64(undefined4 p_unknown) +{ + if (m_compositePresenter) + return m_compositePresenter->VTable0x64(p_unknown); + return TRUE; +} + // OFFSET: LEGO1 0x100b60b0 MxCompositePresenter::MxCompositePresenter() { @@ -34,11 +42,3 @@ void MxCompositePresenter::VTable0x60(undefined4 p_unknown) { // TODO } - -// OFFSET: LEGO1 0x1000caf0 -MxBool MxCompositePresenter::VTable0x64(undefined4 p_unknown) -{ - if (m_compositePresenter) - return m_compositePresenter->VTable0x64(p_unknown); - return TRUE; -} diff --git a/LEGO1/mxcore.cpp b/LEGO1/mxcore.cpp index 8e2ac5a1..519c3cfa 100644 --- a/LEGO1/mxcore.cpp +++ b/LEGO1/mxcore.cpp @@ -2,6 +2,12 @@ #include "define.h" +// OFFSET: LEGO1 0x10001f70 +MxResult MxCore::Tickle() +{ + return SUCCESS; +} + // OFFSET: LEGO1 0x100ae1a0 MxCore::MxCore() { @@ -19,9 +25,3 @@ MxLong MxCore::Notify(MxParam& p) { return 0; } - -// OFFSET: LEGO1 0x10001f70 -MxResult MxCore::Tickle() -{ - return SUCCESS; -} diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index 899e3371..5ea45f93 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -8,6 +8,13 @@ class MxParam; +// TODO: Find proper compilation unit to put these +// OFFSET: LEGO1 0x100140d0 TEMPLATE +// MxCore::IsA + +// OFFSET: LEGO1 0x100144c0 TEMPLATE +// MxCore::ClassName + // VTABLE 0x100dc0f8 // SIZE 0x8 class MxCore { @@ -17,14 +24,12 @@ class MxCore { __declspec(dllexport) virtual MxLong Notify(MxParam& p); // vtable+04 virtual MxResult Tickle(); // vtable+08 - // OFFSET: LEGO1 0x100144c0 inline virtual const char* ClassName() const // vtable+0c { // 0x100f007c return "MxCore"; } - // OFFSET: LEGO1 0x100140d0 inline virtual MxBool IsA(const char* name) const // vtable+10 { return !strcmp(name, MxCore::ClassName()); diff --git a/LEGO1/mxcriticalsection.cpp b/LEGO1/mxcriticalsection.cpp index f3b4c27d..1ff5f41e 100644 --- a/LEGO1/mxcriticalsection.cpp +++ b/LEGO1/mxcriticalsection.cpp @@ -31,12 +31,6 @@ MxCriticalSection::~MxCriticalSection() DeleteCriticalSection(&this->m_criticalSection); } -// OFFSET: LEGO1 0x100b6e00 -void MxCriticalSection::SetDoMutex() -{ - g_useMutex = 1; -} - // OFFSET: LEGO1 0x100b6d80 void MxCriticalSection::Enter() { @@ -70,3 +64,9 @@ void MxCriticalSection::Leave() LeaveCriticalSection(&this->m_criticalSection); } + +// OFFSET: LEGO1 0x100b6e00 +void MxCriticalSection::SetDoMutex() +{ + g_useMutex = 1; +} diff --git a/LEGO1/mxdirectdraw.cpp b/LEGO1/mxdirectdraw.cpp index 8f992fea..b9181737 100644 --- a/LEGO1/mxdirectdraw.cpp +++ b/LEGO1/mxdirectdraw.cpp @@ -9,44 +9,10 @@ DECOMP_SIZE_ASSERT(MxDirectDraw::DeviceModesInfo, 0x17c); #define DDSCAPS_3DDEVICE 0x00002000l #endif -// GLOBAL OFFSET: LEGO1 0x10100C68 +// GLOBAL OFFSET: LEGO1 0x10100c68 BOOL g_is_PALETTEINDEXED8 = 0; -// OFFSET: LEGO1 0x1009DA20 -void EnableResizing(HWND hwnd, BOOL flag) -{ - static DWORD dwStyle; - - if (!flag) { - dwStyle = GetWindowLong(hwnd, GWL_STYLE); - if (dwStyle & WS_THICKFRAME) { - SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) ^ WS_THICKFRAME); - } - } - else { - SetWindowLong(hwnd, GWL_STYLE, dwStyle); - } -} - -// OFFSET: LEGO1 0x1009efb0 -MxDirectDraw::DeviceModesInfo::DeviceModesInfo() -{ - memset(this, 0, sizeof(*this)); -} - -// OFFSET: LEGO1 0x1009EFD0 -MxDirectDraw::DeviceModesInfo::~DeviceModesInfo() -{ - if (p_guid != NULL) { - delete p_guid; - } - - if (m_mode_ARRAY != NULL) { - delete m_mode_ARRAY; - } -} - -// OFFSET: LEGO1 0x1009D490 +// OFFSET: LEGO1 0x1009d490 MxDirectDraw::MxDirectDraw() { m_pFrontBuffer = NULL; @@ -73,7 +39,7 @@ MxDirectDraw::MxDirectDraw() m_hFont = NULL; } -// OFFSET: LEGO1 0x1009D530 +// OFFSET: LEGO1 0x1009d530 MxDirectDraw::~MxDirectDraw() { Destroy(); @@ -106,7 +72,7 @@ int MxDirectDraw::GetPrimaryBitDepth() return dwRGBBitCount; } -// OFFSET: LEGO1 0x1009D5E0 +// OFFSET: LEGO1 0x1009d5e0 BOOL MxDirectDraw::Create( HWND hWnd, BOOL fullscreen_1, @@ -151,7 +117,82 @@ BOOL MxDirectDraw::Create( return TRUE; } -// OFFSET: LEGO1 0x1009D800 +// OFFSET: LEGO1 0x1009d690 +BOOL MxDirectDraw::RecreateDirectDraw(GUID** ppGUID) +{ + if (m_pDirectDraw) { + m_pDirectDraw->Release(); + m_pDirectDraw = NULL; + } + + return (DirectDrawCreate(*ppGUID, &m_pDirectDraw, 0) == DD_OK); +} + +// OFFSET: LEGO1 0x1009d6c0 +BOOL MxDirectDraw::CacheOriginalPaletteEntries() +{ + HDC DC; + + if (g_is_PALETTEINDEXED8) { + DC = GetDC(0); + GetSystemPaletteEntries(DC, 0, _countof(m_originalPaletteEntries), m_originalPaletteEntries); + ReleaseDC(0, DC); + } + return TRUE; +} + +// OFFSET: LEGO1 0x1009d700 +BOOL MxDirectDraw::SetPaletteEntries(const PALETTEENTRY* pPaletteEntries, int paletteEntryCount, BOOL fullscreen) +{ + int reservedLowEntryCount = 10; + int reservedHighEntryCount = 10; + int arraySize = _countof(m_paletteEntries); + HDC hdc; + int i; + + if (g_is_PALETTEINDEXED8) { + hdc = GetDC(NULL); + GetSystemPaletteEntries(hdc, 0, arraySize, m_paletteEntries); + ReleaseDC(NULL, hdc); + } + + for (i = 0; i < reservedLowEntryCount; i++) { + m_paletteEntries[i].peFlags = 0x80; + } + + for (i = reservedLowEntryCount; i < 142; i++) { + m_paletteEntries[i].peFlags = 0x44; + } + + for (i = 142; i < arraySize - reservedHighEntryCount; i++) { + m_paletteEntries[i].peFlags = 0x84; + } + + for (i = arraySize - reservedHighEntryCount; i < arraySize; i++) { + m_paletteEntries[i].peFlags = 0x80; + } + + if (paletteEntryCount != 0) { + for (i = reservedLowEntryCount; (i < paletteEntryCount) && (i < arraySize - reservedHighEntryCount); i++) { + m_paletteEntries[i].peRed = pPaletteEntries[i].peRed; + m_paletteEntries[i].peGreen = pPaletteEntries[i].peGreen; + m_paletteEntries[i].peBlue = pPaletteEntries[i].peBlue; + } + } + + if (m_pPalette != NULL) { + HRESULT result; + result = m_pPalette->SetEntries(0, 0, _countof(m_paletteEntries), m_paletteEntries); + if (result != DD_OK) { + Error("SetEntries failed", result); + return FALSE; + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009d800 void MxDirectDraw::Destroy() { DestroyButNotDirectDraw(); @@ -171,7 +212,7 @@ void MxDirectDraw::Destroy() } } -// OFFSET: LEGO1 0x1009D860 +// OFFSET: LEGO1 0x1009d860 void MxDirectDraw::DestroyButNotDirectDraw() { RestoreOriginalPaletteEntries(); @@ -219,6 +260,542 @@ void MxDirectDraw::DestroyButNotDirectDraw() } } +// OFFSET: LEGO1 0x1009d920 +void MxDirectDraw::FUN_1009D920() +{ + RestoreOriginalPaletteEntries(); + if (m_pDirectDraw != NULL) { + m_bIgnoreWM_SIZE = TRUE; + m_pDirectDraw->RestoreDisplayMode(); + m_pDirectDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL); + m_bIgnoreWM_SIZE = FALSE; + } +} + +// OFFSET: LEGO1 0x1009d960 +BOOL MxDirectDraw::DDInit(BOOL fullscreen) +{ + HRESULT result; + + if (fullscreen) { + m_bIgnoreWM_SIZE = 1; + result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + m_bIgnoreWM_SIZE = 0; + } + else { + result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_NORMAL); + } + + if (result != DD_OK) { + Error("SetCooperativeLevel failed", result); + return FALSE; + } + + m_bFullScreen = fullscreen; + + return TRUE; +} + +// OFFSET: LEGO1 0x1009d9d0 +BOOL MxDirectDraw::IsSupportedMode(int width, int height, int bpp) +{ + Mode mode = {width, height, bpp}; + + for (int i = 0; i < m_pCurrentDeviceModesList->count; i++) { + if (m_pCurrentDeviceModesList->m_mode_ARRAY[i] == mode) { + return TRUE; + } + } + + return FALSE; +} + +// OFFSET: LEGO1 0x1009da20 +void EnableResizing(HWND hwnd, BOOL flag) +{ + static DWORD dwStyle; + + if (!flag) { + dwStyle = GetWindowLong(hwnd, GWL_STYLE); + if (dwStyle & WS_THICKFRAME) { + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) ^ WS_THICKFRAME); + } + } + else { + SetWindowLong(hwnd, GWL_STYLE, dwStyle); + } +} + +// OFFSET: LEGO1 0x1009da80 +BOOL MxDirectDraw::DDSetMode(int width, int height, int bpp) +{ + HRESULT result; + + if (m_bFullScreen) { + LPDIRECTDRAW lpDD; + + EnableResizing(m_hWndMain, FALSE); + + if (!m_bIsOnPrimaryDevice) { + lpDD = NULL; + result = DirectDrawCreate(0, &lpDD, 0); + if (result == DD_OK) { + result = lpDD->SetCooperativeLevel(m_hWndMain, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT); + if (result == DD_OK) { + lpDD->SetDisplayMode(width, height, 8); + } + } + } + + if (!IsSupportedMode(width, height, bpp)) { + width = m_pCurrentDeviceModesList->m_mode_ARRAY[0].width; + height = m_pCurrentDeviceModesList->m_mode_ARRAY[0].height; + bpp = m_pCurrentDeviceModesList->m_mode_ARRAY[0].bitsPerPixel; + } + + m_bIgnoreWM_SIZE = TRUE; + result = m_pDirectDraw->SetDisplayMode(width, height, bpp); + m_bIgnoreWM_SIZE = FALSE; + if (result != DD_OK) { + Error("SetDisplayMode failed", result); + return FALSE; + } + } + else { + RECT rc; + DWORD dwStyle; + + if (!m_bIsOnPrimaryDevice) { + Error("Attempt made enter a windowed mode on a DirectDraw device that is not the primary display", E_FAIL); + return FALSE; + } + + m_bIgnoreWM_SIZE = TRUE; + dwStyle = GetWindowLong(m_hWndMain, GWL_STYLE); + dwStyle &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPED); + dwStyle |= WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPED; + SetWindowLong(m_hWndMain, GWL_STYLE, dwStyle); + + SetRect(&rc, 0, 0, width - 1, height - 1); + AdjustWindowRectEx( + &rc, + GetWindowLong(m_hWndMain, GWL_STYLE), + GetMenu(m_hWndMain) != NULL, + GetWindowLong(m_hWndMain, GWL_EXSTYLE) + ); + SetWindowPos( + m_hWndMain, + NULL, + 0, + 0, + rc.right - rc.left + 1, + rc.bottom - rc.top + 1, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE + ); + SetWindowPos(m_hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + m_bIgnoreWM_SIZE = FALSE; + } + + m_currentMode.width = width; + m_currentMode.height = height; + m_currentMode.bitsPerPixel = bpp; + + if (!DDCreateSurfaces()) { + return FALSE; + } + + DDSURFACEDESC ddsd; + + FUN_1009E020(); + + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { + return FALSE; + } + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { + m_bPrimaryPalettized = TRUE; + } + else { + m_bPrimaryPalettized = FALSE; + } + + if (m_bPrimaryPalettized) { + result = m_pDirectDraw->CreatePalette( + DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, // 0x4c + m_paletteEntries, + &m_pPalette, + NULL + ); + if (result != DD_OK) { + Error("CreatePalette failed", result); + return 0; + } + result = m_pBackBuffer->SetPalette(m_pPalette); // TODO: add FIX_BUGS define and fix this + result = m_pFrontBuffer->SetPalette(m_pPalette); + if (result != DD_OK) { + Error("SetPalette failed", result); + return FALSE; + } + } + + // create debug text only in windowed mode? + return m_bFullScreen || CreateTextSurfaces(); +} + +// OFFSET: LEGO1 0x1009dd80 +HRESULT MxDirectDraw::CreateDDSurface(LPDDSURFACEDESC a2, LPDIRECTDRAWSURFACE* a3, IUnknown* a4) +{ + return m_pDirectDraw->CreateSurface(a2, a3, a4); +} + +// OFFSET: LEGO1 0x1009dda0 +BOOL MxDirectDraw::GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf) +{ + HRESULT result; + + memset(lpDDSurfDesc, 0, sizeof(*lpDDSurfDesc)); + lpDDSurfDesc->dwSize = sizeof(*lpDDSurfDesc); + result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + if (result != DD_OK) { + Error("Error getting a surface description", result); + } + + return (result == DD_OK); +} + +// OFFSET: LEGO1 0x1009ddf0 +BOOL MxDirectDraw::DDCreateSurfaces() +{ + HRESULT result; + DDSCAPS ddscaps; + DDSURFACEDESC ddsd; + + if (m_bFlipSurfaces) { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + if (m_bOnlySystemMemory) { + ddsd.ddsCaps.dwCaps = + DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_SYSTEMMEMORY; + } + ddsd.dwBackBufferCount = 1; + result = CreateDDSurface(&ddsd, &m_pFrontBuffer, 0); + if (result != DD_OK) { + Error("CreateSurface for front/back fullScreen buffer failed", result); + return FALSE; + } + + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + result = m_pFrontBuffer->GetAttachedSurface(&ddscaps, &m_pBackBuffer); + if (result != DD_OK) { + Error("GetAttachedSurface failed to get back buffer", result); + return FALSE; + } + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { + return FALSE; + } + } + else { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + result = CreateDDSurface(&ddsd, &m_pFrontBuffer, NULL); + if (result != DD_OK) { + Error("CreateSurface for window front buffer failed", result); + return FALSE; + } + ddsd.dwHeight = m_currentMode.height; + ddsd.dwWidth = m_currentMode.width; + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + if (m_bOnlySystemMemory) + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_SYSTEMMEMORY; + result = CreateDDSurface(&ddsd, &m_pBackBuffer, NULL); + if (result != DD_OK) { + Error("CreateSurface for window back buffer failed", result); + return FALSE; + } + + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { + return FALSE; + } + + result = m_pDirectDraw->CreateClipper(0, &m_pClipper, NULL); + if (result != DD_OK) { + Error("CreateClipper failed", result); + return FALSE; + } + result = m_pClipper->SetHWnd(0, m_hWndMain); + if (result != DD_OK) { + Error("Clipper SetHWnd failed", result); + return FALSE; + } + result = m_pFrontBuffer->SetClipper(m_pClipper); + if (result != DD_OK) { + Error("SetClipper failed", result); + return FALSE; + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e020 +void MxDirectDraw::FUN_1009E020() +{ + HRESULT result; + byte* line; + DDSURFACEDESC ddsd; + int j; + int count = m_bFlipSurfaces ? 2 : 1; + + for (int i = 0; i < count; i++) { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); + if (result == DDERR_SURFACELOST) { + m_pBackBuffer->Restore(); + result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); + } + + if (result != DD_OK) { + // lock failed + return; + } + + // clear backBuffer + line = (byte*) ddsd.lpSurface; + for (j = ddsd.dwHeight; j--;) { + memset(line, 0, ddsd.dwWidth); + line += ddsd.lPitch; + } + + m_pBackBuffer->Unlock(ddsd.lpSurface); + + if (m_bFlipSurfaces) { + m_pFrontBuffer->Flip(NULL, DDFLIP_WAIT); + } + } +} + +// OFFSET: LEGO1 0x1009e110 +BOOL MxDirectDraw::TextToTextSurface(const char* text, IDirectDrawSurface* pSurface, SIZE& textSizeOnSurface) +{ + HRESULT result; + HDC hdc; + RECT rc; + size_t textLength; + + if (pSurface == NULL) { + return FALSE; + } + + result = pSurface->GetDC(&hdc); + if (result != DD_OK) { + Error("GetDC for text surface failed", result); + return FALSE; + } + + textLength = strlen(text); + + SelectObject(hdc, m_hFont); + SetTextColor(hdc, RGB(255, 255, 0)); + SetBkColor(hdc, RGB(0, 0, 0)); + SetBkMode(hdc, OPAQUE); + GetTextExtentPoint32(hdc, text, textLength, &textSizeOnSurface); + SetRect(&rc, 0, 0, textSizeOnSurface.cx, textSizeOnSurface.cy); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, text, textLength, NULL); + pSurface->ReleaseDC(hdc); + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e210 +BOOL MxDirectDraw::TextToTextSurface1(const char* text) +{ + return TextToTextSurface(text, m_pText1Surface, m_text1SizeOnSurface); +} + +// OFFSET: LEGO1 0x1009e230 +BOOL MxDirectDraw::TextToTextSurface2(const char* text) +{ + return TextToTextSurface(text, m_pText2Surface, m_text2SizeOnSurface); +} + +// OFFSET: LEGO1 0x1009e250 +BOOL MxDirectDraw::CreateTextSurfaces() +{ + HRESULT result; + DDCOLORKEY ddck; + DDSURFACEDESC ddsd; + HDC DC; + char dummyinfo[] = "000x000x00 (RAMP) 0000"; + char dummyfps[] = "000.00 fps (000.00 fps (000.00 fps) 00000 tps)"; + + if (m_hFont != NULL) { + DeleteObject(m_hFont); + } + + m_hFont = CreateFontA( + m_currentMode.width <= 600 ? 12 : 24, + 0, + 0, + 0, + FW_NORMAL, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + VARIABLE_PITCH, + "Arial" + ); + + DC = GetDC(NULL); + SelectObject(DC, m_hFont); + GetTextExtentPointA(DC, dummyfps, strlen(dummyfps), &m_text1SizeOnSurface); + GetTextExtentPointA(DC, dummyinfo, strlen(dummyinfo), &m_text2SizeOnSurface); + ReleaseDC(NULL, DC); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if (m_bOnlySystemMemory) + ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + ddsd.dwHeight = m_text1SizeOnSurface.cy; + ddsd.dwWidth = m_text1SizeOnSurface.cx; + + result = CreateDDSurface(&ddsd, &m_pText1Surface, 0); + if (result != DD_OK) { + Error("CreateSurface for text surface 1 failed", result); + return FALSE; + } + + memset(&ddck, 0, sizeof(ddck)); + m_pText1Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); + if (!TextToTextSurface1(dummyfps)) { + return FALSE; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if (m_bOnlySystemMemory) + ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + ddsd.dwHeight = m_text2SizeOnSurface.cy; + ddsd.dwWidth = m_text2SizeOnSurface.cx; + + result = CreateDDSurface(&ddsd, &m_pText2Surface, 0); + if (result != DD_OK) { + Error("CreateSurface for text surface 2 failed", result); + return FALSE; + } + + memset(&ddck, 0, sizeof(ddck)); + m_pText2Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); + if (!TextToTextSurface2(dummyinfo)) { + return FALSE; + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e4d0 +BOOL MxDirectDraw::RestoreSurfaces() +{ + HRESULT result; + + if (m_pFrontBuffer != NULL) { + if (m_pFrontBuffer->IsLost() == DDERR_SURFACELOST) { + result = m_pFrontBuffer->Restore(); + if (result != DD_OK) { + Error("Restore of front buffer failed", result); + return FALSE; + } + } + } + + if (m_pBackBuffer != NULL) { + if (m_pBackBuffer->IsLost() == DDERR_SURFACELOST) { + result = m_pBackBuffer->Restore(); + if (result != DD_OK) { + Error("Restore of back buffer failed", result); + return FALSE; + } + } + } + + if (m_pZBuffer != NULL) { + if (m_pZBuffer->IsLost() == DDERR_SURFACELOST) { + result = m_pZBuffer->Restore(); + if (result != DD_OK) { + Error("Restore of Z-buffer failed", result); + return FALSE; + } + } + } + + if (m_pText1Surface != NULL) { + if (m_pText1Surface->IsLost() == DDERR_SURFACELOST) { + result = m_pText1Surface->Restore(); + if (result != DD_OK) { + Error("Restore of text surface 1 failed", result); + return FALSE; + } + } + } + + if (m_pText2Surface != NULL) { + if (m_pText2Surface->IsLost() == DDERR_SURFACELOST) { + result = m_pText2Surface->Restore(); + if (result != DD_OK) { + Error("Restore of text surface 2 failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e5e0 +BOOL MxDirectDraw::CreateZBuffer(DWORD memorytype, DWORD depth) +{ + HRESULT result; // eax + LPDIRECTDRAWSURFACE lpZBuffer; // [esp+8h] [ebp-70h] BYREF + DDSURFACEDESC ddsd; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwHeight = m_currentMode.height; + ddsd.dwWidth = m_currentMode.width; + ddsd.dwZBufferBitDepth = depth; + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | memorytype; + + result = CreateDDSurface(&ddsd, &lpZBuffer, 0); + if (result != DD_OK) { + Error("CreateSurface for fullScreen Z-buffer failed", result); + return FALSE; + } + + result = m_pBackBuffer->AddAttachedSurface(lpZBuffer); + if (result != DD_OK) { + Error("AddAttachedBuffer failed for Z-Buffer", result); + return FALSE; + } + + m_pZBuffer = lpZBuffer; + return TRUE; +} + // OFFSET: LEGO1 0x1009e6a0 int MxDirectDraw::Pause(int p_increment) { @@ -259,7 +836,74 @@ int MxDirectDraw::Pause(int p_increment) return TRUE; } -// OFFSET: LEGO1 0x1009E880 +// OFFSET: LEGO1 0x1009e750 +BOOL MxDirectDraw::RestorePaletteEntries() +{ + HRESULT result; + + if (m_bFullScreen && m_bPrimaryPalettized) { + if (m_pPalette) { + result = m_pPalette->SetEntries(0, 0, _countof(m_paletteEntries), m_paletteEntries); + if (result != DD_OK) { + Error("SetEntries failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e7a0 +BOOL MxDirectDraw::RestoreOriginalPaletteEntries() +{ + HRESULT result; + + if (m_bPrimaryPalettized) { + if (m_pPalette) { + result = m_pPalette->SetEntries(0, 0, 256, m_originalPaletteEntries); + if (result != DD_OK) { + Error("SetEntries failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// OFFSET: LEGO1 0x1009e7f0 +int MxDirectDraw::FlipToGDISurface() +{ + HRESULT ret; + + if (m_pDirectDraw) { + ret = m_pDirectDraw->FlipToGDISurface(); + if (ret != DD_OK) { + Error("FlipToGDISurface failed", ret); + } + return !ret; + } + + return 1; +} + +// OFFSET: LEGO1 0x1009e830 +void MxDirectDraw::Error(const char* message, int error) +{ + // 0x10100c70 + static BOOL isInsideError = FALSE; + if (!isInsideError) { + isInsideError = TRUE; + Destroy(); + if (m_pErrorHandler) { + m_pErrorHandler(message, error, m_pErrorHandlerArg); + } + isInsideError = FALSE; + } +} + +// OFFSET: LEGO1 0x1009e880 const char* MxDirectDraw::ErrorToString(HRESULT error) { switch (error) { @@ -469,664 +1113,20 @@ const char* MxDirectDraw::ErrorToString(HRESULT error) } } -// OFFSET: LEGO1 0x1009D6C0 -BOOL MxDirectDraw::CacheOriginalPaletteEntries() +// OFFSET: LEGO1 0x1009efb0 +MxDirectDraw::DeviceModesInfo::DeviceModesInfo() { - HDC DC; - - if (g_is_PALETTEINDEXED8) { - DC = GetDC(0); - GetSystemPaletteEntries(DC, 0, _countof(m_originalPaletteEntries), m_originalPaletteEntries); - ReleaseDC(0, DC); - } - return TRUE; + memset(this, 0, sizeof(*this)); } -// OFFSET: LEGO1 0x1009DD80 -HRESULT MxDirectDraw::CreateDDSurface(LPDDSURFACEDESC a2, LPDIRECTDRAWSURFACE* a3, IUnknown* a4) +// OFFSET: LEGO1 0x1009efd0 +MxDirectDraw::DeviceModesInfo::~DeviceModesInfo() { - return m_pDirectDraw->CreateSurface(a2, a3, a4); -} - -// OFFSET: LEGO1 0x1009E250 -BOOL MxDirectDraw::CreateTextSurfaces() -{ - HRESULT result; - DDCOLORKEY ddck; - DDSURFACEDESC ddsd; - HDC DC; - char dummyinfo[] = "000x000x00 (RAMP) 0000"; - char dummyfps[] = "000.00 fps (000.00 fps (000.00 fps) 00000 tps)"; - - if (m_hFont != NULL) { - DeleteObject(m_hFont); + if (p_guid != NULL) { + delete p_guid; } - m_hFont = CreateFontA( - m_currentMode.width <= 600 ? 12 : 24, - 0, - 0, - 0, - FW_NORMAL, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - VARIABLE_PITCH, - "Arial" - ); - - DC = GetDC(NULL); - SelectObject(DC, m_hFont); - GetTextExtentPointA(DC, dummyfps, strlen(dummyfps), &m_text1SizeOnSurface); - GetTextExtentPointA(DC, dummyinfo, strlen(dummyinfo), &m_text2SizeOnSurface); - ReleaseDC(NULL, DC); - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - if (m_bOnlySystemMemory) - ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; - ddsd.dwHeight = m_text1SizeOnSurface.cy; - ddsd.dwWidth = m_text1SizeOnSurface.cx; - - result = CreateDDSurface(&ddsd, &m_pText1Surface, 0); - if (result != DD_OK) { - Error("CreateSurface for text surface 1 failed", result); - return FALSE; - } - - memset(&ddck, 0, sizeof(ddck)); - m_pText1Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); - if (!TextToTextSurface1(dummyfps)) { - return FALSE; - } - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - if (m_bOnlySystemMemory) - ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; - ddsd.dwHeight = m_text2SizeOnSurface.cy; - ddsd.dwWidth = m_text2SizeOnSurface.cx; - - result = CreateDDSurface(&ddsd, &m_pText2Surface, 0); - if (result != DD_OK) { - Error("CreateSurface for text surface 2 failed", result); - return FALSE; - } - - memset(&ddck, 0, sizeof(ddck)); - m_pText2Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); - if (!TextToTextSurface2(dummyinfo)) { - return FALSE; - } - - return TRUE; -} - -// OFFSET: LEGO1 0x1009E5E0 -BOOL MxDirectDraw::CreateZBuffer(DWORD memorytype, DWORD depth) -{ - HRESULT result; // eax - LPDIRECTDRAWSURFACE lpZBuffer; // [esp+8h] [ebp-70h] BYREF - DDSURFACEDESC ddsd; - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwHeight = m_currentMode.height; - ddsd.dwWidth = m_currentMode.width; - ddsd.dwZBufferBitDepth = depth; - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_ZBUFFERBITDEPTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | memorytype; - - result = CreateDDSurface(&ddsd, &lpZBuffer, 0); - if (result != DD_OK) { - Error("CreateSurface for fullScreen Z-buffer failed", result); - return FALSE; - } - - result = m_pBackBuffer->AddAttachedSurface(lpZBuffer); - if (result != DD_OK) { - Error("AddAttachedBuffer failed for Z-Buffer", result); - return FALSE; - } - - m_pZBuffer = lpZBuffer; - return TRUE; -} - -// OFFSET: LEGO1 0x1009DDF0 -BOOL MxDirectDraw::DDCreateSurfaces() -{ - HRESULT result; - DDSCAPS ddscaps; - DDSURFACEDESC ddsd; - - if (m_bFlipSurfaces) { - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; - if (m_bOnlySystemMemory) { - ddsd.ddsCaps.dwCaps = - DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_SYSTEMMEMORY; - } - ddsd.dwBackBufferCount = 1; - result = CreateDDSurface(&ddsd, &m_pFrontBuffer, 0); - if (result != DD_OK) { - Error("CreateSurface for front/back fullScreen buffer failed", result); - return FALSE; - } - - ddscaps.dwCaps = DDSCAPS_BACKBUFFER; - result = m_pFrontBuffer->GetAttachedSurface(&ddscaps, &m_pBackBuffer); - if (result != DD_OK) { - Error("GetAttachedSurface failed to get back buffer", result); - return FALSE; - } - if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { - return FALSE; - } - } - else { - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - result = CreateDDSurface(&ddsd, &m_pFrontBuffer, NULL); - if (result != DD_OK) { - Error("CreateSurface for window front buffer failed", result); - return FALSE; - } - ddsd.dwHeight = m_currentMode.height; - ddsd.dwWidth = m_currentMode.width; - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; - if (m_bOnlySystemMemory) - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_SYSTEMMEMORY; - result = CreateDDSurface(&ddsd, &m_pBackBuffer, NULL); - if (result != DD_OK) { - Error("CreateSurface for window back buffer failed", result); - return FALSE; - } - - if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { - return FALSE; - } - - result = m_pDirectDraw->CreateClipper(0, &m_pClipper, NULL); - if (result != DD_OK) { - Error("CreateClipper failed", result); - return FALSE; - } - result = m_pClipper->SetHWnd(0, m_hWndMain); - if (result != DD_OK) { - Error("Clipper SetHWnd failed", result); - return FALSE; - } - result = m_pFrontBuffer->SetClipper(m_pClipper); - if (result != DD_OK) { - Error("SetClipper failed", result); - return FALSE; - } - } - - return TRUE; -} - -// OFFSET: LEGO1 0x1009D960 -BOOL MxDirectDraw::DDInit(BOOL fullscreen) -{ - HRESULT result; - - if (fullscreen) { - m_bIgnoreWM_SIZE = 1; - result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); - m_bIgnoreWM_SIZE = 0; - } - else { - result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_NORMAL); - } - - if (result != DD_OK) { - Error("SetCooperativeLevel failed", result); - return FALSE; - } - - m_bFullScreen = fullscreen; - - return TRUE; -} - -// OFFSET: LEGO1 0x1009DA80 -BOOL MxDirectDraw::DDSetMode(int width, int height, int bpp) -{ - HRESULT result; - - if (m_bFullScreen) { - LPDIRECTDRAW lpDD; - - EnableResizing(m_hWndMain, FALSE); - - if (!m_bIsOnPrimaryDevice) { - lpDD = NULL; - result = DirectDrawCreate(0, &lpDD, 0); - if (result == DD_OK) { - result = lpDD->SetCooperativeLevel(m_hWndMain, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT); - if (result == DD_OK) { - lpDD->SetDisplayMode(width, height, 8); - } - } - } - - if (!IsSupportedMode(width, height, bpp)) { - width = m_pCurrentDeviceModesList->m_mode_ARRAY[0].width; - height = m_pCurrentDeviceModesList->m_mode_ARRAY[0].height; - bpp = m_pCurrentDeviceModesList->m_mode_ARRAY[0].bitsPerPixel; - } - - m_bIgnoreWM_SIZE = TRUE; - result = m_pDirectDraw->SetDisplayMode(width, height, bpp); - m_bIgnoreWM_SIZE = FALSE; - if (result != DD_OK) { - Error("SetDisplayMode failed", result); - return FALSE; - } - } - else { - RECT rc; - DWORD dwStyle; - - if (!m_bIsOnPrimaryDevice) { - Error("Attempt made enter a windowed mode on a DirectDraw device that is not the primary display", E_FAIL); - return FALSE; - } - - m_bIgnoreWM_SIZE = TRUE; - dwStyle = GetWindowLong(m_hWndMain, GWL_STYLE); - dwStyle &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPED); - dwStyle |= WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPED; - SetWindowLong(m_hWndMain, GWL_STYLE, dwStyle); - - SetRect(&rc, 0, 0, width - 1, height - 1); - AdjustWindowRectEx( - &rc, - GetWindowLong(m_hWndMain, GWL_STYLE), - GetMenu(m_hWndMain) != NULL, - GetWindowLong(m_hWndMain, GWL_EXSTYLE) - ); - SetWindowPos( - m_hWndMain, - NULL, - 0, - 0, - rc.right - rc.left + 1, - rc.bottom - rc.top + 1, - SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE - ); - SetWindowPos(m_hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); - m_bIgnoreWM_SIZE = FALSE; - } - - m_currentMode.width = width; - m_currentMode.height = height; - m_currentMode.bitsPerPixel = bpp; - - if (!DDCreateSurfaces()) { - return FALSE; - } - - DDSURFACEDESC ddsd; - - FUN_1009E020(); - - if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { - return FALSE; - } - - if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { - m_bPrimaryPalettized = TRUE; - } - else { - m_bPrimaryPalettized = FALSE; - } - - if (m_bPrimaryPalettized) { - result = m_pDirectDraw->CreatePalette( - DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, // 0x4c - m_paletteEntries, - &m_pPalette, - NULL - ); - if (result != DD_OK) { - Error("CreatePalette failed", result); - return 0; - } - result = m_pBackBuffer->SetPalette(m_pPalette); // TODO: add FIX_BUGS define and fix this - result = m_pFrontBuffer->SetPalette(m_pPalette); - if (result != DD_OK) { - Error("SetPalette failed", result); - return FALSE; - } - } - - // create debug text only in windowed mode? - return m_bFullScreen || CreateTextSurfaces(); -} - -// OFFSET: LEGO1 0x1009E830 -void MxDirectDraw::Error(const char* message, int error) -{ - // OFFSET: LEGO1 0x10100C70 - static BOOL isInsideError = FALSE; - if (!isInsideError) { - isInsideError = TRUE; - Destroy(); - if (m_pErrorHandler) { - m_pErrorHandler(message, error, m_pErrorHandlerArg); - } - isInsideError = FALSE; - } -} - -// OFFSET: LEGO1 0x1009DDA0 -BOOL MxDirectDraw::GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf) -{ - HRESULT result; - - memset(lpDDSurfDesc, 0, sizeof(*lpDDSurfDesc)); - lpDDSurfDesc->dwSize = sizeof(*lpDDSurfDesc); - result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); - if (result != DD_OK) { - Error("Error getting a surface description", result); - } - - return (result == DD_OK); -} - -// OFFSET: LEGO1 0x1009D9D0 -BOOL MxDirectDraw::IsSupportedMode(int width, int height, int bpp) -{ - Mode mode = {width, height, bpp}; - - for (int i = 0; i < m_pCurrentDeviceModesList->count; i++) { - if (m_pCurrentDeviceModesList->m_mode_ARRAY[i] == mode) { - return TRUE; - } - } - - return FALSE; -} - -// OFFSET: LEGO1 0x1009D690 -BOOL MxDirectDraw::RecreateDirectDraw(GUID** ppGUID) -{ - if (m_pDirectDraw) { - m_pDirectDraw->Release(); - m_pDirectDraw = NULL; - } - - return (DirectDrawCreate(*ppGUID, &m_pDirectDraw, 0) == DD_OK); -} - -// OFFSET: LEGO1 0x1009E7A0 -BOOL MxDirectDraw::RestoreOriginalPaletteEntries() -{ - HRESULT result; - - if (m_bPrimaryPalettized) { - if (m_pPalette) { - result = m_pPalette->SetEntries(0, 0, 256, m_originalPaletteEntries); - if (result != DD_OK) { - Error("SetEntries failed", result); - return FALSE; - } - } - } - - return TRUE; -} - -// OFFSET: LEGO1 0x1009E750 -BOOL MxDirectDraw::RestorePaletteEntries() -{ - HRESULT result; - - if (m_bFullScreen && m_bPrimaryPalettized) { - if (m_pPalette) { - result = m_pPalette->SetEntries(0, 0, _countof(m_paletteEntries), m_paletteEntries); - if (result != DD_OK) { - Error("SetEntries failed", result); - return FALSE; - } - } - } - - return TRUE; -} - -// OFFSET: LEGO1 0x1009e7f0 -int MxDirectDraw::FlipToGDISurface() -{ - HRESULT ret; - - if (m_pDirectDraw) { - ret = m_pDirectDraw->FlipToGDISurface(); - if (ret != DD_OK) { - Error("FlipToGDISurface failed", ret); - } - return !ret; - } - - return 1; -} - -// OFFSET: LEGO1 0x1009E4D0 -BOOL MxDirectDraw::RestoreSurfaces() -{ - HRESULT result; - - if (m_pFrontBuffer != NULL) { - if (m_pFrontBuffer->IsLost() == DDERR_SURFACELOST) { - result = m_pFrontBuffer->Restore(); - if (result != DD_OK) { - Error("Restore of front buffer failed", result); - return FALSE; - } - } - } - - if (m_pBackBuffer != NULL) { - if (m_pBackBuffer->IsLost() == DDERR_SURFACELOST) { - result = m_pBackBuffer->Restore(); - if (result != DD_OK) { - Error("Restore of back buffer failed", result); - return FALSE; - } - } - } - - if (m_pZBuffer != NULL) { - if (m_pZBuffer->IsLost() == DDERR_SURFACELOST) { - result = m_pZBuffer->Restore(); - if (result != DD_OK) { - Error("Restore of Z-buffer failed", result); - return FALSE; - } - } - } - - if (m_pText1Surface != NULL) { - if (m_pText1Surface->IsLost() == DDERR_SURFACELOST) { - result = m_pText1Surface->Restore(); - if (result != DD_OK) { - Error("Restore of text surface 1 failed", result); - return FALSE; - } - } - } - - if (m_pText2Surface != NULL) { - if (m_pText2Surface->IsLost() == DDERR_SURFACELOST) { - result = m_pText2Surface->Restore(); - if (result != DD_OK) { - Error("Restore of text surface 2 failed", result); - return FALSE; - } - } - } - - return TRUE; -} - -// OFFSET: LEGO1 0x1009D700 -BOOL MxDirectDraw::SetPaletteEntries(const PALETTEENTRY* pPaletteEntries, int paletteEntryCount, BOOL fullscreen) -{ - int reservedLowEntryCount = 10; - int reservedHighEntryCount = 10; - int arraySize = _countof(m_paletteEntries); - HDC hdc; - int i; - - if (g_is_PALETTEINDEXED8) { - hdc = GetDC(NULL); - GetSystemPaletteEntries(hdc, 0, arraySize, m_paletteEntries); - ReleaseDC(NULL, hdc); - } - - for (i = 0; i < reservedLowEntryCount; i++) { - m_paletteEntries[i].peFlags = 0x80; - } - - for (i = reservedLowEntryCount; i < 142; i++) { - m_paletteEntries[i].peFlags = 0x44; - } - - for (i = 142; i < arraySize - reservedHighEntryCount; i++) { - m_paletteEntries[i].peFlags = 0x84; - } - - for (i = arraySize - reservedHighEntryCount; i < arraySize; i++) { - m_paletteEntries[i].peFlags = 0x80; - } - - if (paletteEntryCount != 0) { - for (i = reservedLowEntryCount; (i < paletteEntryCount) && (i < arraySize - reservedHighEntryCount); i++) { - m_paletteEntries[i].peRed = pPaletteEntries[i].peRed; - m_paletteEntries[i].peGreen = pPaletteEntries[i].peGreen; - m_paletteEntries[i].peBlue = pPaletteEntries[i].peBlue; - } - } - - if (m_pPalette != NULL) { - HRESULT result; - result = m_pPalette->SetEntries(0, 0, _countof(m_paletteEntries), m_paletteEntries); - if (result != DD_OK) { - Error("SetEntries failed", result); - return FALSE; - } - } - - return TRUE; -} - -// OFFSET: LEGO1 0x1009E110 -BOOL MxDirectDraw::TextToTextSurface(const char* text, IDirectDrawSurface* pSurface, SIZE& textSizeOnSurface) -{ - HRESULT result; - HDC hdc; - RECT rc; - size_t textLength; - - if (pSurface == NULL) { - return FALSE; - } - - result = pSurface->GetDC(&hdc); - if (result != DD_OK) { - Error("GetDC for text surface failed", result); - return FALSE; - } - - textLength = strlen(text); - - SelectObject(hdc, m_hFont); - SetTextColor(hdc, RGB(255, 255, 0)); - SetBkColor(hdc, RGB(0, 0, 0)); - SetBkMode(hdc, OPAQUE); - GetTextExtentPoint32(hdc, text, textLength, &textSizeOnSurface); - SetRect(&rc, 0, 0, textSizeOnSurface.cx, textSizeOnSurface.cy); - ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, text, textLength, NULL); - pSurface->ReleaseDC(hdc); - - return TRUE; -} - -// OFFSET: LEGO1 0x1009E210 -BOOL MxDirectDraw::TextToTextSurface1(const char* text) -{ - return TextToTextSurface(text, m_pText1Surface, m_text1SizeOnSurface); -} - -// OFFSET: LEGO1 0x1009E230 -BOOL MxDirectDraw::TextToTextSurface2(const char* text) -{ - return TextToTextSurface(text, m_pText2Surface, m_text2SizeOnSurface); -} - -// OFFSET: LEGO1 0x1009E020 -void MxDirectDraw::FUN_1009E020() -{ - HRESULT result; - byte* line; - DDSURFACEDESC ddsd; - int j; - int count = m_bFlipSurfaces ? 2 : 1; - - for (int i = 0; i < count; i++) { - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); - if (result == DDERR_SURFACELOST) { - m_pBackBuffer->Restore(); - result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); - } - - if (result != DD_OK) { - // lock failed - return; - } - - // clear backBuffer - line = (byte*) ddsd.lpSurface; - for (j = ddsd.dwHeight; j--;) { - memset(line, 0, ddsd.dwWidth); - line += ddsd.lPitch; - } - - m_pBackBuffer->Unlock(ddsd.lpSurface); - - if (m_bFlipSurfaces) { - m_pFrontBuffer->Flip(NULL, DDFLIP_WAIT); - } - } -} - -// OFFSET: LEGO1 0x1009D920 -void MxDirectDraw::FUN_1009D920() -{ - RestoreOriginalPaletteEntries(); - if (m_pDirectDraw != NULL) { - m_bIgnoreWM_SIZE = TRUE; - m_pDirectDraw->RestoreDisplayMode(); - m_pDirectDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL); - m_bIgnoreWM_SIZE = FALSE; + if (m_mode_ARRAY != NULL) { + delete m_mode_ARRAY; } } diff --git a/LEGO1/mxdiskstreamcontroller.cpp b/LEGO1/mxdiskstreamcontroller.cpp index 95d6858c..290ff5b3 100644 --- a/LEGO1/mxdiskstreamcontroller.cpp +++ b/LEGO1/mxdiskstreamcontroller.cpp @@ -17,13 +17,6 @@ MxDiskStreamController::~MxDiskStreamController() // TODO } -// OFFSET: LEGO1 0x100c8640 STUB -MxResult MxDiskStreamController::Tickle() -{ - // TODO - return SUCCESS; -} - // OFFSET: LEGO1 0x100c7790 MxResult MxDiskStreamController::Open(const char* p_filename) { @@ -56,17 +49,9 @@ MxResult MxDiskStreamController::vtable0x18(undefined4 p_unknown, undefined4 p_u return SUCCESS; } -// OFFSET: LEGO1 0x100c7ff0 STUB -MxResult MxDiskStreamController::vtable0x20(MxDSAction* p_action) +// OFFSET: LEGO1 0x100c7960 +MxResult MxDiskStreamController::vtable0x34(undefined4 p_unknown) { - // TODO - return FAILURE; -} - -// OFFSET: LEGO1 0x100c8160 STUB -MxResult MxDiskStreamController::vtable0x24(undefined4 p_unknown) -{ - // TODO return FAILURE; } @@ -84,8 +69,23 @@ MxResult MxDiskStreamController::vtable0x30(undefined4 p_unknown) return FAILURE; } -// OFFSET: LEGO1 0x100c7960 -MxResult MxDiskStreamController::vtable0x34(undefined4 p_unknown) +// OFFSET: LEGO1 0x100c7ff0 STUB +MxResult MxDiskStreamController::vtable0x20(MxDSAction* p_action) { + // TODO return FAILURE; } + +// OFFSET: LEGO1 0x100c8160 STUB +MxResult MxDiskStreamController::vtable0x24(undefined4 p_unknown) +{ + // TODO + return FAILURE; +} + +// OFFSET: LEGO1 0x100c8640 STUB +MxResult MxDiskStreamController::Tickle() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/mxdiskstreamprovider.cpp b/LEGO1/mxdiskstreamprovider.cpp index 0c422b99..f8a442c4 100644 --- a/LEGO1/mxdiskstreamprovider.cpp +++ b/LEGO1/mxdiskstreamprovider.cpp @@ -70,6 +70,12 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource) return result; } +// OFFSET: LEGO1 0x100d15e0 STUB +void MxDiskStreamProvider::vtable0x20(undefined4 p_unknown1) +{ + // TODO +} + // OFFSET: LEGO1 0x100d1750 MxResult MxDiskStreamProvider::WaitForWorkToComplete() { @@ -99,12 +105,6 @@ MxU32 MxDiskStreamProvider::GetStreamBuffersNum() return m_pFile->GetStreamBuffersNum(); } -// OFFSET: LEGO1 0x100d15e0 STUB -void MxDiskStreamProvider::vtable0x20(undefined4 p_unknown1) -{ - // TODO -} - // OFFSET: LEGO1 0x100d1eb0 MxU32 MxDiskStreamProvider::GetLengthInDWords() { diff --git a/LEGO1/mxdisplaysurface.cpp b/LEGO1/mxdisplaysurface.cpp index 2e3f8b5a..8c4d7999 100644 --- a/LEGO1/mxdisplaysurface.cpp +++ b/LEGO1/mxdisplaysurface.cpp @@ -28,6 +28,12 @@ void MxDisplaySurface::Reset() memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc)); } +// OFFSET: LEGO1 0x100ba640 STUB +void MxDisplaySurface::FUN_100ba640() +{ + // TODO +} + // OFFSET: LEGO1 0x100ba790 MxResult MxDisplaySurface::Init( MxVideoParam& p_videoParam, @@ -178,33 +184,12 @@ void MxDisplaySurface::SetPalette(MxPalette* p_palette) { } -// OFFSET: LEGO1 0x100bc200 STUB -void MxDisplaySurface::vtable24( - LPDDSURFACEDESC, - MxBitmap*, - undefined4, - undefined4, - undefined4, - undefined4, - undefined4, - undefined4 -) -{ -} - // OFFSET: LEGO1 0x100bacc0 STUB MxBool MxDisplaySurface::vtable28(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) { return 0; } -// OFFSET: LEGO1 0x100bc630 STUB -MxBool MxDisplaySurface:: - vtable2c(LPDDSURFACEDESC, MxBitmap*, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool) -{ - return 0; -} - // OFFSET: LEGO1 0x100bb1d0 STUB MxBool MxDisplaySurface::vtable30( undefined4, @@ -253,8 +238,23 @@ undefined4 MxDisplaySurface::vtable44(undefined4, undefined4*, undefined4, undef return 0; } -// OFFSET: LEGO1 0x100ba640 STUB -void MxDisplaySurface::FUN_100ba640() +// OFFSET: LEGO1 0x100bc200 STUB +void MxDisplaySurface::vtable24( + LPDDSURFACEDESC, + MxBitmap*, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4 +) { - // TODO +} + +// OFFSET: LEGO1 0x100bc630 STUB +MxBool MxDisplaySurface:: + vtable2c(LPDDSURFACEDESC, MxBitmap*, undefined4, undefined4, undefined4, undefined4, undefined4, undefined4, MxBool) +{ + return 0; } diff --git a/LEGO1/mxdsaction.cpp b/LEGO1/mxdsaction.cpp index 3dc58a99..69f3a838 100644 --- a/LEGO1/mxdsaction.cpp +++ b/LEGO1/mxdsaction.cpp @@ -32,6 +32,36 @@ MxDSAction::MxDSAction() this->m_unkTimingField = INT_MIN; } +// OFFSET: LEGO1 0x100ad940 +MxLong MxDSAction::GetDuration() +{ + return this->m_duration; +} + +// OFFSET: LEGO1 0x100ad950 +void MxDSAction::SetDuration(MxLong p_duration) +{ + this->m_duration = p_duration; +} + +// OFFSET: LEGO1 0x100ad960 +MxBool MxDSAction::HasId(MxU32 p_objectId) +{ + return this->GetObjectId() == p_objectId; +} + +// OFFSET: LEGO1 0x100ada40 +void MxDSAction::SetUnkTimingField(MxLong p_unkTimingField) +{ + this->m_unkTimingField = p_unkTimingField; +} + +// OFFSET: LEGO1 0x100ada50 +MxLong MxDSAction::GetUnkTimingField() +{ + return this->m_unkTimingField; +} + // OFFSET: LEGO1 0x100ada80 MxDSAction::~MxDSAction() { @@ -58,17 +88,6 @@ void MxDSAction::CopyFrom(MxDSAction& p_dsAction) this->m_unkTimingField = p_dsAction.m_unkTimingField; } -// OFFSET: LEGO1 0x100adc10 -MxDSAction& MxDSAction::operator=(MxDSAction& p_dsAction) -{ - if (this == &p_dsAction) - return *this; - - MxDSObject::operator=(p_dsAction); - this->CopyFrom(p_dsAction); - return *this; -} - // OFFSET: LEGO1 0x100adbe0 MxU32 MxDSAction::GetSizeOnDisk() { @@ -80,42 +99,15 @@ MxU32 MxDSAction::GetSizeOnDisk() return totalSizeOnDisk; } -// OFFSET: LEGO1 0x100adf70 -void MxDSAction::Deserialize(char** p_source, MxS16 p_unk24) +// OFFSET: LEGO1 0x100adc10 +MxDSAction& MxDSAction::operator=(MxDSAction& p_dsAction) { - MxDSObject::Deserialize(p_source, p_unk24); + if (this == &p_dsAction) + return *this; - GetScalar(p_source, this->m_flags); - GetScalar(p_source, this->m_startTime); - GetScalar(p_source, this->m_duration); - GetScalar(p_source, this->m_loopCount); - GetDouble(p_source, this->m_location[0]); - GetDouble(p_source, this->m_location[1]); - GetDouble(p_source, this->m_location[2]); - GetDouble(p_source, this->m_direction[0]); - GetDouble(p_source, this->m_direction[1]); - GetDouble(p_source, this->m_direction[2]); - GetDouble(p_source, this->m_up[0]); - GetDouble(p_source, this->m_up[1]); - GetDouble(p_source, this->m_up[2]); - - MxU16 extraLength = GetScalar((MxU16**) p_source); - if (extraLength) { - AppendData(extraLength, *p_source); - *p_source += extraLength; - } -} - -// OFFSET: LEGO1 0x100ad940 -MxLong MxDSAction::GetDuration() -{ - return this->m_duration; -} - -// OFFSET: LEGO1 0x100ad950 -void MxDSAction::SetDuration(MxLong p_duration) -{ - this->m_duration = p_duration; + MxDSObject::operator=(p_dsAction); + this->CopyFrom(p_dsAction); + return *this; } // OFFSET: LEGO1 0x100adc40 @@ -129,6 +121,12 @@ MxDSAction* MxDSAction::Clone() return clone; } +// OFFSET: LEGO1 0x100adcd0 +MxLong MxDSAction::GetElapsedTime() +{ + return Timer()->GetTime() - this->m_unkTimingField; +} + // OFFSET: LEGO1 0x100add00 void MxDSAction::MergeFrom(MxDSAction& p_dsAction) { @@ -178,30 +176,6 @@ void MxDSAction::MergeFrom(MxDSAction& p_dsAction) } } -// OFFSET: LEGO1 0x100ad960 -MxBool MxDSAction::HasId(MxU32 p_objectId) -{ - return this->GetObjectId() == p_objectId; -} - -// OFFSET: LEGO1 0x100ada40 -void MxDSAction::SetUnkTimingField(MxLong p_unkTimingField) -{ - this->m_unkTimingField = p_unkTimingField; -} - -// OFFSET: LEGO1 0x100ada50 -MxLong MxDSAction::GetUnkTimingField() -{ - return this->m_unkTimingField; -} - -// OFFSET: LEGO1 0x100adcd0 -MxLong MxDSAction::GetElapsedTime() -{ - return Timer()->GetTime() - this->m_unkTimingField; -} - // OFFSET: LEGO1 0x100ade60 void MxDSAction::AppendData(MxU16 p_extraLength, const char* p_extraData) { @@ -229,3 +203,29 @@ void MxDSAction::AppendData(MxU16 p_extraLength, const char* p_extraData) } } } + +// OFFSET: LEGO1 0x100adf70 +void MxDSAction::Deserialize(char** p_source, MxS16 p_unk24) +{ + MxDSObject::Deserialize(p_source, p_unk24); + + GetScalar(p_source, this->m_flags); + GetScalar(p_source, this->m_startTime); + GetScalar(p_source, this->m_duration); + GetScalar(p_source, this->m_loopCount); + GetDouble(p_source, this->m_location[0]); + GetDouble(p_source, this->m_location[1]); + GetDouble(p_source, this->m_location[2]); + GetDouble(p_source, this->m_direction[0]); + GetDouble(p_source, this->m_direction[1]); + GetDouble(p_source, this->m_direction[2]); + GetDouble(p_source, this->m_up[0]); + GetDouble(p_source, this->m_up[1]); + GetDouble(p_source, this->m_up[2]); + + MxU16 extraLength = GetScalar((MxU16**) p_source); + if (extraLength) { + AppendData(extraLength, *p_source); + *p_source += extraLength; + } +} diff --git a/LEGO1/mxdsfile.cpp b/LEGO1/mxdsfile.cpp index 0ba17c52..045cf370 100644 --- a/LEGO1/mxdsfile.cpp +++ b/LEGO1/mxdsfile.cpp @@ -5,6 +5,12 @@ #define SI_MAJOR_VERSION 2 #define SI_MINOR_VERSION 2 +// OFFSET: LEGO1 0x100bfed0 +MxDSFile::~MxDSFile() +{ + Close(); +} + // OFFSET: LEGO1 0x100cc4b0 MxDSFile::MxDSFile(const char* filename, MxULong skipReadingChunks) { @@ -12,12 +18,6 @@ MxDSFile::MxDSFile(const char* filename, MxULong skipReadingChunks) m_skipReadingChunks = skipReadingChunks; } -// OFFSET: LEGO1 0x100bfed0 -MxDSFile::~MxDSFile() -{ - Close(); -} - // OFFSET: LEGO1 0x100cc590 MxLong MxDSFile::Open(MxULong uStyle) { @@ -46,16 +46,6 @@ MxLong MxDSFile::Open(MxULong uStyle) return longResult; } -// OFFSET: LEGO1 0x100cc780 -MxResult MxDSFile::Read(unsigned char* p_buf, MxULong p_nbytes) -{ - if (m_io.Read(p_buf, p_nbytes) != p_nbytes) - return FAILURE; - - m_position += p_nbytes; - return SUCCESS; -} - // OFFSET: LEGO1 0x100cc620 MxLong MxDSFile::ReadChunks() { @@ -91,6 +81,30 @@ MxLong MxDSFile::ReadChunks() } } +// OFFSET: LEGO1 0x100cc740 +MxLong MxDSFile::Close() +{ + m_io.Close(0); + m_position = -1; + memset(&m_header, 0, sizeof(m_header)); + if (m_lengthInDWords != 0) { + m_lengthInDWords = 0; + delete[] m_pBuffer; + m_pBuffer = NULL; + } + return 0; +} + +// OFFSET: LEGO1 0x100cc780 +MxResult MxDSFile::Read(unsigned char* p_buf, MxULong p_nbytes) +{ + if (m_io.Read(p_buf, p_nbytes) != p_nbytes) + return FAILURE; + + m_position += p_nbytes; + return SUCCESS; +} + // OFFSET: LEGO1 0x100cc7b0 MxLong MxDSFile::Seek(MxLong lOffset, int iOrigin) { @@ -108,17 +122,3 @@ MxULong MxDSFile::GetStreamBuffersNum() { return m_header.streamBuffersNum; } - -// OFFSET: LEGO1 0x100cc740 -MxLong MxDSFile::Close() -{ - m_io.Close(0); - m_position = -1; - memset(&m_header, 0, sizeof(m_header)); - if (m_lengthInDWords != 0) { - m_lengthInDWords = 0; - delete[] m_pBuffer; - m_pBuffer = NULL; - } - return 0; -} diff --git a/LEGO1/mxdsmediaaction.cpp b/LEGO1/mxdsmediaaction.cpp index 61c75654..fabdc569 100644 --- a/LEGO1/mxdsmediaaction.cpp +++ b/LEGO1/mxdsmediaaction.cpp @@ -47,6 +47,23 @@ MxDSMediaAction& MxDSMediaAction::operator=(MxDSMediaAction& p_dsMediaAction) return *this; } +// OFFSET: LEGO1 0x100c8e80 +void MxDSMediaAction::CopyMediaSrcPath(const char* p_mediaSrcPath) +{ + if (this->m_mediaSrcPath == p_mediaSrcPath) + return; + + delete[] this->m_mediaSrcPath; + + if (p_mediaSrcPath) { + this->m_mediaSrcPath = new char[strlen(p_mediaSrcPath) + 1]; + if (this->m_mediaSrcPath) + strcpy(this->m_mediaSrcPath, p_mediaSrcPath); + } + else + this->m_mediaSrcPath = NULL; +} + // OFFSET: LEGO1 0x100c8f10 MxU32 MxDSMediaAction::GetSizeOnDisk() { @@ -75,20 +92,3 @@ void MxDSMediaAction::Deserialize(char** p_source, MxS16 p_unk24) GetScalar(p_source, this->m_paletteManagement); GetScalar(p_source, this->m_sustainTime); } - -// OFFSET: LEGO1 0x100c8e80 -void MxDSMediaAction::CopyMediaSrcPath(const char* p_mediaSrcPath) -{ - if (this->m_mediaSrcPath == p_mediaSrcPath) - return; - - delete[] this->m_mediaSrcPath; - - if (p_mediaSrcPath) { - this->m_mediaSrcPath = new char[strlen(p_mediaSrcPath) + 1]; - if (this->m_mediaSrcPath) - strcpy(this->m_mediaSrcPath, p_mediaSrcPath); - } - else - this->m_mediaSrcPath = NULL; -} diff --git a/LEGO1/mxdsobject.h b/LEGO1/mxdsobject.h index 9064fc81..28e8a636 100644 --- a/LEGO1/mxdsobject.h +++ b/LEGO1/mxdsobject.h @@ -6,6 +6,10 @@ #include "mxcore.h" #include "mxdstypes.h" +// TODO: Find proper compilation unit to put this +// OFFSET: LEGO1 0x10005530 TEMPLATE +// MxDSObject::SetAtomId + // VTABLE 0x100dc868 // SIZE 0x2c class MxDSObject : public MxCore { @@ -28,11 +32,9 @@ class MxDSObject : public MxCore { return !strcmp(name, MxDSObject::ClassName()) || MxCore::IsA(name); }; // vtable+10; - virtual undefined4 unk14(); // vtable+14; - virtual MxU32 GetSizeOnDisk(); // vtable+18; - virtual void Deserialize(char** p_source, MxS16 p_unk24); // vtable+1c; - // OFFSET: ISLE 0x401c40 - // OFFSET: LEGO1 0x10005530 + virtual undefined4 unk14(); // vtable+14; + virtual MxU32 GetSizeOnDisk(); // vtable+18; + virtual void Deserialize(char** p_source, MxS16 p_unk24); // vtable+1c; inline virtual void SetAtomId(MxAtomId p_atomId) { this->m_atomId = p_atomId; } // vtable+20; inline const MxAtomId& GetAtomId() { return this->m_atomId; } diff --git a/LEGO1/mxdssound.cpp b/LEGO1/mxdssound.cpp index 32ec470e..d0214f52 100644 --- a/LEGO1/mxdssound.cpp +++ b/LEGO1/mxdssound.cpp @@ -34,23 +34,6 @@ MxDSSound& MxDSSound::operator=(MxDSSound& p_dsSound) return *this; } -// OFFSET: LEGO1 0x100c95d0 -MxU32 MxDSSound::GetSizeOnDisk() -{ - MxU32 totalSizeOnDisk = MxDSMediaAction::GetSizeOnDisk(); - - this->m_sizeOnDisk = sizeof(this->m_volume); - return totalSizeOnDisk + 4; -} - -// OFFSET: LEGO1 0x100c95a0 -void MxDSSound::Deserialize(char** p_source, MxS16 p_unk24) -{ - MxDSMediaAction::Deserialize(p_source, p_unk24); - - GetScalar(p_source, this->m_volume); -} - // OFFSET: LEGO1 0x100c9510 MxDSAction* MxDSSound::Clone() { @@ -61,3 +44,20 @@ MxDSAction* MxDSSound::Clone() return clone; } + +// OFFSET: LEGO1 0x100c95a0 +void MxDSSound::Deserialize(char** p_source, MxS16 p_unk24) +{ + MxDSMediaAction::Deserialize(p_source, p_unk24); + + GetScalar(p_source, this->m_volume); +} + +// OFFSET: LEGO1 0x100c95d0 +MxU32 MxDSSound::GetSizeOnDisk() +{ + MxU32 totalSizeOnDisk = MxDSMediaAction::GetSizeOnDisk(); + + this->m_sizeOnDisk = sizeof(this->m_volume); + return totalSizeOnDisk + 4; +} diff --git a/LEGO1/mxdsstreamingaction.cpp b/LEGO1/mxdsstreamingaction.cpp index ec241943..ffcc55fa 100644 --- a/LEGO1/mxdsstreamingaction.cpp +++ b/LEGO1/mxdsstreamingaction.cpp @@ -14,6 +14,14 @@ MxDSStreamingAction::MxDSStreamingAction(MxDSAction& p_dsAction, MxU32 p_offset) this->m_bufferOffset = p_offset; } +// OFFSET: LEGO1 0x100cd090 +MxBool MxDSStreamingAction::HasId(MxU32 p_objectId) +{ + if (this->m_internalAction) + return this->m_internalAction->HasId(p_objectId); + return FALSE; +} + // OFFSET: LEGO1 0x100cd0d0 MxDSStreamingAction::MxDSStreamingAction(MxDSStreamingAction& p_dsStreamingAction) { @@ -32,6 +40,20 @@ MxDSStreamingAction::~MxDSStreamingAction() delete this->m_internalAction; } +// OFFSET: LEGO1 0x100cd1e0 +MxResult MxDSStreamingAction::Init() +{ + this->m_unk94 = 0; + this->m_bufferOffset = 0; + this->m_unk9c = 0; + this->m_unka0 = NULL; + this->m_unka4 = NULL; + this->m_unka8 = 0; + this->m_unkac = 2; + this->m_internalAction = NULL; + return SUCCESS; +} + // OFFSET: LEGO1 0x100cd220 MxDSStreamingAction* MxDSStreamingAction::CopyFrom(MxDSStreamingAction& p_dsStreamingAction) { @@ -48,28 +70,6 @@ MxDSStreamingAction* MxDSStreamingAction::CopyFrom(MxDSStreamingAction& p_dsStre return this; } -// OFFSET: LEGO1 0x100cd090 -MxBool MxDSStreamingAction::HasId(MxU32 p_objectId) -{ - if (this->m_internalAction) - return this->m_internalAction->HasId(p_objectId); - return FALSE; -} - -// OFFSET: LEGO1 0x100cd1e0 -MxResult MxDSStreamingAction::Init() -{ - this->m_unk94 = 0; - this->m_bufferOffset = 0; - this->m_unk9c = 0; - this->m_unka0 = NULL; - this->m_unka4 = NULL; - this->m_unka8 = 0; - this->m_unkac = 2; - this->m_internalAction = NULL; - return SUCCESS; -} - // OFFSET: LEGO1 0x100cd2a0 void MxDSStreamingAction::SetInternalAction(MxDSAction* p_dsAction) { diff --git a/LEGO1/mxentity.cpp b/LEGO1/mxentity.cpp index 524bb293..bcf66a1b 100644 --- a/LEGO1/mxentity.cpp +++ b/LEGO1/mxentity.cpp @@ -2,17 +2,6 @@ DECOMP_SIZE_ASSERT(MxEntity, 0x10) -// OFFSET: LEGO1 0x1001d190 -MxEntity::MxEntity() -{ - this->m_mxEntityId = -1; -} - -// OFFSET: LEGO1 0x1000c110 -MxEntity::~MxEntity() -{ -} - // OFFSET: LEGO1 0x10001070 MxResult MxEntity::Create(MxS32 p_id, const MxAtomId& p_atom) { @@ -20,3 +9,14 @@ MxResult MxEntity::Create(MxS32 p_id, const MxAtomId& p_atom) this->m_atom = p_atom; return SUCCESS; } + +// OFFSET: LEGO1 0x1000c110 +MxEntity::~MxEntity() +{ +} + +// OFFSET: LEGO1 0x1001d190 +MxEntity::MxEntity() +{ + this->m_mxEntityId = -1; +} diff --git a/LEGO1/mxflcpresenter.h b/LEGO1/mxflcpresenter.h index 6fcf8973..7cf6aa9d 100644 --- a/LEGO1/mxflcpresenter.h +++ b/LEGO1/mxflcpresenter.h @@ -11,6 +11,12 @@ class MxFlcPresenter : public MxVideoPresenter { MxFlcPresenter(); virtual ~MxFlcPresenter() override; + // OFFSET: LEGO1 0x1004e200 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, MxFlcPresenter::ClassName()) || MxVideoPresenter::IsA(name); + } + // OFFSET: LEGO1 0x100b33f0 inline virtual const char* ClassName() const override // vtable+0xc { @@ -18,12 +24,6 @@ class MxFlcPresenter : public MxVideoPresenter { return "MxFlcPresenter"; } - // OFFSET: LEGO1 0x1004e200 - inline virtual MxBool IsA(const char* name) const override // vtable+0x10 - { - return !strcmp(name, MxFlcPresenter::ClassName()) || MxVideoPresenter::IsA(name); - } - virtual void VTable0x70() override; // vtable+0x70 undefined4* m_unk64; diff --git a/LEGO1/mxmediamanager.cpp b/LEGO1/mxmediamanager.cpp index 8fa2ec32..4a63791a 100644 --- a/LEGO1/mxmediamanager.cpp +++ b/LEGO1/mxmediamanager.cpp @@ -28,24 +28,6 @@ MxResult MxMediaManager::Init() return SUCCESS; } -// OFFSET: LEGO1 0x100b8790 -MxResult MxMediaManager::Tickle() -{ - MxAutoLocker lock(&this->m_criticalSection); - MxPresenter* presenter; - MxPresenterListCursor cursor(this->m_presenters); - - while (cursor.Next(presenter)) - presenter->Tickle(); - - cursor.Reset(); - - while (cursor.Next(presenter)) - presenter->PutData(); - - return SUCCESS; -} - // OFFSET: LEGO1 0x100b85e0 MxResult MxMediaManager::InitPresenters() { @@ -72,6 +54,24 @@ void MxMediaManager::Destroy() Init(); } +// OFFSET: LEGO1 0x100b8790 +MxResult MxMediaManager::Tickle() +{ + MxAutoLocker lock(&this->m_criticalSection); + MxPresenter* presenter; + MxPresenterListCursor cursor(this->m_presenters); + + while (cursor.Next(presenter)) + presenter->Tickle(); + + cursor.Reset(); + + while (cursor.Next(presenter)) + presenter->PutData(); + + return SUCCESS; +} + // OFFSET: LEGO1 0x100b88c0 void MxMediaManager::AddPresenter(MxPresenter& p_presenter) { diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index 0a4d691a..a1c6f98e 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -103,6 +103,69 @@ MxStreamChunk* MxMediaPresenter::NextChunk() return result; } +// OFFSET: LEGO1 0x100b5700 +MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + MxResult result = FAILURE; + MxAutoLocker lock(&m_criticalSection); + + if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { + if (m_action->GetFlags() & MxDSAction::Flag_Looping) { + m_chunks = new MxStreamChunkList; + m_cursor = new MxStreamChunkListCursor(m_chunks); + + if (!m_chunks && !m_cursor) + goto done; + } + + if (p_controller) { + m_subscriber = new MxDSSubscriber; + + if (!m_subscriber || + m_subscriber->FUN_100b7ed0(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS) + goto done; + } + + result = SUCCESS; + } + +done: + return result; +} + +// OFFSET: LEGO1 0x100b5bc0 +void MxMediaPresenter::EndAction() +{ + MxAutoLocker lock(&m_criticalSection); + + if (!m_action) + return; + + m_currentChunk = NULL; + + if (m_action->GetFlags() & MxDSAction::Flag_World && + (!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) { + MxPresenter::Enable(FALSE); + SetTickleState(TickleState_Idle); + } + else { + MxDSAction* action = m_action; + MxPresenter::EndAction(); + + if (m_subscriber) { + delete m_subscriber; + m_subscriber = NULL; + } + + if (action && action->GetUnknown8c()) { + NotificationManager()->Send( + action->GetUnknown8c(), + &MxEndActionNotificationParam(c_notificationEndAction, this, action, FALSE) + ); + } + } +} + // OFFSET: LEGO1 0x100b5d10 MxResult MxMediaPresenter::Tickle() { @@ -170,6 +233,20 @@ void MxMediaPresenter::DoneTickle() EndAction(); } +// OFFSET: LEGO1 0x100b5f10 +void MxMediaPresenter::AppendChunk(MxStreamChunk* p_chunk) +{ + MxStreamChunk* chunk = new MxStreamChunk; + + MxU32 length = p_chunk->GetLength(); + chunk->SetLength(length); + chunk->SetData(new MxU8[length]); + chunk->SetTime(p_chunk->GetTime()); + + memcpy(chunk->GetData(), p_chunk->GetData(), chunk->GetLength()); + m_chunks->Append(chunk); +} + // OFFSET: LEGO1 0x100b6030 void MxMediaPresenter::Enable(MxBool p_enable) { @@ -189,80 +266,3 @@ void MxMediaPresenter::Enable(MxBool p_enable) } } } - -// OFFSET: LEGO1 0x100b5700 -MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) -{ - MxResult result = FAILURE; - MxAutoLocker lock(&m_criticalSection); - - if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { - if (m_action->GetFlags() & MxDSAction::Flag_Looping) { - m_chunks = new MxStreamChunkList; - m_cursor = new MxStreamChunkListCursor(m_chunks); - - if (!m_chunks && !m_cursor) - goto done; - } - - if (p_controller) { - m_subscriber = new MxDSSubscriber; - - if (!m_subscriber || - m_subscriber->FUN_100b7ed0(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS) - goto done; - } - - result = SUCCESS; - } - -done: - return result; -} - -// OFFSET: LEGO1 0x100b5bc0 -void MxMediaPresenter::EndAction() -{ - MxAutoLocker lock(&m_criticalSection); - - if (!m_action) - return; - - m_currentChunk = NULL; - - if (m_action->GetFlags() & MxDSAction::Flag_World && - (!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) { - MxPresenter::Enable(FALSE); - SetTickleState(TickleState_Idle); - } - else { - MxDSAction* action = m_action; - MxPresenter::EndAction(); - - if (m_subscriber) { - delete m_subscriber; - m_subscriber = NULL; - } - - if (action && action->GetUnknown8c()) { - NotificationManager()->Send( - action->GetUnknown8c(), - &MxEndActionNotificationParam(c_notificationEndAction, this, action, FALSE) - ); - } - } -} - -// OFFSET: LEGO1 0x100b5f10 -void MxMediaPresenter::AppendChunk(MxStreamChunk* p_chunk) -{ - MxStreamChunk* chunk = new MxStreamChunk; - - MxU32 length = p_chunk->GetLength(); - chunk->SetLength(length); - chunk->SetData(new MxU8[length]); - chunk->SetTime(p_chunk->GetTime()); - - memcpy(chunk->GetData(), p_chunk->GetData(), chunk->GetLength()); - m_chunks->Append(chunk); -} diff --git a/LEGO1/mxmusicmanager.cpp b/LEGO1/mxmusicmanager.cpp index 542bea64..e380bcf7 100644 --- a/LEGO1/mxmusicmanager.cpp +++ b/LEGO1/mxmusicmanager.cpp @@ -19,24 +19,6 @@ MxMusicManager::~MxMusicManager() Destroy(TRUE); } -// OFFSET: LEGO1 0x100c0b20 -void MxMusicManager::DeinitializeMIDI() -{ - m_criticalSection.Enter(); - - if (m_MIDIInitialized) { - m_MIDIInitialized = FALSE; - midiStreamStop(m_MIDIStreamH); - midiOutUnprepareHeader((HMIDIOUT) m_MIDIStreamH, m_MIDIHdrP, sizeof(MIDIHDR)); - midiOutSetVolume((HMIDIOUT) m_MIDIStreamH, m_MIDIVolume); - midiStreamClose(m_MIDIStreamH); - delete m_MIDIHdrP; - InitData(); - } - - m_criticalSection.Leave(); -} - // OFFSET: LEGO1 0x100c0690 void MxMusicManager::Init() { @@ -80,19 +62,6 @@ void MxMusicManager::Destroy(MxBool p_fromDestructor) } } -// OFFSET: LEGO1 0x100c0930 -void MxMusicManager::Destroy() -{ - Destroy(FALSE); -} - -// OFFSET: LEGO1 0x100c09a0 -MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume) -{ - MxS32 result = (p_volume * 0xffff) / 100; - return (result << 0x10) | result; -} - // OFFSET: LEGO1 0x100c07f0 void MxMusicManager::SetMIDIVolume() { @@ -105,15 +74,6 @@ void MxMusicManager::SetMIDIVolume() } } -// OFFSET: LEGO1 0x100c0940 -void MxMusicManager::SetVolume(MxS32 p_volume) -{ - MxAudioManager::SetVolume(p_volume); - m_criticalSection.Enter(); - SetMIDIVolume(); - m_criticalSection.Leave(); -} - // OFFSET: LEGO1 0x100c0840 MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { @@ -144,3 +104,43 @@ MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) return status; } + +// OFFSET: LEGO1 0x100c0930 +void MxMusicManager::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100c0940 +void MxMusicManager::SetVolume(MxS32 p_volume) +{ + MxAudioManager::SetVolume(p_volume); + m_criticalSection.Enter(); + SetMIDIVolume(); + m_criticalSection.Leave(); +} + +// OFFSET: LEGO1 0x100c09a0 +MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume) +{ + MxS32 result = (p_volume * 0xffff) / 100; + return (result << 0x10) | result; +} + +// OFFSET: LEGO1 0x100c0b20 +void MxMusicManager::DeinitializeMIDI() +{ + m_criticalSection.Enter(); + + if (m_MIDIInitialized) { + m_MIDIInitialized = FALSE; + midiStreamStop(m_MIDIStreamH); + midiOutUnprepareHeader((HMIDIOUT) m_MIDIStreamH, m_MIDIHdrP, sizeof(MIDIHDR)); + midiOutSetVolume((HMIDIOUT) m_MIDIStreamH, m_MIDIVolume); + midiStreamClose(m_MIDIStreamH); + delete m_MIDIHdrP; + InitData(); + } + + m_criticalSection.Leave(); +} diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index a548f530..5f7847a1 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -44,6 +44,47 @@ MxNotificationManager::~MxNotificationManager() TickleManager()->UnregisterClient(this); } +// OFFSET: LEGO1 0x100ac600 +MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxResult result = SUCCESS; + m_queue = new MxNotificationPtrList(); + + if (m_queue == NULL) { + result = FAILURE; + } + else { + TickleManager()->RegisterClient(this, 10); + } + + return result; +} + +// OFFSET: LEGO1 0x100ac6c0 +MxResult MxNotificationManager::Send(MxCore* p_listener, MxNotificationParam* p_param) +{ + MxAutoLocker lock(&m_lock); + + if (m_active == FALSE) { + return FAILURE; + } + else { + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it == m_listenerIds.end()) { + return FAILURE; + } + else { + MxNotification* notif = new MxNotification(p_listener, p_param); + if (notif != NULL) { + m_queue->push_back(notif); + return SUCCESS; + } + } + } + + return FAILURE; +} + // OFFSET: LEGO1 0x100ac800 MxResult MxNotificationManager::Tickle() { @@ -73,47 +114,6 @@ MxResult MxNotificationManager::Tickle() } } -// OFFSET: LEGO1 0x100ac600 -MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) -{ - MxResult result = SUCCESS; - m_queue = new MxNotificationPtrList(); - - if (m_queue == NULL) { - result = FAILURE; - } - else { - TickleManager()->RegisterClient(this, 10); - } - - return result; -} - -// OFFSET: LEGO1 0x100acd20 -void MxNotificationManager::Register(MxCore* p_listener) -{ - MxAutoLocker lock(&m_lock); - - MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); - if (it != m_listenerIds.end()) - return; - - m_listenerIds.push_back(p_listener->GetId()); -} - -// OFFSET: LEGO1 0x100acdf0 -void MxNotificationManager::Unregister(MxCore* p_listener) -{ - MxAutoLocker lock(&m_lock); - - MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); - - if (it != m_listenerIds.end()) { - m_listenerIds.erase(it); - FlushPending(p_listener); - } -} - // OFFSET: LEGO1 0x100ac990 void MxNotificationManager::FlushPending(MxCore* p_listener) { @@ -163,27 +163,27 @@ void MxNotificationManager::FlushPending(MxCore* p_listener) } } -// OFFSET: LEGO1 0x100ac6c0 -MxResult MxNotificationManager::Send(MxCore* p_listener, MxNotificationParam* p_param) +// OFFSET: LEGO1 0x100acd20 +void MxNotificationManager::Register(MxCore* p_listener) { MxAutoLocker lock(&m_lock); - if (m_active == FALSE) { - return FAILURE; - } - else { - MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); - if (it == m_listenerIds.end()) { - return FAILURE; - } - else { - MxNotification* notif = new MxNotification(p_listener, p_param); - if (notif != NULL) { - m_queue->push_back(notif); - return SUCCESS; - } - } - } + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it != m_listenerIds.end()) + return; - return FAILURE; + m_listenerIds.push_back(p_listener->GetId()); +} + +// OFFSET: LEGO1 0x100acdf0 +void MxNotificationManager::Unregister(MxCore* p_listener) +{ + MxAutoLocker lock(&m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + + if (it != m_listenerIds.end()) { + m_listenerIds.erase(it); + FlushPending(p_listener); + } } diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 469e058a..3a9a2fe1 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -25,12 +25,115 @@ MxBool g_use3dSound; // 0x101015b0 MxOmni* MxOmni::g_instance = NULL; +// OFFSET: LEGO1 0x100159e0 +void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last) +{ + MxDSAction action; + + action.SetAtomId(*p_id); + action.SetUnknown24(-2); + + for (MxS32 l_first = p_first, l_last = p_last; l_first <= l_last; l_first++) { + action.SetObjectId(l_first); + DeleteObject(action); + } +} + +// OFFSET: LEGO1 0x10058a90 +MxBool MxOmni::IsTimerRunning() +{ + return m_timerRunning; +} + +// OFFSET: LEGO1 0x100acea0 +MxObjectFactory* ObjectFactory() +{ + return MxOmni::GetInstance()->GetObjectFactory(); +} + +// OFFSET: LEGO1 0x100aceb0 +MxNotificationManager* NotificationManager() +{ + return MxOmni::GetInstance()->GetNotificationManager(); +} + +// OFFSET: LEGO1 0x100acec0 +MxTickleManager* TickleManager() +{ + return MxOmni::GetInstance()->GetTickleManager(); +} + +// OFFSET: LEGO1 0x100aced0 +MxTimer* Timer() +{ + return MxOmni::GetInstance()->GetTimer(); +} + +// OFFSET: LEGO1 0x100acee0 +MxAtomIdCounterSet* AtomIdCounterSet() +{ + return MxOmni::GetInstance()->GetAtomIdCounterSet(); +} + +// OFFSET: LEGO1 0x100acef0 +MxStreamer* Streamer() +{ + return MxOmni::GetInstance()->GetStreamer(); +} + +// OFFSET: LEGO1 0x100acf00 +MxSoundManager* MSoundManager() +{ + return MxOmni::GetInstance()->GetSoundManager(); +} + +// OFFSET: LEGO1 0x100acf10 +MxVideoManager* MVideoManager() +{ + return MxOmni::GetInstance()->GetVideoManager(); +} + +// OFFSET: LEGO1 0x100acf20 +MxVariableTable* VariableTable() +{ + return MxOmni::GetInstance()->GetVariableTable(); +} + +// OFFSET: LEGO1 0x100acf30 +MxMusicManager* MusicManager() +{ + return MxOmni::GetInstance()->GetMusicManager(); +} + +// OFFSET: LEGO1 0x100acf40 +MxEventManager* EventManager() +{ + return MxOmni::GetInstance()->GetEventManager(); +} + +// OFFSET: LEGO1 0x100acf70 +MxResult DeleteObject(MxDSAction& p_dsAction) +{ + return MxOmni::GetInstance()->DeleteObject(p_dsAction); +} + // OFFSET: LEGO1 0x100aef10 MxOmni::MxOmni() { Init(); } +// OFFSET: LEGO1 0x100aefb0 +MxEntity* MxOmni::FindWorld(const char*, MxS32, MxPresenter*) +{ + return NULL; +} + +// OFFSET: LEGO1 0x100aefc0 +void MxOmni::NotifyCurrentEntity(MxNotificationParam* p_param) +{ +} + // OFFSET: LEGO1 0x100aeff0 MxOmni::~MxOmni() { @@ -55,130 +158,6 @@ void MxOmni::Init() m_timerRunning = NULL; } -// OFFSET: LEGO1 0x100b0090 -MxResult MxOmni::Start(MxDSAction* p_dsAction) -{ - MxResult result = FAILURE; - if (p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) { - result = m_streamer->FUN_100b99b0(p_dsAction); - } - - return result; -} - -// OFFSET: LEGO1 0x100b00c0 STUB -MxResult MxOmni::DeleteObject(MxDSAction& p_dsAction) -{ - // TODO - return FAILURE; -} - -// OFFSET: LEGO1 0x100b09a0 -MxBool MxOmni::DoesEntityExist(MxDSAction& p_dsAction) -{ - if (m_streamer->FUN_100b9b30(p_dsAction)) { - MxNotificationPtrList* queue = m_notificationManager->GetQueue(); - - if (!queue || queue->size() == 0) - return TRUE; - } - return FALSE; -} - -// OFFSET: LEGO1 0x100b00e0 STUB -void MxOmni::Vtable0x2c() -{ - // TODO -} - -// OFFSET: LEGO1 0x100aefb0 -MxEntity* MxOmni::FindWorld(const char*, MxS32, MxPresenter*) -{ - return NULL; -} - -// OFFSET: LEGO1 0x100aefc0 -void MxOmni::NotifyCurrentEntity(MxNotificationParam* p_param) -{ -} - -// OFFSET: LEGO1 0x100b09d0 -void MxOmni::StartTimer() -{ - if (m_timerRunning == FALSE && m_timer != NULL && m_soundManager != NULL) { - m_timer->Start(); - m_soundManager->vtable0x34(); - m_timerRunning = TRUE; - } -} - -// OFFSET: LEGO1 0x100b0a00 -void MxOmni::StopTimer() -{ - if (m_timerRunning != FALSE && m_timer != NULL && m_soundManager != NULL) { - m_timer->Stop(); - m_soundManager->vtable0x38(); - m_timerRunning = FALSE; - } -} - -// OFFSET: LEGO1 0x10058a90 -MxBool MxOmni::IsTimerRunning() -{ - return m_timerRunning; -} - -// OFFSET: LEGO1 0x100b0690 -void MxOmni::DestroyInstance() -{ - if (g_instance != NULL) { - delete g_instance; - g_instance = NULL; - } -} - -// OFFSET: LEGO1 0x100b0900 -const char* MxOmni::GetHD() -{ - return g_hdPath; -} - -// OFFSET: LEGO1 0x100b0940 -const char* MxOmni::GetCD() -{ - return g_cdPath; -} - -// OFFSET: LEGO1 0x100b0980 -MxBool MxOmni::IsSound3D() -{ - return g_use3dSound; -} - -// OFFSET: LEGO1 0x100b0910 -void MxOmni::SetHD(const char* p_hd) -{ - strcpy(g_hdPath, p_hd); -} - -// OFFSET: LEGO1 0x100b0950 -void MxOmni::SetCD(const char* p_cd) -{ - strcpy(g_cdPath, p_cd); -} - -// OFFSET: LEGO1 0x100b0990 -void MxOmni::SetSound3D(MxBool p_3dsound) -{ - g_use3dSound = p_3dsound; -} - -// OFFSET: LEGO1 0x100b0680 -MxOmni* MxOmni::GetInstance() -{ - return g_instance; -} - // OFFSET: LEGO1 0x100af0b0 void MxOmni::SetInstance(MxOmni* instance) { @@ -320,6 +299,45 @@ void MxOmni::Destroy() Init(); } +// OFFSET: LEGO1 0x100b0090 +MxResult MxOmni::Start(MxDSAction* p_dsAction) +{ + MxResult result = FAILURE; + if (p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) { + result = m_streamer->FUN_100b99b0(p_dsAction); + } + + return result; +} + +// OFFSET: LEGO1 0x100b00c0 STUB +MxResult MxOmni::DeleteObject(MxDSAction& p_dsAction) +{ + // TODO + return FAILURE; +} + +// OFFSET: LEGO1 0x100b00e0 STUB +void MxOmni::Vtable0x2c() +{ + // TODO +} + +// OFFSET: LEGO1 0x100b0680 +MxOmni* MxOmni::GetInstance() +{ + return g_instance; +} + +// OFFSET: LEGO1 0x100b0690 +void MxOmni::DestroyInstance() +{ + if (g_instance != NULL) { + delete g_instance; + g_instance = NULL; + } +} + // OFFSET: LEGO1 0x100b07f0 MxLong MxOmni::Notify(MxParam& p) { @@ -338,88 +356,70 @@ MxResult MxOmni::HandleNotificationType2(MxParam& p_param) return FAILURE; } -// OFFSET: LEGO1 0x100acea0 -MxObjectFactory* ObjectFactory() +// OFFSET: LEGO1 0x100b0900 +const char* MxOmni::GetHD() { - return MxOmni::GetInstance()->GetObjectFactory(); + return g_hdPath; } -// OFFSET: LEGO1 0x100aceb0 -MxNotificationManager* NotificationManager() +// OFFSET: LEGO1 0x100b0910 +void MxOmni::SetHD(const char* p_hd) { - return MxOmni::GetInstance()->GetNotificationManager(); + strcpy(g_hdPath, p_hd); } -// OFFSET: LEGO1 0x100acec0 -MxTickleManager* TickleManager() +// OFFSET: LEGO1 0x100b0940 +const char* MxOmni::GetCD() { - return MxOmni::GetInstance()->GetTickleManager(); + return g_cdPath; } -// OFFSET: LEGO1 0x100aced0 -MxTimer* Timer() +// OFFSET: LEGO1 0x100b0950 +void MxOmni::SetCD(const char* p_cd) { - return MxOmni::GetInstance()->GetTimer(); + strcpy(g_cdPath, p_cd); } -// OFFSET: LEGO1 0x100acee0 -MxAtomIdCounterSet* AtomIdCounterSet() +// OFFSET: LEGO1 0x100b0980 +MxBool MxOmni::IsSound3D() { - return MxOmni::GetInstance()->GetAtomIdCounterSet(); + return g_use3dSound; } -// OFFSET: LEGO1 0x100acef0 -MxStreamer* Streamer() +// OFFSET: LEGO1 0x100b0990 +void MxOmni::SetSound3D(MxBool p_3dsound) { - return MxOmni::GetInstance()->GetStreamer(); + g_use3dSound = p_3dsound; } -// OFFSET: LEGO1 0x100acf00 -MxSoundManager* MSoundManager() +// OFFSET: LEGO1 0x100b09a0 +MxBool MxOmni::DoesEntityExist(MxDSAction& p_dsAction) { - return MxOmni::GetInstance()->GetSoundManager(); + if (m_streamer->FUN_100b9b30(p_dsAction)) { + MxNotificationPtrList* queue = m_notificationManager->GetQueue(); + + if (!queue || queue->size() == 0) + return TRUE; + } + return FALSE; } -// OFFSET: LEGO1 0x100acf10 -MxVideoManager* MVideoManager() +// OFFSET: LEGO1 0x100b09d0 +void MxOmni::StartTimer() { - return MxOmni::GetInstance()->GetVideoManager(); -} - -// OFFSET: LEGO1 0x100acf20 -MxVariableTable* VariableTable() -{ - return MxOmni::GetInstance()->GetVariableTable(); -} - -// OFFSET: LEGO1 0x100acf30 -MxMusicManager* MusicManager() -{ - return MxOmni::GetInstance()->GetMusicManager(); -} - -// OFFSET: LEGO1 0x100acf40 -MxEventManager* EventManager() -{ - return MxOmni::GetInstance()->GetEventManager(); -} - -// OFFSET: LEGO1 0x100acf70 -MxResult DeleteObject(MxDSAction& p_dsAction) -{ - return MxOmni::GetInstance()->DeleteObject(p_dsAction); -} - -// OFFSET: LEGO1 0x100159e0 -void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last) -{ - MxDSAction action; - - action.SetAtomId(*p_id); - action.SetUnknown24(-2); - - for (MxS32 l_first = p_first, l_last = p_last; l_first <= l_last; l_first++) { - action.SetObjectId(l_first); - DeleteObject(action); + if (m_timerRunning == FALSE && m_timer != NULL && m_soundManager != NULL) { + m_timer->Start(); + m_soundManager->vtable0x34(); + m_timerRunning = TRUE; + } +} + +// OFFSET: LEGO1 0x100b0a00 +void MxOmni::StopTimer() +{ + if (m_timerRunning != FALSE && m_timer != NULL && m_soundManager != NULL) { + m_timer->Stop(); + m_soundManager->vtable0x38(); + m_timerRunning = FALSE; } } diff --git a/LEGO1/mxpalette.cpp b/LEGO1/mxpalette.cpp index 24b5f181..2634bb59 100644 --- a/LEGO1/mxpalette.cpp +++ b/LEGO1/mxpalette.cpp @@ -80,7 +80,7 @@ MxPalette::MxPalette() this->m_skyColor = this->m_entries[141]; } -// OFFSET: LEGO1 0x100BEED0 +// OFFSET: LEGO1 0x100beed0 MxPalette::MxPalette(const RGBQUAD* p_colors) { this->m_overrideSkyColor = FALSE; @@ -97,7 +97,7 @@ MxPalette::MxPalette(const RGBQUAD* p_colors) this->m_skyColor = this->m_entries[141]; } -// OFFSET: LEGO1 100bef90 +// OFFSET: LEGO1 0x100bef90 MxPalette::~MxPalette() { if (m_palette) { @@ -105,21 +105,30 @@ MxPalette::~MxPalette() } } -// OFFSET: LEGO1 0x100bf390 -void MxPalette::ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries) +// OFFSET: LEGO1 0x100bf000 +LPDIRECTDRAWPALETTE MxPalette::CreateNativePalette() { - HDC hdc; + MxS32 i; + if (this->m_palette == NULL) { + for (i = 0; i < 10; i++) + this->m_entries[i].peFlags = 0x80; + for (i = 10; i < 136; i++) + this->m_entries[i].peFlags = 0x44; + for (i = 136; i < 140; i++) + this->m_entries[i].peFlags = 0x84; + this->m_entries[140].peFlags = 0x84; + this->m_entries[141].peFlags = 0x44; + for (i = 142; i < 246; i++) + this->m_entries[i].peFlags = 0x84; + for (i = 246; i < 256; i++) + this->m_entries[i].peFlags = 0x80; - hdc = GetDC(0); - if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) { - GetSystemPaletteEntries(hdc, 0, 10, p_entries); - GetSystemPaletteEntries(hdc, 246, 10, &p_entries[246]); + if (MVideoManager() && MVideoManager()->GetDirectDraw()) { + MVideoManager()->GetDirectDraw()->CreatePalette(4, this->m_entries, &this->m_palette, NULL); + } } - else { - memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 10); - memcpy(&p_entries[246], &g_defaultPaletteEntries[246], sizeof(PALETTEENTRY) * 10); - } - ReleaseDC(0, hdc); + + return this->m_palette; } // OFFSET: LEGO1 0x100bf0b0 @@ -131,23 +140,6 @@ MxPalette* MxPalette::Clone() return result; } -// OFFSET: LEGO1 0x100bf420 -void MxPalette::GetDefaultPalette(LPPALETTEENTRY p_entries) -{ - HDC hdc; - - hdc = GetDC(0); - if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) { - GetSystemPaletteEntries(hdc, 0, 256, p_entries); - memcpy(&p_entries[10], &g_defaultPaletteEntries[10], sizeof(PALETTEENTRY) * 236); - } - else { - memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 256); - } - - ReleaseDC(0, hdc); -} - // OFFSET: LEGO1 0x100bf150 MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries) { @@ -155,26 +147,6 @@ MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries) return SUCCESS; } -// OFFSET: LEGO1 0x100bf340 -MxBool MxPalette::operator==(MxPalette& other) -{ - for (MxS32 i = 0; i < 256; i++) { - if (this->m_entries[i].peRed != other.m_entries[i].peRed) - return FALSE; - if (this->m_entries[i].peGreen != other.m_entries[i].peGreen) - return FALSE; - if (this->m_entries[i].peBlue != other.m_entries[i].peBlue) - return FALSE; - } - return TRUE; -} - -// OFFSET: LEGO1 0x100bf330 -void MxPalette::Detach() -{ - this->m_palette = NULL; -} - // OFFSET: LEGO1 0x100bf170 MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) { @@ -240,7 +212,61 @@ MxResult MxPalette::SetSkyColor(LPPALETTEENTRY p_sky_color) return status; } -// OFFSET: LEGO1 0x100BF490 +// OFFSET: LEGO1 0x100bf330 +void MxPalette::Detach() +{ + this->m_palette = NULL; +} + +// OFFSET: LEGO1 0x100bf340 +MxBool MxPalette::operator==(MxPalette& other) +{ + for (MxS32 i = 0; i < 256; i++) { + if (this->m_entries[i].peRed != other.m_entries[i].peRed) + return FALSE; + if (this->m_entries[i].peGreen != other.m_entries[i].peGreen) + return FALSE; + if (this->m_entries[i].peBlue != other.m_entries[i].peBlue) + return FALSE; + } + return TRUE; +} + +// OFFSET: LEGO1 0x100bf390 +void MxPalette::ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries) +{ + HDC hdc; + + hdc = GetDC(0); + if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) { + GetSystemPaletteEntries(hdc, 0, 10, p_entries); + GetSystemPaletteEntries(hdc, 246, 10, &p_entries[246]); + } + else { + memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 10); + memcpy(&p_entries[246], &g_defaultPaletteEntries[246], sizeof(PALETTEENTRY) * 10); + } + ReleaseDC(0, hdc); +} + +// OFFSET: LEGO1 0x100bf420 +void MxPalette::GetDefaultPalette(LPPALETTEENTRY p_entries) +{ + HDC hdc; + + hdc = GetDC(0); + if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) { + GetSystemPaletteEntries(hdc, 0, 256, p_entries); + memcpy(&p_entries[10], &g_defaultPaletteEntries[10], sizeof(PALETTEENTRY) * 236); + } + else { + memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 256); + } + + ReleaseDC(0, hdc); +} + +// OFFSET: LEGO1 0x100bf490 void MxPalette::Reset(MxBool p_ignoreSkyColor) { if (this->m_palette != NULL) { @@ -252,29 +278,3 @@ void MxPalette::Reset(MxBool p_ignoreSkyColor) this->m_palette->SetEntries(0, 0, 256, this->m_entries); } } - -// OFFSET: LEGO1 0x100BF000 -LPDIRECTDRAWPALETTE MxPalette::CreateNativePalette() -{ - MxS32 i; - if (this->m_palette == NULL) { - for (i = 0; i < 10; i++) - this->m_entries[i].peFlags = 0x80; - for (i = 10; i < 136; i++) - this->m_entries[i].peFlags = 0x44; - for (i = 136; i < 140; i++) - this->m_entries[i].peFlags = 0x84; - this->m_entries[140].peFlags = 0x84; - this->m_entries[141].peFlags = 0x44; - for (i = 142; i < 246; i++) - this->m_entries[i].peFlags = 0x84; - for (i = 246; i < 256; i++) - this->m_entries[i].peFlags = 0x80; - - if (MVideoManager() && MVideoManager()->GetDirectDraw()) { - MVideoManager()->GetDirectDraw()->CreatePalette(4, this->m_entries, &this->m_palette, NULL); - } - } - - return this->m_palette; -} diff --git a/LEGO1/mxpresenter.cpp b/LEGO1/mxpresenter.cpp index 85579b64..3394402b 100644 --- a/LEGO1/mxpresenter.cpp +++ b/LEGO1/mxpresenter.cpp @@ -16,6 +16,97 @@ DECOMP_SIZE_ASSERT(MxPresenter, 0x40); +// OFFSET: LEGO1 0x1000be30 +void MxPresenter::VTable0x14() +{ +} + +// OFFSET: LEGO1 0x1000be40 +void MxPresenter::ReadyTickle() +{ + ParseExtra(); + + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Starting; +} + +// OFFSET: LEGO1 0x1000be60 +void MxPresenter::StartingTickle() +{ + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Streaming; +} + +// OFFSET: LEGO1 0x1000be80 +void MxPresenter::StreamingTickle() +{ + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Repeating; +} + +// OFFSET: LEGO1 0x1000bea0 +void MxPresenter::RepeatingTickle() +{ + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_unk5; +} + +// OFFSET: LEGO1 0x1000bec0 +void MxPresenter::Unk5Tickle() +{ + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Done; +} + +// OFFSET: LEGO1 0x1000bee0 +void MxPresenter::DoneTickle() +{ + m_previousTickleStates |= 1 << m_currentTickleState; + m_currentTickleState = TickleState_Idle; +} + +// OFFSET: LEGO1 0x1000bf00 +MxPresenter::~MxPresenter() +{ +} + +// OFFSET: LEGO1 0x1000bf70 +MxResult MxPresenter::AddToManager() +{ + return SUCCESS; +} + +// OFFSET: LEGO1 0x1000bf80 +void MxPresenter::Destroy() +{ + Init(); +} + +// OFFSET: LEGO1 0x1000bf90 +void MxPresenter::SetTickleState(TickleState p_tickleState) +{ + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = p_tickleState; +} + +// OFFSET: LEGO1 0x1000bfb0 +MxBool MxPresenter::HasTickleStatePassed(TickleState p_tickleState) +{ + return m_previousTickleStates & (1 << (unsigned char) p_tickleState); +} + +// OFFSET: LEGO1 0x1000bfc0 +undefined4 MxPresenter::PutData() +{ + return 0; +} + +// OFFSET: LEGO1 0x1000bfd0 +MxBool MxPresenter::IsHit(MxS32 p_x, MxS32 p_y) +{ + return FALSE; +} + // OFFSET: LEGO1 0x100b4d50 void MxPresenter::Init() { @@ -27,6 +118,44 @@ void MxPresenter::Init() m_previousTickleStates = 0; } +// OFFSET: LEGO1 0x100b4d80 +MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action) +{ + MxAutoLocker lock(&this->m_criticalSection); + + this->m_action = p_action; + + const Vector3Data& location = this->m_action->GetLocation(); + MxS32 previousTickleState = this->m_currentTickleState; + + 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; + + return SUCCESS; +} + +// OFFSET: LEGO1 0x100b4e40 +void MxPresenter::EndAction() +{ + if (this->m_action == FALSE) + return; + + MxAutoLocker lock(&this->m_criticalSection); + + if (!this->m_compositePresenter) { + MxOmni::GetInstance()->NotifyCurrentEntity( + &MxEndActionNotificationParam(c_notificationEndAction, NULL, this->m_action, TRUE) + ); + } + + this->m_action = FALSE; + MxS32 previousTickleState = 1 << m_currentTickleState; + this->m_previousTickleStates |= previousTickleState; + this->m_currentTickleState = TickleState_Idle; +} + // OFFSET: LEGO1 0x100b4fc0 void MxPresenter::ParseExtra() { @@ -71,11 +200,6 @@ void MxPresenter::SendToCompositePresenter(MxOmni* p_omni) } } -// OFFSET: LEGO1 0x1000bf00 -MxPresenter::~MxPresenter() -{ -} - // OFFSET: LEGO1 0x100b5200 MxResult MxPresenter::Tickle() { @@ -116,44 +240,6 @@ MxResult MxPresenter::Tickle() return SUCCESS; } -// OFFSET: LEGO1 0x100b4d80 -MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action) -{ - MxAutoLocker lock(&this->m_criticalSection); - - this->m_action = p_action; - - const Vector3Data& location = this->m_action->GetLocation(); - MxS32 previousTickleState = this->m_currentTickleState; - - 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; - - return SUCCESS; -} - -// OFFSET: LEGO1 0x100b4e40 -void MxPresenter::EndAction() -{ - if (this->m_action == FALSE) - return; - - MxAutoLocker lock(&this->m_criticalSection); - - if (!this->m_compositePresenter) { - MxOmni::GetInstance()->NotifyCurrentEntity( - &MxEndActionNotificationParam(c_notificationEndAction, NULL, this->m_action, TRUE) - ); - } - - this->m_action = FALSE; - MxS32 previousTickleState = 1 << m_currentTickleState; - this->m_previousTickleStates |= previousTickleState; - this->m_currentTickleState = TickleState_Idle; -} - // OFFSET: LEGO1 0x100b52d0 void MxPresenter::Enable(MxBool p_enable) { @@ -223,89 +309,3 @@ MxBool MxPresenter::IsEnabled() { return this->m_action && this->m_action->GetFlags() & MxDSAction::Flag_Enabled; } - -// OFFSET: LEGO1 0x1000be30 -void MxPresenter::VTable0x14() -{ -} - -// OFFSET: LEGO1 0x1000be40 -void MxPresenter::ReadyTickle() -{ - ParseExtra(); - - m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; - m_currentTickleState = TickleState_Starting; -} - -// OFFSET: LEGO1 0x1000be60 -void MxPresenter::StartingTickle() -{ - m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; - m_currentTickleState = TickleState_Streaming; -} - -// OFFSET: LEGO1 0x1000be80 -void MxPresenter::StreamingTickle() -{ - m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; - m_currentTickleState = TickleState_Repeating; -} - -// OFFSET: LEGO1 0x1000bea0 -void MxPresenter::RepeatingTickle() -{ - m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; - m_currentTickleState = TickleState_unk5; -} - -// OFFSET: LEGO1 0x1000bec0 -void MxPresenter::Unk5Tickle() -{ - m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; - m_currentTickleState = TickleState_Done; -} - -// OFFSET: LEGO1 0x1000bee0 -void MxPresenter::DoneTickle() -{ - m_previousTickleStates |= 1 << m_currentTickleState; - m_currentTickleState = TickleState_Idle; -} - -// OFFSET: LEGO1 0x1000bf70 -MxResult MxPresenter::AddToManager() -{ - return SUCCESS; -} - -// OFFSET: LEGO1 0x1000bf80 -void MxPresenter::Destroy() -{ - Init(); -} - -// OFFSET: LEGO1 0x1000bf90 -void MxPresenter::SetTickleState(TickleState p_tickleState) -{ - m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; - m_currentTickleState = p_tickleState; -} - -// OFFSET: LEGO1 0x1000bfb0 -MxBool MxPresenter::HasTickleStatePassed(TickleState p_tickleState) -{ - return m_previousTickleStates & (1 << (unsigned char) p_tickleState); -} - -// OFFSET: LEGO1 0x1000bfc0 -undefined4 MxPresenter::PutData() -{ - return 0; -} - -// OFFSET: LEGO1 0x1000bfd0 -MxBool MxPresenter::IsHit(MxS32 p_x, MxS32 p_y) -{ - return FALSE; -} diff --git a/LEGO1/mxramstreamcontroller.cpp b/LEGO1/mxramstreamcontroller.cpp index 2e8efc36..4689518f 100644 --- a/LEGO1/mxramstreamcontroller.cpp +++ b/LEGO1/mxramstreamcontroller.cpp @@ -5,11 +5,7 @@ DECOMP_SIZE_ASSERT(MxRAMStreamController, 0x98); -// OFFSET: LEGO1 0x100d0d80 STUB -undefined* __cdecl FUN_100d0d80(MxU32* p_fileSizeBuffer, MxU32 p_fileSize) -{ - return NULL; -} +undefined* __cdecl FUN_100d0d80(MxU32* p_fileSizeBuffer, MxU32 p_fileSize); // OFFSET: LEGO1 0x100c6110 MxResult MxRAMStreamController::Open(const char* p_filename) @@ -52,3 +48,9 @@ MxResult MxRAMStreamController::vtable0x24(undefined4 p_unknown) // TODO STUB return FAILURE; } + +// OFFSET: LEGO1 0x100d0d80 STUB +undefined* __cdecl FUN_100d0d80(MxU32* p_fileSizeBuffer, MxU32 p_fileSize) +{ + return NULL; +} diff --git a/LEGO1/mxramstreamprovider.cpp b/LEGO1/mxramstreamprovider.cpp index 795523c8..47a9dc4c 100644 --- a/LEGO1/mxramstreamprovider.cpp +++ b/LEGO1/mxramstreamprovider.cpp @@ -14,27 +14,6 @@ MxRAMStreamProvider::MxRAMStreamProvider() m_bufferForDWords = NULL; } -// OFFSET: LEGO1 0x100d0a50 -MxRAMStreamProvider::~MxRAMStreamProvider() -{ - m_bufferSize = 0; - m_fileSize = 0; - - free(m_pBufferOfFileSize); - m_pBufferOfFileSize = NULL; - - m_lengthInDWords = 0; - - free(m_bufferForDWords); - m_bufferForDWords = NULL; -} - -// OFFSET: LEGO1 0x100d0ae0 STUB -MxResult MxRAMStreamProvider::SetResourceToGet(MxStreamController* p_resource) -{ - return FAILURE; -} - // OFFSET: LEGO1 0x100d0930 MxU32 MxRAMStreamProvider::GetFileSize() { @@ -58,3 +37,24 @@ MxU32* MxRAMStreamProvider::GetBufferForDWords() { return m_bufferForDWords; } + +// OFFSET: LEGO1 0x100d0a50 +MxRAMStreamProvider::~MxRAMStreamProvider() +{ + m_bufferSize = 0; + m_fileSize = 0; + + free(m_pBufferOfFileSize); + m_pBufferOfFileSize = NULL; + + m_lengthInDWords = 0; + + free(m_bufferForDWords); + m_bufferForDWords = NULL; +} + +// OFFSET: LEGO1 0x100d0ae0 STUB +MxResult MxRAMStreamProvider::SetResourceToGet(MxStreamController* p_resource) +{ + return FAILURE; +} diff --git a/LEGO1/mxregionlist.cpp b/LEGO1/mxregionlist.cpp index 74e5739a..b9231d35 100644 --- a/LEGO1/mxregionlist.cpp +++ b/LEGO1/mxregionlist.cpp @@ -2,6 +2,12 @@ #include "mxregion.h" +// OFFSET: LEGO1 0x100c32e0 TEMPLATE +// MxCollection::Compare + +// OFFSET: LEGO1 0x100c3340 TEMPLATE +// MxCollection::Destroy + // OFFSET: LEGO1 0x100c33e0 void MxRegionList::Destroy(MxRegionTopBottom* p_topBottom) { @@ -12,18 +18,6 @@ void MxRegionList::Destroy(MxRegionTopBottom* p_topBottom) } } -// OFFSET: LEGO1 0x100c4e80 -void MxRegionLeftRightList::Destroy(MxRegionLeftRight* p_leftRight) -{ - delete p_leftRight; -} - -// OFFSET: LEGO1 0x100c32e0 TEMPLATE -// MxCollection::Compare - -// OFFSET: LEGO1 0x100c3340 TEMPLATE -// MxCollection::Destroy - // OFFSET: LEGO1 0x100c34d0 TEMPLATE // MxCollection::`scalar deleting destructor' @@ -39,6 +33,12 @@ void MxRegionLeftRightList::Destroy(MxRegionLeftRight* p_leftRight) // OFFSET: LEGO1 0x100c4de0 TEMPLATE // MxCollection::Destroy +// OFFSET: LEGO1 0x100c4e80 +void MxRegionLeftRightList::Destroy(MxRegionLeftRight* p_leftRight) +{ + delete p_leftRight; +} + // OFFSET: LEGO1 0x100c4f50 TEMPLATE // MxCollection::`scalar deleting destructor' diff --git a/LEGO1/mxsmkpresenter.cpp b/LEGO1/mxsmkpresenter.cpp index c4c2224e..66d63f7a 100644 --- a/LEGO1/mxsmkpresenter.cpp +++ b/LEGO1/mxsmkpresenter.cpp @@ -41,6 +41,11 @@ void MxSmkPresenter::Destroy(MxBool p_fromDestructor) } } +// OFFSET: LEGO1 0x100b3940 STUB +void MxSmkPresenter::VTable0x5c(undefined4 p_unknown1) +{ +} + // OFFSET: LEGO1 0x100b3960 void MxSmkPresenter::VTable0x60() { @@ -52,45 +57,11 @@ void MxSmkPresenter::VTable0x60() m_bitmap->SetSize(m_mxSmack.m_smack.m_width, m_mxSmack.m_smack.m_height, NULL, FALSE); } -// OFFSET: LEGO1 0x100c5d40 -void MxSmkPresenter::FUN_100c5d40(MxSmack* p_mxSmack) -{ - if (p_mxSmack->m_unk0x6a0) - delete p_mxSmack->m_unk0x6a0; - if (p_mxSmack->m_unk0x6a4) - delete p_mxSmack->m_unk0x6a4; - if (p_mxSmack->m_unk0x6a8) - delete p_mxSmack->m_unk0x6a8; - if (p_mxSmack->m_unk0x6ac) - delete p_mxSmack->m_unk0x6ac; - if (p_mxSmack->m_unk0x6b4) - delete p_mxSmack->m_unk0x6b4; -} - -// OFFSET: LEGO1 0x100b4300 -void MxSmkPresenter::Destroy() -{ - Destroy(FALSE); -} - -// OFFSET: LEGO1 0x100b3940 STUB -void MxSmkPresenter::VTable0x5c(undefined4 p_unknown1) -{ -} - // OFFSET: LEGO1 0x100b3a00 STUB void MxSmkPresenter::VTable0x68(undefined4 p_unknown1) { } -// OFFSET: LEGO1 0x100b42c0 -void MxSmkPresenter::VTable0x70() -{ - MxPalette* palette = m_bitmap->CreatePalette(); - MVideoManager()->RealizePalette(palette); - delete palette; -} - // OFFSET: LEGO1 0x100b4260 MxU32 MxSmkPresenter::VTable0x88() { @@ -111,3 +82,32 @@ MxU32 MxSmkPresenter::VTable0x88() return result; } } + +// OFFSET: LEGO1 0x100b42c0 +void MxSmkPresenter::VTable0x70() +{ + MxPalette* palette = m_bitmap->CreatePalette(); + MVideoManager()->RealizePalette(palette); + delete palette; +} + +// OFFSET: LEGO1 0x100b4300 +void MxSmkPresenter::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100c5d40 +void MxSmkPresenter::FUN_100c5d40(MxSmack* p_mxSmack) +{ + if (p_mxSmack->m_unk0x6a0) + delete p_mxSmack->m_unk0x6a0; + if (p_mxSmack->m_unk0x6a4) + delete p_mxSmack->m_unk0x6a4; + if (p_mxSmack->m_unk0x6a8) + delete p_mxSmack->m_unk0x6a8; + if (p_mxSmack->m_unk0x6ac) + delete p_mxSmack->m_unk0x6ac; + if (p_mxSmack->m_unk0x6b4) + delete p_mxSmack->m_unk0x6b4; +} diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp index 1fb3ae03..ea518d3e 100644 --- a/LEGO1/mxstreamcontroller.cpp +++ b/LEGO1/mxstreamcontroller.cpp @@ -6,6 +6,24 @@ DECOMP_SIZE_ASSERT(MxNextActionDataStart, 0x14) +// OFFSET: LEGO1 0x100b9400 +MxResult MxStreamController::vtable0x18(undefined4 p_unknown, undefined4 p_unknown2) +{ + return FAILURE; +} + +// OFFSET: LEGO1 0x100b9410 +MxResult MxStreamController::vtable0x1C(undefined4 p_unknown, undefined4 p_unknown2) +{ + return FAILURE; +} + +// OFFSET: LEGO1 0x100b9420 +MxResult MxStreamController::vtable0x28() +{ + return SUCCESS; +} + // OFFSET: LEGO1 0x100c0b90 STUB MxStreamController::MxStreamController() { @@ -18,13 +36,6 @@ MxStreamController::~MxStreamController() // TODO } -// OFFSET: LEGO1 0x100c20d0 STUB -MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj) -{ - // TODO - return TRUE; -} - // OFFSET: LEGO1 0x100c1520 MxResult MxStreamController::Open(const char* p_filename) { @@ -36,18 +47,6 @@ MxResult MxStreamController::Open(const char* p_filename) return SUCCESS; } -// OFFSET: LEGO1 0x100b9400 -MxResult MxStreamController::vtable0x18(undefined4 p_unknown, undefined4 p_unknown2) -{ - return FAILURE; -} - -// OFFSET: LEGO1 0x100b9410 -MxResult MxStreamController::vtable0x1C(undefined4 p_unknown, undefined4 p_unknown2) -{ - return FAILURE; -} - // OFFSET: LEGO1 0x100c1690 MxResult MxStreamController::vtable0x20(MxDSAction* p_action) { @@ -89,10 +88,10 @@ MxResult MxStreamController::FUN_100c1800(MxDSAction* p_action, MxU32 p_val) return FAILURE; } -// OFFSET: LEGO1 0x100b9420 -MxResult MxStreamController::vtable0x28() +// OFFSET: LEGO1 0x100c1a00 STUB +MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval) { - return SUCCESS; + return FAILURE; } // OFFSET: LEGO1 0x100c1c10 @@ -111,8 +110,9 @@ MxResult MxStreamController::vtable0x30(undefined4 p_unknown) return FAILURE; } -// OFFSET: LEGO1 0x100c1a00 STUB -MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval) +// OFFSET: LEGO1 0x100c20d0 STUB +MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj) { - return FAILURE; + // TODO + return TRUE; } diff --git a/LEGO1/mxthread.cpp b/LEGO1/mxthread.cpp index 7e445f7d..a54e037a 100644 --- a/LEGO1/mxthread.cpp +++ b/LEGO1/mxthread.cpp @@ -6,11 +6,34 @@ #include -// OFFSET: LEGO1 0x100bf690 -MxResult MxThread::Run() +// OFFSET: LEGO1 0x100b8bb0 +MxTickleThread::MxTickleThread(MxCore* p_target, int p_frequencyMS) { - m_semaphore.Release(1); - return SUCCESS; + m_target = p_target; + m_frequencyMS = p_frequencyMS; +} + +// Match except for register allocation +// OFFSET: LEGO1 0x100b8c90 +MxResult MxTickleThread::Run() +{ + MxTimer* timer = Timer(); + int lastTickled = -m_frequencyMS; + while (IsRunning()) { + int currentTime = timer->GetTime(); + + if (currentTime < lastTickled) { + lastTickled = -m_frequencyMS; + } + int timeRemainingMS = (m_frequencyMS - currentTime) + lastTickled; + if (timeRemainingMS <= 0) { + m_target->Tickle(); + timeRemainingMS = 0; + lastTickled = currentTime; + } + Sleep(timeRemainingMS); + } + return MxThread::Run(); } // OFFSET: LEGO1 0x100bf510 @@ -42,6 +65,12 @@ MxResult MxThread::Start(int p_stack, int p_flag) return result; } +// OFFSET: LEGO1 0x100bf660 +void MxThread::Sleep(MxS32 p_milliseconds) +{ + ::Sleep(p_milliseconds); +} + // OFFSET: LEGO1 0x100bf670 void MxThread::Terminate() { @@ -55,38 +84,9 @@ unsigned MxThread::ThreadProc(void* p_thread) return static_cast(p_thread)->Run(); } -// OFFSET: LEGO1 0x100bf660 -void MxThread::Sleep(MxS32 p_milliseconds) +// OFFSET: LEGO1 0x100bf690 +MxResult MxThread::Run() { - ::Sleep(p_milliseconds); -} - -// OFFSET: LEGO1 0x100b8bb0 -MxTickleThread::MxTickleThread(MxCore* p_target, int p_frequencyMS) -{ - m_target = p_target; - m_frequencyMS = p_frequencyMS; -} - -// Match except for register allocation -// OFFSET: LEGO1 0x100b8c90 -MxResult MxTickleThread::Run() -{ - MxTimer* timer = Timer(); - int lastTickled = -m_frequencyMS; - while (IsRunning()) { - int currentTime = timer->GetTime(); - - if (currentTime < lastTickled) { - lastTickled = -m_frequencyMS; - } - int timeRemainingMS = (m_frequencyMS - currentTime) + lastTickled; - if (timeRemainingMS <= 0) { - m_target->Tickle(); - timeRemainingMS = 0; - lastTickled = currentTime; - } - Sleep(timeRemainingMS); - } - return MxThread::Run(); + m_semaphore.Release(1); + return SUCCESS; } diff --git a/LEGO1/mxtimer.cpp b/LEGO1/mxtimer.cpp index c9822dda..79225bfd 100644 --- a/LEGO1/mxtimer.cpp +++ b/LEGO1/mxtimer.cpp @@ -17,6 +17,13 @@ MxTimer::MxTimer() s_LastTimeCalculated = m_startTime; } +// OFFSET: LEGO1 0x100ae140 +MxLong MxTimer::GetRealTime() +{ + MxTimer::s_LastTimeCalculated = timeGetTime(); + return MxTimer::s_LastTimeCalculated - this->m_startTime; +} + // OFFSET: LEGO1 0x100ae160 void MxTimer::Start() { @@ -33,10 +40,3 @@ void MxTimer::Stop() // this feels very stupid but it's what the assembly does this->m_startTime = this->m_startTime + startTime - 5; } - -// OFFSET: LEGO1 0x100ae140 -MxLong MxTimer::GetRealTime() -{ - MxTimer::s_LastTimeCalculated = timeGetTime(); - return MxTimer::s_LastTimeCalculated - this->m_startTime; -} diff --git a/LEGO1/mxtransitionmanager.cpp b/LEGO1/mxtransitionmanager.cpp index 0df51929..e96843a2 100644 --- a/LEGO1/mxtransitionmanager.cpp +++ b/LEGO1/mxtransitionmanager.cpp @@ -39,6 +39,14 @@ MxTransitionManager::~MxTransitionManager() TickleManager()->UnregisterClient(this); } +// OFFSET: LEGO1 0x1004baa0 +MxResult MxTransitionManager::GetDDrawSurfaceFromVideoManager() // vtable+0x14 +{ + LegoVideoManager* videoManager = VideoManager(); + this->m_ddSurface = videoManager->GetDisplaySurface()->GetDirectDrawSurface2(); + return SUCCESS; +} + // OFFSET: LEGO1 0x1004bac0 MxResult MxTransitionManager::Tickle() { @@ -71,6 +79,53 @@ MxResult MxTransitionManager::Tickle() return SUCCESS; } +// OFFSET: LEGO1 0x1004bb70 +MxResult MxTransitionManager::StartTransition( + TransitionType p_animationType, + MxS32 p_speed, + MxBool p_doCopy, + MxBool p_playMusicInAnim +) +{ + if (this->m_transitionType == NOT_TRANSITIONING) { + if (!p_playMusicInAnim) { + MxBackgroundAudioManager* backgroundAudioManager = BackgroundAudioManager(); + backgroundAudioManager->Stop(); + } + + this->m_transitionType = p_animationType; + + m_copyFlags.bit0 = p_doCopy; + + if (m_copyFlags.bit0 && m_waitIndicator != NULL) { + m_waitIndicator->Enable(TRUE); + + MxDSAction* action = m_waitIndicator->GetAction(); + action->SetLoopCount(10000); + action->SetFlags(action->GetFlags() | MxDSAction::Flag_Bit9); + } + + MxU32 time = timeGetTime(); + this->m_systemTime = time; + + this->m_animationSpeed = p_speed; + + MxTickleManager* tickleManager = TickleManager(); + tickleManager->RegisterClient(this, p_speed); + + LegoInputManager* inputManager = InputManager(); + inputManager->m_unk0x88 = TRUE; + inputManager->m_unk0x336 = FALSE; + + LegoVideoManager* videoManager = VideoManager(); + videoManager->SetUnkE4(FALSE); + + SetAppCursor(1); + return SUCCESS; + } + return FAILURE; +} + // OFFSET: LEGO1 0x1004bc30 void MxTransitionManager::EndTransition(MxBool p_notifyWorld) { @@ -91,6 +146,14 @@ void MxTransitionManager::EndTransition(MxBool p_notifyWorld) } } +// OFFSET: LEGO1 0x1004bcf0 +void MxTransitionManager::Transition_None() +{ + LegoVideoManager* videoManager = VideoManager(); + videoManager->GetDisplaySurface()->FUN_100ba640(); + EndTransition(TRUE); +} + // OFFSET: LEGO1 0x1004bd10 void MxTransitionManager::Transition_Dissolve() { @@ -173,69 +236,6 @@ void MxTransitionManager::Transition_Dissolve() } } -// OFFSET: LEGO1 0x1004baa0 -MxResult MxTransitionManager::GetDDrawSurfaceFromVideoManager() // vtable+0x14 -{ - LegoVideoManager* videoManager = VideoManager(); - this->m_ddSurface = videoManager->GetDisplaySurface()->GetDirectDrawSurface2(); - return SUCCESS; -} - -// OFFSET: LEGO1 0x1004bb70 -MxResult MxTransitionManager::StartTransition( - TransitionType p_animationType, - MxS32 p_speed, - MxBool p_doCopy, - MxBool p_playMusicInAnim -) -{ - if (this->m_transitionType == NOT_TRANSITIONING) { - if (!p_playMusicInAnim) { - MxBackgroundAudioManager* backgroundAudioManager = BackgroundAudioManager(); - backgroundAudioManager->Stop(); - } - - this->m_transitionType = p_animationType; - - m_copyFlags.bit0 = p_doCopy; - - if (m_copyFlags.bit0 && m_waitIndicator != NULL) { - m_waitIndicator->Enable(TRUE); - - MxDSAction* action = m_waitIndicator->GetAction(); - action->SetLoopCount(10000); - action->SetFlags(action->GetFlags() | MxDSAction::Flag_Bit9); - } - - MxU32 time = timeGetTime(); - this->m_systemTime = time; - - this->m_animationSpeed = p_speed; - - MxTickleManager* tickleManager = TickleManager(); - tickleManager->RegisterClient(this, p_speed); - - LegoInputManager* inputManager = InputManager(); - inputManager->m_unk0x88 = TRUE; - inputManager->m_unk0x336 = FALSE; - - LegoVideoManager* videoManager = VideoManager(); - videoManager->SetUnkE4(FALSE); - - SetAppCursor(1); - return SUCCESS; - } - return FAILURE; -} - -// OFFSET: LEGO1 0x1004bcf0 -void MxTransitionManager::Transition_None() -{ - LegoVideoManager* videoManager = VideoManager(); - videoManager->GetDisplaySurface()->FUN_100ba640(); - EndTransition(TRUE); -} - // OFFSET: LEGO1 0x1004bed0 void MxTransitionManager::Transition_Pixelation() { @@ -353,6 +353,45 @@ void MxTransitionManager::Transition_Pixelation() } } +// OFFSET: LEGO1 0x1004c170 +void MxTransitionManager::Transition_Wipe() +{ + // If the animation is finished + 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); + + // For each of the 240 animation ticks, blank out two scanlines + // starting at the top of the screen. + // (dwRGBBitCount / 8) will tell how many bytes are used per pixel. + MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer; + memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); + + line += ddsd.lPitch; + memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + m_animationTimer++; + } +} + // OFFSET: LEGO1 0x1004c270 void MxTransitionManager::Transition_Windows() { @@ -424,45 +463,6 @@ void MxTransitionManager::Transition_Broken() } } -// OFFSET: LEGO1 0x1004c170 -void MxTransitionManager::Transition_Wipe() -{ - // If the animation is finished - 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); - - // For each of the 240 animation ticks, blank out two scanlines - // starting at the top of the screen. - // (dwRGBBitCount / 8) will tell how many bytes are used per pixel. - MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer; - memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); - - line += ddsd.lPitch; - memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); - - SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); - - m_animationTimer++; - } -} - // OFFSET: LEGO1 0x1004c470 void MxTransitionManager::SetWaitIndicator(MxVideoPresenter* p_waitIndicator) { diff --git a/LEGO1/mxvariabletable.cpp b/LEGO1/mxvariabletable.cpp index 0faa2b7b..cd7fc9ed 100644 --- a/LEGO1/mxvariabletable.cpp +++ b/LEGO1/mxvariabletable.cpp @@ -1,5 +1,29 @@ #include "mxvariabletable.h" +// OFFSET: LEGO1 0x100afcd0 TEMPLATE +// MxCollection::Compare + +// OFFSET: LEGO1 0x100afce0 TEMPLATE +// MxCollection::~MxCollection + +// OFFSET: LEGO1 0x100afd30 TEMPLATE +// MxCollection::Destroy + +// OFFSET: LEGO1 0x100afd40 TEMPLATE +// MxCollection::`scalar deleting destructor' + +// OFFSET: LEGO1 0x100afdb0 TEMPLATE +// MxVariableTable::Destroy + +// OFFSET: LEGO1 0x100afdc0 TEMPLATE +// MxHashTable::Hash + +// OFFSET: LEGO1 0x100b0bd0 TEMPLATE +// MxHashTable::~MxHashTable + +// OFFSET: LEGO1 0x100b0ca0 TEMPLATE +// MxHashTable::`scalar deleting destructor' + // OFFSET: LEGO1 0x100b7330 MxS8 MxVariableTable::Compare(MxVariable* p_var0, MxVariable* p_var1) { @@ -64,3 +88,9 @@ const char* MxVariableTable::GetVariable(const char* p_key) return value; } + +// OFFSET: LEGO1 0x100b7ab0 TEMPLATE +// MxHashTable::Resize + +// OFFSET: LEGO1 0x100b7b80 TEMPLATE +// MxHashTable::_NodeInsert diff --git a/LEGO1/mxvariabletable.h b/LEGO1/mxvariabletable.h index 1df02204..5d36fc71 100644 --- a/LEGO1/mxvariabletable.h +++ b/LEGO1/mxvariabletable.h @@ -14,40 +14,12 @@ class MxVariableTable : public MxHashTable { __declspec(dllexport) void SetVariable(MxVariable* p_var); __declspec(dllexport) const char* GetVariable(const char* p_key); - // OFFSET: LEGO1 0x100afdb0 static void Destroy(MxVariable* p_obj) { p_obj->Destroy(); } virtual MxS8 Compare(MxVariable*, MxVariable*) override; // vtable+0x14 virtual MxU32 Hash(MxVariable*) override; // vtable+0x18 }; -// OFFSET: LEGO1 0x100afcd0 TEMPLATE -// MxCollection::Compare - -// OFFSET: LEGO1 0x100afce0 TEMPLATE -// MxCollection::~MxCollection - -// OFFSET: LEGO1 0x100afd30 TEMPLATE -// MxCollection::Destroy - -// OFFSET: LEGO1 0x100afd40 TEMPLATE -// MxCollection::`scalar deleting destructor' - -// OFFSET: LEGO1 0x100afdc0 TEMPLATE -// MxHashTable::Hash - -// OFFSET: LEGO1 0x100b0bd0 TEMPLATE -// MxHashTable::~MxHashTable - -// OFFSET: LEGO1 0x100b0ca0 TEMPLATE -// MxHashTable::`scalar deleting destructor' - -// OFFSET: LEGO1 0x100b7ab0 TEMPLATE -// MxHashTable::Resize - -// OFFSET: LEGO1 0x100b7b80 TEMPLATE -// MxHashTable::_NodeInsert - // VTABLE 0x100dc1b0 TEMPLATE // class MxCollection diff --git a/LEGO1/mxvideoparam.cpp b/LEGO1/mxvideoparam.cpp index d631e5be..40e25c79 100644 --- a/LEGO1/mxvideoparam.cpp +++ b/LEGO1/mxvideoparam.cpp @@ -44,17 +44,11 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) SetDeviceName(p_videoParam.m_deviceId); } -// OFFSET: LEGO1 0x100bede0 -MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) +// OFFSET: LEGO1 0x100bed50 +MxVideoParam::~MxVideoParam() { - this->m_rect = p_videoParam.m_rect; - this->m_palette = p_videoParam.m_palette; - this->m_backBuffers = p_videoParam.m_backBuffers; - this->m_flags = p_videoParam.m_flags; - this->m_unk1c = p_videoParam.m_unk1c; - SetDeviceName(p_videoParam.m_deviceId); - - return *this; + if (this->m_deviceId != NULL) + delete[] this->m_deviceId; } // OFFSET: LEGO1 0x100bed70 @@ -75,9 +69,15 @@ void MxVideoParam::SetDeviceName(char* id) } } -// OFFSET: LEGO1 0x100bed50 -MxVideoParam::~MxVideoParam() +// OFFSET: LEGO1 0x100bede0 +MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) { - if (this->m_deviceId != NULL) - delete[] this->m_deviceId; + this->m_rect = p_videoParam.m_rect; + this->m_palette = p_videoParam.m_palette; + this->m_backBuffers = p_videoParam.m_backBuffers; + this->m_flags = p_videoParam.m_flags; + this->m_unk1c = p_videoParam.m_unk1c; + SetDeviceName(p_videoParam.m_deviceId); + + return *this; } diff --git a/LEGO1/realtime/matrix.cpp b/LEGO1/realtime/matrix.cpp index 0b6b90b1..b36a06ff 100644 --- a/LEGO1/realtime/matrix.cpp +++ b/LEGO1/realtime/matrix.cpp @@ -138,7 +138,7 @@ void Matrix4Impl::ToQuaternion(Vector4Impl* p_outQuat) return; } - // OFFSET: LEGO1 0x100d4090 + // 0x100d4090 static int rotateIndex[] = {1, 2, 0}; // Largest element along the trace diff --git a/LEGO1/realtime/realtimeview.cpp b/LEGO1/realtime/realtimeview.cpp index f5864885..6d47547b 100644 --- a/LEGO1/realtime/realtimeview.cpp +++ b/LEGO1/realtime/realtimeview.cpp @@ -14,6 +14,19 @@ float g_userMaxLod = 3.6f; // 0x1010104c float g_partsThreshold = 1000.0f; +// OFFSET: LEGO1 0x100a5de0 +void RealtimeView::SetUserMaxLOD(float p_lod) +{ + g_userMaxLod = p_lod; + UpdateMaxLOD(); +} + +// OFFSET: LEGO1 0x100a5df0 +void RealtimeView::SetPartsThreshold(float p_threshold) +{ + g_partsThreshold = p_threshold; +} + // OFFSET: LEGO1 0x100a5e00 float RealtimeView::GetUserMaxLOD() { @@ -27,21 +40,8 @@ float RealtimeView::GetPartsThreshold() return g_partsThreshold; } -// OFFSET: LEGO1 100a5e20 +// OFFSET: LEGO1 0x100a5e20 void RealtimeView::UpdateMaxLOD() { g_userMaxLodPower = pow(g_userMaxBase, -g_userMaxLod); } - -// OFFSET: LEGO1 0x100a5de0 -void RealtimeView::SetUserMaxLOD(float p_lod) -{ - g_userMaxLod = p_lod; - UpdateMaxLOD(); -} - -// OFFSET: LEGO1 0x100a5df0 -void RealtimeView::SetPartsThreshold(float p_threshold) -{ - g_partsThreshold = p_threshold; -} diff --git a/LEGO1/realtime/vector.cpp b/LEGO1/realtime/vector.cpp index 4cdcec83..5223903e 100644 --- a/LEGO1/realtime/vector.cpp +++ b/LEGO1/realtime/vector.cpp @@ -12,10 +12,63 @@ DECOMP_SIZE_ASSERT(Vector4Impl, 0x8); DECOMP_SIZE_ASSERT(Vector3Data, 0x14); DECOMP_SIZE_ASSERT(Vector4Data, 0x18); -// OFFSET: LEGO1 0x100020a0 -const float* Vector2Impl::GetData() const +// OFFSET: LEGO1 0x10001f80 +void Vector2Impl::AddVectorImpl(float* p_value) { - return m_data; + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; +} + +// OFFSET: LEGO1 0x10001fa0 +void Vector2Impl::AddScalarImpl(float p_value) +{ + m_data[0] += p_value; + m_data[1] += p_value; +} + +// OFFSET: LEGO1 0x10001fc0 +void Vector2Impl::SubVectorImpl(float* p_value) +{ + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; +} + +// OFFSET: LEGO1 0x10001fe0 +void Vector2Impl::MullVectorImpl(float* p_value) +{ + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; +} + +// OFFSET: LEGO1 0x10002000 +void Vector2Impl::MullScalarImpl(float* p_value) +{ + m_data[0] *= *p_value; + m_data[1] *= *p_value; +} + +// OFFSET: LEGO1 0x10002020 +void Vector2Impl::DivScalarImpl(float* p_value) +{ + m_data[0] /= *p_value; + m_data[1] /= *p_value; +} + +// OFFSET: LEGO1 0x10002040 +float Vector2Impl::DotImpl(float* p_a, float* p_b) const +{ + return p_b[0] * p_a[0] + p_b[1] * p_a[1]; +} + +// OFFSET: LEGO1 0x10002060 TEMPLATE +// Vector2Impl::SetData + +// OFFSET: LEGO1 0x10002070 +void Vector2Impl::EqualsImpl(float* p_data) +{ + float* vec = m_data; + vec[0] = p_data[0]; + vec[1] = p_data[1]; } // OFFSET: LEGO1 0x10002090 @@ -24,16 +77,24 @@ float* Vector2Impl::GetData() return m_data; } -// OFFSET: LEGO1 0x10002130 -float Vector2Impl::Dot(Vector2Impl* p_a, float* p_b) const +// OFFSET: LEGO1 0x100020a0 +const float* Vector2Impl::GetData() const { - return DotImpl(p_a->m_data, p_b); + return m_data; } -// OFFSET: LEGO1 0x10002110 -float Vector2Impl::Dot(float* p_a, Vector2Impl* p_b) const +// OFFSET: LEGO1 0x100020b0 +void Vector2Impl::Clear() { - return DotImpl(p_a, p_b->m_data); + float* vec = m_data; + vec[0] = 0.0f; + vec[1] = 0.0f; +} + +// OFFSET: LEGO1 0x100020d0 +float Vector2Impl::Dot(float* p_a, float* p_b) const +{ + return DotImpl(p_a, p_b); } // OFFSET: LEGO1 0x100020f0 @@ -42,10 +103,22 @@ float Vector2Impl::Dot(Vector2Impl* p_a, Vector2Impl* p_b) const return DotImpl(p_a->m_data, p_b->m_data); } -// OFFSET: LEGO1 0x100020d0 -float Vector2Impl::Dot(float* p_a, float* p_b) const +// OFFSET: LEGO1 0x10002110 +float Vector2Impl::Dot(float* p_a, Vector2Impl* p_b) const { - return DotImpl(p_a, p_b); + return DotImpl(p_a, p_b->m_data); +} + +// OFFSET: LEGO1 0x10002130 +float Vector2Impl::Dot(Vector2Impl* p_a, float* p_b) const +{ + return DotImpl(p_a->m_data, p_b); +} + +// OFFSET: LEGO1 0x10002150 +float Vector2Impl::LenSquared() const +{ + return m_data[0] * m_data[0] + m_data[1] * m_data[1]; } // OFFSET: LEGO1 0x10002160 @@ -62,10 +135,10 @@ int Vector2Impl::Unitize() return -1; } -// OFFSET: LEGO1 0x100021e0 -void Vector2Impl::AddVector(Vector2Impl* p_other) +// OFFSET: LEGO1 0x100021c0 +void Vector2Impl::AddScalar(float p_value) { - AddVectorImpl(p_other->m_data); + AddScalarImpl(p_value); } // OFFSET: LEGO1 0x100021d0 @@ -74,16 +147,10 @@ void Vector2Impl::AddVector(float* p_other) AddVectorImpl(p_other); } -// OFFSET: LEGO1 0x100021c0 -void Vector2Impl::AddScalar(float p_value) +// OFFSET: LEGO1 0x100021e0 +void Vector2Impl::AddVector(Vector2Impl* p_other) { - AddScalarImpl(p_value); -} - -// OFFSET: LEGO1 0x10002200 -void Vector2Impl::SubVector(Vector2Impl* p_other) -{ - SubVectorImpl(p_other->m_data); + AddVectorImpl(p_other->m_data); } // OFFSET: LEGO1 0x100021f0 @@ -92,16 +159,10 @@ void Vector2Impl::SubVector(float* p_other) SubVectorImpl(p_other); } -// OFFSET: LEGO1 0x10002230 -void Vector2Impl::MullScalar(float* p_value) +// OFFSET: LEGO1 0x10002200 +void Vector2Impl::SubVector(Vector2Impl* p_other) { - MullScalarImpl(p_value); -} - -// OFFSET: LEGO1 0x10002220 -void Vector2Impl::MullVector(Vector2Impl* p_other) -{ - MullVectorImpl(p_other->m_data); + SubVectorImpl(p_other->m_data); } // OFFSET: LEGO1 0x10002210 @@ -110,100 +171,206 @@ void Vector2Impl::MullVector(float* p_other) MullVectorImpl(p_other); } +// OFFSET: LEGO1 0x10002220 +void Vector2Impl::MullVector(Vector2Impl* p_other) +{ + MullVectorImpl(p_other->m_data); +} + +// OFFSET: LEGO1 0x10002230 +void Vector2Impl::MullScalar(float* p_value) +{ + MullScalarImpl(p_value); +} + // OFFSET: LEGO1 0x10002240 void Vector2Impl::DivScalar(float* p_value) { DivScalarImpl(p_value); } -// OFFSET: LEGO1 0x10002260 -void Vector2Impl::SetVector(Vector2Impl* p_other) -{ - EqualsImpl(p_other->m_data); -} - // OFFSET: LEGO1 0x10002250 void Vector2Impl::SetVector(float* p_other) { EqualsImpl(p_other); } -// OFFSET: LEGO1 0x10001fa0 -void Vector2Impl::AddScalarImpl(float p_value) +// OFFSET: LEGO1 0x10002260 +void Vector2Impl::SetVector(Vector2Impl* p_other) { - m_data[0] += p_value; - m_data[1] += p_value; + EqualsImpl(p_other->m_data); } -// OFFSET: LEGO1 0x10001f80 -void Vector2Impl::AddVectorImpl(float* p_value) +// OFFSET: LEGO1 0x10002270 +void Vector3Impl::EqualsCrossImpl(float* p_a, float* p_b) +{ + m_data[0] = p_a[1] * p_b[2] - p_a[2] * p_b[1]; + m_data[1] = p_a[2] * p_b[0] - p_a[0] * p_b[2]; + m_data[2] = p_a[0] * p_b[1] - p_a[1] * p_b[0]; +} + +// OFFSET: LEGO1 0x100022c0 +void Vector3Impl::EqualsCross(Vector3Impl* p_a, Vector3Impl* p_b) +{ + EqualsCrossImpl(p_a->m_data, p_b->m_data); +} + +// OFFSET: LEGO1 0x100022e0 +void Vector3Impl::EqualsCross(Vector3Impl* p_a, float* p_b) +{ + EqualsCrossImpl(p_a->m_data, p_b); +} + +// OFFSET: LEGO1 0x10002300 +void Vector3Impl::EqualsCross(float* p_a, Vector3Impl* p_b) +{ + EqualsCrossImpl(p_a, p_b->m_data); +} + +// OFFSET: LEGO1 0x10002870 +void Vector4Impl::AddVectorImpl(float* p_value) { m_data[0] += p_value[0]; m_data[1] += p_value[1]; + m_data[2] += p_value[2]; + m_data[3] += p_value[3]; } -// OFFSET: LEGO1 0x10001fc0 -void Vector2Impl::SubVectorImpl(float* p_value) -{ - m_data[0] -= p_value[0]; - m_data[1] -= p_value[1]; -} - -// OFFSET: LEGO1 0x10002000 -void Vector2Impl::MullScalarImpl(float* p_value) -{ - m_data[0] *= *p_value; - m_data[1] *= *p_value; -} - -// OFFSET: LEGO1 0x10001fe0 -void Vector2Impl::MullVectorImpl(float* p_value) -{ - m_data[0] *= p_value[0]; - m_data[1] *= p_value[1]; -} - -// OFFSET: LEGO1 0x10002020 -void Vector2Impl::DivScalarImpl(float* p_value) -{ - m_data[0] /= *p_value; - m_data[1] /= *p_value; -} - -// OFFSET: LEGO1 0x10002040 -float Vector2Impl::DotImpl(float* p_a, float* p_b) const -{ - return p_b[0] * p_a[0] + p_b[1] * p_a[1]; -} - -// OFFSET: LEGO1 0x10002070 -void Vector2Impl::EqualsImpl(float* p_data) -{ - float* vec = m_data; - vec[0] = p_data[0]; - vec[1] = p_data[1]; -} - -// OFFSET: LEGO1 0x100020b0 -void Vector2Impl::Clear() -{ - float* vec = m_data; - vec[0] = 0.0f; - vec[1] = 0.0f; -} - -// OFFSET: LEGO1 0x10002150 -float Vector2Impl::LenSquared() const -{ - return m_data[0] * m_data[0] + m_data[1] * m_data[1]; -} - -// OFFSET: LEGO1 0x10003a90 -void Vector3Impl::AddScalarImpl(float p_value) +// OFFSET: LEGO1 0x100028b0 +void Vector4Impl::AddScalarImpl(float p_value) { m_data[0] += p_value; m_data[1] += p_value; m_data[2] += p_value; + m_data[3] += p_value; +} + +// OFFSET: LEGO1 0x100028f0 +void Vector4Impl::SubVectorImpl(float* p_value) +{ + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; + m_data[2] -= p_value[2]; + m_data[3] -= p_value[3]; +} + +// OFFSET: LEGO1 0x10002930 +void Vector4Impl::MullVectorImpl(float* p_value) +{ + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; + m_data[2] *= p_value[2]; + m_data[3] *= p_value[3]; +} + +// OFFSET: LEGO1 0x10002970 +void Vector4Impl::MullScalarImpl(float* p_value) +{ + m_data[0] *= *p_value; + m_data[1] *= *p_value; + m_data[2] *= *p_value; + m_data[3] *= *p_value; +} + +// OFFSET: LEGO1 0x100029b0 +void Vector4Impl::DivScalarImpl(float* p_value) +{ + m_data[0] /= *p_value; + m_data[1] /= *p_value; + m_data[2] /= *p_value; + m_data[3] /= *p_value; +} + +// OFFSET: LEGO1 0x100029f0 +float Vector4Impl::DotImpl(float* p_a, float* p_b) const +{ + return p_a[0] * p_b[0] + p_a[2] * p_b[2] + (p_a[1] * p_b[1] + p_a[3] * p_b[3]); +} + +// OFFSET: LEGO1 0x10002a20 +void Vector4Impl::EqualsImpl(float* p_data) +{ + float* vec = m_data; + vec[0] = p_data[0]; + vec[1] = p_data[1]; + vec[2] = p_data[2]; + vec[3] = p_data[3]; +} + +// OFFSET: LEGO1 0x10002a40 +void Vector4Impl::SetMatrixProductImpl(float* p_vec, float* p_mat) +{ + m_data[0] = p_vec[0] * p_mat[0] + p_vec[1] * p_mat[4] + p_vec[2] * p_mat[8] + p_vec[3] * p_mat[12]; + m_data[1] = p_vec[0] * p_mat[1] + p_vec[1] * p_mat[5] + p_vec[2] * p_mat[9] + p_vec[4] * p_mat[13]; + m_data[2] = p_vec[0] * p_mat[2] + p_vec[1] * p_mat[6] + p_vec[2] * p_mat[10] + p_vec[4] * p_mat[14]; + m_data[3] = p_vec[0] * p_mat[3] + p_vec[1] * p_mat[7] + p_vec[2] * p_mat[11] + p_vec[4] * p_mat[15]; +} + +// OFFSET: LEGO1 0x10002ae0 +void Vector4Impl::SetMatrixProduct(Vector4Impl* p_a, float* p_b) +{ + SetMatrixProductImpl(p_a->m_data, p_b); +} + +// OFFSET: LEGO1 0x10002b00 +void Vector4Impl::Clear() +{ + float* vec = m_data; + vec[0] = 0.0f; + vec[1] = 0.0f; + vec[2] = 0.0f; + vec[3] = 0.0f; +} + +// OFFSET: LEGO1 0x10002b20 +float Vector4Impl::LenSquared() const +{ + return m_data[1] * m_data[1] + m_data[0] * m_data[0] + m_data[2] * m_data[2] + m_data[3] * m_data[3]; +} + +// OFFSET: LEGO1 0x10002b40 +void Vector4Impl::EqualsScalar(float* p_value) +{ + m_data[0] = *p_value; + m_data[1] = *p_value; + m_data[2] = *p_value; + m_data[3] = *p_value; +} + +// Note close yet, included because I'm at least confident I know what operation +// it's trying to do. +// OFFSET: LEGO1 0x10002b70 STUB +int Vector4Impl::NormalizeQuaternion() +{ + float* v = m_data; + float magnitude = v[1] * v[1] + v[2] * v[2] + v[0] * v[0]; + if (magnitude > 0.0f) { + float theta = v[3] * 0.5f; + v[3] = cos(theta); + float frac = sin(theta); + magnitude = frac / sqrt(magnitude); + v[0] *= magnitude; + v[1] *= magnitude; + v[2] *= magnitude; + return 0; + } + return -1; +} + +// OFFSET: LEGO1 0x10002bf0 +void Vector4Impl::UnknownQuaternionOp(Vector4Impl* p_a, Vector4Impl* p_b) +{ + float* bDat = p_b->m_data; + float* aDat = p_a->m_data; + + this->m_data[3] = aDat[3] * bDat[3] - (bDat[0] * aDat[0] + aDat[2] * bDat[2] + aDat[1] * aDat[1]); + this->m_data[0] = bDat[2] * aDat[1] - bDat[1] * aDat[2]; + this->m_data[1] = aDat[2] * bDat[0] - bDat[2] * aDat[0]; + this->m_data[2] = bDat[1] * aDat[0] - aDat[1] * bDat[0]; + + m_data[0] = p_b->m_data[3] * p_a->m_data[0] + p_a->m_data[3] * p_b->m_data[0] + m_data[0]; + m_data[1] = p_b->m_data[1] * p_a->m_data[3] + p_a->m_data[1] * p_b->m_data[3] + m_data[1]; + m_data[2] = p_b->m_data[2] * p_a->m_data[3] + p_a->m_data[2] * p_b->m_data[3] + m_data[2]; } // OFFSET: LEGO1 0x10003a60 @@ -214,6 +381,14 @@ void Vector3Impl::AddVectorImpl(float* p_value) m_data[2] += p_value[2]; } +// OFFSET: LEGO1 0x10003a90 +void Vector3Impl::AddScalarImpl(float p_value) +{ + m_data[0] += p_value; + m_data[1] += p_value; + m_data[2] += p_value; +} + // OFFSET: LEGO1 0x10003ac0 void Vector3Impl::SubVectorImpl(float* p_value) { @@ -222,14 +397,6 @@ void Vector3Impl::SubVectorImpl(float* p_value) m_data[2] -= p_value[2]; } -// OFFSET: LEGO1 0x10003b20 -void Vector3Impl::MullScalarImpl(float* p_value) -{ - m_data[0] *= *p_value; - m_data[1] *= *p_value; - m_data[2] *= *p_value; -} - // OFFSET: LEGO1 0x10003af0 void Vector3Impl::MullVectorImpl(float* p_value) { @@ -238,6 +405,14 @@ void Vector3Impl::MullVectorImpl(float* p_value) m_data[2] *= p_value[2]; } +// OFFSET: LEGO1 0x10003b20 +void Vector3Impl::MullScalarImpl(float* p_value) +{ + m_data[0] *= *p_value; + m_data[1] *= *p_value; + m_data[2] *= *p_value; +} + // OFFSET: LEGO1 0x10003b50 void Vector3Impl::DivScalarImpl(float* p_value) { @@ -276,32 +451,6 @@ float Vector3Impl::LenSquared() const return m_data[1] * m_data[1] + m_data[0] * m_data[0] + m_data[2] * m_data[2]; } -// OFFSET: LEGO1 0x10002270 -void Vector3Impl::EqualsCrossImpl(float* p_a, float* p_b) -{ - m_data[0] = p_a[1] * p_b[2] - p_a[2] * p_b[1]; - m_data[1] = p_a[2] * p_b[0] - p_a[0] * p_b[2]; - m_data[2] = p_a[0] * p_b[1] - p_a[1] * p_b[0]; -} - -// OFFSET: LEGO1 0x10002300 -void Vector3Impl::EqualsCross(float* p_a, Vector3Impl* p_b) -{ - EqualsCrossImpl(p_a, p_b->m_data); -} - -// OFFSET: LEGO1 0x100022e0 -void Vector3Impl::EqualsCross(Vector3Impl* p_a, float* p_b) -{ - EqualsCrossImpl(p_a->m_data, p_b); -} - -// OFFSET: LEGO1 0x100022c0 -void Vector3Impl::EqualsCross(Vector3Impl* p_a, Vector3Impl* p_b) -{ - EqualsCrossImpl(p_a->m_data, p_b->m_data); -} - // OFFSET: LEGO1 0x10003bf0 void Vector3Impl::EqualsScalar(float* p_value) { @@ -309,149 +458,3 @@ void Vector3Impl::EqualsScalar(float* p_value) m_data[1] = *p_value; m_data[2] = *p_value; } - -// OFFSET: LEGO1 0x100028b0 -void Vector4Impl::AddScalarImpl(float p_value) -{ - m_data[0] += p_value; - m_data[1] += p_value; - m_data[2] += p_value; - m_data[3] += p_value; -} - -// OFFSET: LEGO1 0x10002870 -void Vector4Impl::AddVectorImpl(float* p_value) -{ - m_data[0] += p_value[0]; - m_data[1] += p_value[1]; - m_data[2] += p_value[2]; - m_data[3] += p_value[3]; -} - -// OFFSET: LEGO1 0x100028f0 -void Vector4Impl::SubVectorImpl(float* p_value) -{ - m_data[0] -= p_value[0]; - m_data[1] -= p_value[1]; - m_data[2] -= p_value[2]; - m_data[3] -= p_value[3]; -} - -// OFFSET: LEGO1 0x10002970 -void Vector4Impl::MullScalarImpl(float* p_value) -{ - m_data[0] *= *p_value; - m_data[1] *= *p_value; - m_data[2] *= *p_value; - m_data[3] *= *p_value; -} - -// OFFSET: LEGO1 0x10002930 -void Vector4Impl::MullVectorImpl(float* p_value) -{ - m_data[0] *= p_value[0]; - m_data[1] *= p_value[1]; - m_data[2] *= p_value[2]; - m_data[3] *= p_value[3]; -} - -// OFFSET: LEGO1 0x100029b0 -void Vector4Impl::DivScalarImpl(float* p_value) -{ - m_data[0] /= *p_value; - m_data[1] /= *p_value; - m_data[2] /= *p_value; - m_data[3] /= *p_value; -} - -// OFFSET: LEGO1 0x100029f0 -float Vector4Impl::DotImpl(float* p_a, float* p_b) const -{ - return p_a[0] * p_b[0] + p_a[2] * p_b[2] + (p_a[1] * p_b[1] + p_a[3] * p_b[3]); -} - -// OFFSET: LEGO1 0x10002a20 -void Vector4Impl::EqualsImpl(float* p_data) -{ - float* vec = m_data; - vec[0] = p_data[0]; - vec[1] = p_data[1]; - vec[2] = p_data[2]; - vec[3] = p_data[3]; -} - -// OFFSET: LEGO1 0x10002b00 -void Vector4Impl::Clear() -{ - float* vec = m_data; - vec[0] = 0.0f; - vec[1] = 0.0f; - vec[2] = 0.0f; - vec[3] = 0.0f; -} - -// OFFSET: LEGO1 0x10002b20 -float Vector4Impl::LenSquared() const -{ - return m_data[1] * m_data[1] + m_data[0] * m_data[0] + m_data[2] * m_data[2] + m_data[3] * m_data[3]; -} - -// OFFSET: LEGO1 0x10002b40 -void Vector4Impl::EqualsScalar(float* p_value) -{ - m_data[0] = *p_value; - m_data[1] = *p_value; - m_data[2] = *p_value; - m_data[3] = *p_value; -} - -// OFFSET: LEGO1 0x10002ae0 -void Vector4Impl::SetMatrixProduct(Vector4Impl* p_a, float* p_b) -{ - SetMatrixProductImpl(p_a->m_data, p_b); -} - -// OFFSET: LEGO1 0x10002a40 -void Vector4Impl::SetMatrixProductImpl(float* p_vec, float* p_mat) -{ - m_data[0] = p_vec[0] * p_mat[0] + p_vec[1] * p_mat[4] + p_vec[2] * p_mat[8] + p_vec[3] * p_mat[12]; - m_data[1] = p_vec[0] * p_mat[1] + p_vec[1] * p_mat[5] + p_vec[2] * p_mat[9] + p_vec[4] * p_mat[13]; - m_data[2] = p_vec[0] * p_mat[2] + p_vec[1] * p_mat[6] + p_vec[2] * p_mat[10] + p_vec[4] * p_mat[14]; - m_data[3] = p_vec[0] * p_mat[3] + p_vec[1] * p_mat[7] + p_vec[2] * p_mat[11] + p_vec[4] * p_mat[15]; -} - -// Note close yet, included because I'm at least confident I know what operation -// it's trying to do. -// OFFSET: LEGO1 0x10002b70 STUB -int Vector4Impl::NormalizeQuaternion() -{ - float* v = m_data; - float magnitude = v[1] * v[1] + v[2] * v[2] + v[0] * v[0]; - if (magnitude > 0.0f) { - float theta = v[3] * 0.5f; - v[3] = cos(theta); - float frac = sin(theta); - magnitude = frac / sqrt(magnitude); - v[0] *= magnitude; - v[1] *= magnitude; - v[2] *= magnitude; - return 0; - } - return -1; -} - -// OFFSET: LEGO1 0x10002bf0 -void Vector4Impl::UnknownQuaternionOp(Vector4Impl* p_a, Vector4Impl* p_b) -{ - float* bDat = p_b->m_data; - float* aDat = p_a->m_data; - - this->m_data[3] = aDat[3] * bDat[3] - (bDat[0] * aDat[0] + aDat[2] * bDat[2] + aDat[1] * aDat[1]); - this->m_data[0] = bDat[2] * aDat[1] - bDat[1] * aDat[2]; - this->m_data[1] = aDat[2] * bDat[0] - bDat[2] * aDat[0]; - this->m_data[2] = bDat[1] * aDat[0] - aDat[1] * bDat[0]; - - m_data[0] = p_b->m_data[3] * p_a->m_data[0] + p_a->m_data[3] * p_b->m_data[0] + m_data[0]; - m_data[1] = p_b->m_data[1] * p_a->m_data[3] + p_a->m_data[1] * p_b->m_data[3] + m_data[1]; - m_data[2] = p_b->m_data[2] * p_a->m_data[3] + p_a->m_data[2] * p_b->m_data[3] + m_data[2]; -} diff --git a/LEGO1/realtime/vector.h b/LEGO1/realtime/vector.h index aaed9556..a530959c 100644 --- a/LEGO1/realtime/vector.h +++ b/LEGO1/realtime/vector.h @@ -3,6 +3,10 @@ #include +// TODO: Find proper compilation unit to put this +// OFFSET: LEGO1 0x1000c0f0 TEMPLATE +// Vector2Impl::Vector2Impl + /* * A simple array of three floats that can be indexed into. */ @@ -60,7 +64,6 @@ struct Vector4 { // SIZE 0x8 class Vector2Impl { public: - // OFFSET: LEGO1 0x1000c0f0 inline Vector2Impl(float* p_data) { this->SetData(p_data); } // vtable + 0x00 (no virtual destructor) @@ -73,8 +76,6 @@ class Vector2Impl { virtual void MullVectorImpl(float* p_value) = 0; virtual void DivScalarImpl(float* p_value) = 0; virtual float DotImpl(float* p_a, float* p_b) const = 0; - - // OFFSET: LEGO1 0x10002060 virtual void SetData(float* p_data) { this->m_data = p_data; } // vtable + 0x20 diff --git a/LEGO1/score.cpp b/LEGO1/score.cpp index 2b7f2d95..1a171b23 100644 --- a/LEGO1/score.cpp +++ b/LEGO1/score.cpp @@ -22,6 +22,12 @@ Score::Score() NotificationManager()->Register(this); } +// OFFSET: LEGO1 0x100010b0 +MxBool Score::VTable0x5c() +{ + return TRUE; +} + // OFFSET: LEGO1 0x10001200 Score::~Score() { @@ -32,6 +38,39 @@ Score::~Score() NotificationManager()->Unregister(this); } +// OFFSET: LEGO1 0x100012a0 +MxResult Score::Create(MxDSObject& p_dsObject) +{ + MxResult result = SetAsCurrentWorld(p_dsObject); + + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + InputManager()->Register(this); + SetIsWorldActive(FALSE); + LegoGameState* gs = GameState(); + ScoreState* state = (ScoreState*) gs->GetState("ScoreState"); + m_state = state ? state : (ScoreState*) gs->CreateState("ScoreState"); + GameState()->SetUnknown424(0xd); + GameState()->FUN_1003a720(0); + } + + return result; +} + +// OFFSET: LEGO1 0x10001340 +void Score::DeleteScript() +{ + if (m_state->GetTutorialFlag()) { + MxDSAction action; + action.SetObjectId(0x1f5); + action.SetAtomId(*g_infoscorScript); + action.SetUnknown24(-2); + DeleteObject(action); + m_state->SetTutorialFlag(FALSE); + } +} + // OFFSET: LEGO1 0x10001410 MxLong Score::Notify(MxParam& p) { @@ -67,45 +106,6 @@ MxLong Score::Notify(MxParam& p) return ret; } -// OFFSET: LEGO1 0x100010b0 -MxBool Score::VTable0x5c() -{ - return TRUE; -} - -// OFFSET: LEGO1 0x100012a0 -MxResult Score::Create(MxDSObject& p_dsObject) -{ - MxResult result = SetAsCurrentWorld(p_dsObject); - - if (result == SUCCESS) { - InputManager()->SetWorld(this); - ControlManager()->Register(this); - InputManager()->Register(this); - SetIsWorldActive(FALSE); - LegoGameState* gs = GameState(); - ScoreState* state = (ScoreState*) gs->GetState("ScoreState"); - m_state = state ? state : (ScoreState*) gs->CreateState("ScoreState"); - GameState()->SetUnknown424(0xd); - GameState()->FUN_1003a720(0); - } - - return result; -} - -// OFFSET: LEGO1 0x10001340 -void Score::DeleteScript() -{ - if (m_state->GetTutorialFlag()) { - MxDSAction action; - action.SetObjectId(0x1f5); - action.SetAtomId(*g_infoscorScript); - action.SetUnknown24(-2); - DeleteObject(action); - m_state->SetTutorialFlag(FALSE); - } -} - // OFFSET: LEGO1 0x10001510 MxLong Score::FUN_10001510(MxEndActionNotificationParam& p) { diff --git a/tools/checkorder/checkorder.py b/tools/checkorder/checkorder.py new file mode 100644 index 00000000..eb243c2d --- /dev/null +++ b/tools/checkorder/checkorder.py @@ -0,0 +1,120 @@ +import os +import sys +import argparse +from isledecomp.dir import ( + walk_source_dir, + is_file_cpp +) +from isledecomp.parser import find_code_blocks +from isledecomp.parser.util import ( + is_exact_offset_comment +) + + +def sig_truncate(sig: str) -> str: + """Helper to truncate function names to 50 chars and append ellipsis + if needed. Goal is to stay under 80 columns for tool output.""" + return f"{sig[:47]}{'...' if len(sig) >= 50 else ''}" + + +def check_file(filename: str, verbose: bool = False) -> bool: + """Open and read the given file, then check whether the code blocks + are in order. If verbose, print each block.""" + + with open(filename, 'r') as f: + code_blocks = find_code_blocks(f) + + bad_comments = [(block.start_line, block.offset_comment) + for block in code_blocks + if not is_exact_offset_comment(block.offset_comment)] + + just_offsets = [block.offset for block in code_blocks] + sorted_offsets = sorted(just_offsets) + file_out_of_order = just_offsets != sorted_offsets + + # If we detect inexact comments, don't print anything unless we are + # in verbose mode. If the file is out of order, we always print the + # file name. + should_report = ((len(bad_comments) > 0 and verbose) + or file_out_of_order) + + if not should_report and not file_out_of_order: + return False + + # Else: we are alerting to some problem in this file + print(filename) + if verbose: + if file_out_of_order: + order_lookup = {k: i for i, k in enumerate(sorted_offsets)} + prev_offset = 0 + + for block in code_blocks: + msg = ' '.join([ + ' ' if block.offset > prev_offset else '!', + f'{block.offset:08x}', + f'{block.end_line - block.start_line:4} lines', + f'{order_lookup[block.offset]:3}', + ' ', + sig_truncate(block.signature), + ]) + print(msg) + prev_offset = block.offset + + for (line_no, line) in bad_comments: + print(f'* line {line_no:3} bad offset comment ({line})') + + print() + + return file_out_of_order + + +def parse_args(test_args: list | None = None) -> dict: + p = argparse.ArgumentParser() + p.add_argument('target', help='The file or directory to check.') + p.add_argument('--enforce', action=argparse.BooleanOptionalAction, + default=False, + help='Fail with error code if target is out of order.') + p.add_argument('--verbose', action=argparse.BooleanOptionalAction, + default=False, + help=('Display each code block in the file and show ' + 'where each consecutive run of blocks is broken.')) + + if test_args is None: + args = p.parse_args() + else: + args = p.parse_args(test_args) + + return vars(args) + + +def main(): + args = parse_args() + + if os.path.isdir(args['target']): + files_to_check = list(walk_source_dir(args['target'])) + elif os.path.isfile(args['target']) and is_file_cpp(args['target']): + files_to_check = [args['target']] + else: + sys.exit('Invalid target') + + files_out_of_order = 0 + + for file in files_to_check: + is_jumbled = check_file(file, args['verbose']) + if is_jumbled: + files_out_of_order += 1 + + if files_out_of_order > 0: + error_message = ' '.join([ + str(files_out_of_order), + 'files are' if files_out_of_order > 1 else 'file is', + 'out of order' + ]) + print(error_message) + + if files_out_of_order > 0 and args['enforce']: + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/tools/checkorder/requirements.txt b/tools/checkorder/requirements.txt new file mode 100644 index 00000000..176352a6 --- /dev/null +++ b/tools/checkorder/requirements.txt @@ -0,0 +1 @@ +isledecomp \ No newline at end of file diff --git a/tools/isledecomp/.gitignore b/tools/isledecomp/.gitignore new file mode 100644 index 00000000..00aa29cb --- /dev/null +++ b/tools/isledecomp/.gitignore @@ -0,0 +1 @@ +isledecomp.egg-info/ \ No newline at end of file diff --git a/tools/isledecomp/isledecomp/__init__.py b/tools/isledecomp/isledecomp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/isledecomp/isledecomp/dir.py b/tools/isledecomp/isledecomp/dir.py new file mode 100644 index 00000000..7904c1c0 --- /dev/null +++ b/tools/isledecomp/isledecomp/dir.py @@ -0,0 +1,21 @@ +import os +from typing import Iterator + + +def is_file_cpp(filename: str) -> bool: + (basefile, ext) = os.path.splitext(filename) + return ext.lower() in ('.h', '.cpp') + + +def walk_source_dir(source: str, recursive: bool = True) -> Iterator[str]: + """Generator to walk the given directory recursively and return + any C++ files found.""" + + source = os.path.abspath(source) + for subdir, dirs, files in os.walk(source): + for file in files: + if is_file_cpp(file): + yield os.path.join(subdir, file) + + if not recursive: + break diff --git a/tools/isledecomp/isledecomp/parser/__init__.py b/tools/isledecomp/isledecomp/parser/__init__.py new file mode 100644 index 00000000..0d504619 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/__init__.py @@ -0,0 +1 @@ +from .parser import find_code_blocks diff --git a/tools/isledecomp/isledecomp/parser/parser.py b/tools/isledecomp/isledecomp/parser/parser.py new file mode 100644 index 00000000..345c8a98 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/parser.py @@ -0,0 +1,142 @@ +# C++ file parser + +from typing import List, TextIO +from enum import Enum +from .util import ( + CodeBlock, + OffsetMatch, + is_blank_or_comment, + match_offset_comment, + is_exact_offset_comment, + get_template_function_name, + remove_trailing_comment, + distinct_by_module, +) + + +class ReaderState(Enum): + WANT_OFFSET = 0 + WANT_SIG = 1 + IN_FUNC = 2 + IN_TEMPLATE = 3 + WANT_CURLY = 4 + FUNCTION_DONE = 5 + + +def find_code_blocks(stream: TextIO) -> List[CodeBlock]: + """Read the IO stream (file) line-by-line and give the following report: + Foreach code block (function) in the file, what are its starting and + ending line numbers, and what is the given offset in the original + binary. We expect the result to be ordered by line number because we + are reading the file from start to finish.""" + + blocks: List[CodeBlock] = [] + + offset_matches: List[OffsetMatch] = [] + + function_sig = None + start_line = None + end_line = None + state = ReaderState.WANT_OFFSET + + # 1-based to match cvdump and your text editor + # I know it says 0, but we will increment before each readline() + line_no = 0 + can_seek = True + + while True: + # Do this before reading again so that an EOF will not + # cause us to miss the last function of the file. + if state == ReaderState.FUNCTION_DONE: + # Our list of offset marks could have duplicates on + # module name, so we'll eliminate those now. + for offset_match in distinct_by_module(offset_matches): + block = CodeBlock(offset=offset_match.address, + signature=function_sig, + start_line=start_line, + end_line=end_line, + offset_comment=offset_match.comment, + module=offset_match.module, + is_template=offset_match.is_template, + is_stub=offset_match.is_stub) + blocks.append(block) + offset_matches = [] + state = ReaderState.WANT_OFFSET + + if can_seek: + line_no += 1 + line = stream.readline() + if line == '': + break + + new_match = match_offset_comment(line) + if new_match is not None: + # We will allow multiple offsets if we have just begun + # the code block, but not after we hit the curly brace. + if state in (ReaderState.WANT_OFFSET, ReaderState.IN_TEMPLATE, + ReaderState.WANT_SIG): + # If we detected an offset marker unexpectedly, + # we are handling it here so we can continue seeking. + can_seek = True + + offset_matches.append(new_match) + + if new_match.is_template: + state = ReaderState.IN_TEMPLATE + else: + state = ReaderState.WANT_SIG + else: + # We hit another offset unexpectedly. + # We can recover easily by just ending the function here. + end_line = line_no - 1 + state = ReaderState.FUNCTION_DONE + + # Pause reading here so we handle the offset marker + # on the next loop iteration + can_seek = False + + elif state == ReaderState.IN_TEMPLATE: + # TEMPLATE functions are a special case. The signature is + # given on the next line (in a // comment) + function_sig = get_template_function_name(line) + start_line = line_no + end_line = line_no + state = ReaderState.FUNCTION_DONE + + elif state == ReaderState.WANT_SIG: + # Skip blank lines or comments that come after the offset + # marker. There is not a formal procedure for this, so just + # assume the next "code line" is the function signature + if not is_blank_or_comment(line): + # Inline functions may end with a comment. Strip that out + # to help parsing. + function_sig = remove_trailing_comment(line.strip()) + + # Now check to see if the opening curly bracket is on the + # same line. clang-format should prevent this (BraceWrapping) + # but it is easy to detect. + # If the entire function is on one line, handle that too. + if function_sig.endswith('{'): + start_line = line_no + state = ReaderState.IN_FUNC + elif (function_sig.endswith('}') or + function_sig.endswith('};')): + start_line = line_no + end_line = line_no + state = ReaderState.FUNCTION_DONE + else: + state = ReaderState.WANT_CURLY + + elif state == ReaderState.WANT_CURLY: + if line.strip() == '{': + start_line = line_no + state = ReaderState.IN_FUNC + + elif state == ReaderState.IN_FUNC: + # Naive but reasonable assumption that functions will end with + # a curly brace on its own line with no prepended spaces. + if line.startswith('}'): + end_line = line_no + state = ReaderState.FUNCTION_DONE + + return blocks diff --git a/tools/isledecomp/isledecomp/parser/util.py b/tools/isledecomp/isledecomp/parser/util.py new file mode 100644 index 00000000..848fd5ff --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/util.py @@ -0,0 +1,97 @@ +# C++ Parser utility functions and data structures +from __future__ import annotations # python <3.10 compatibility +import re +from typing import List +from collections import namedtuple + + +CodeBlock = namedtuple('CodeBlock', + ['offset', 'signature', 'start_line', 'end_line', + 'offset_comment', 'module', 'is_template', 'is_stub']) + +OffsetMatch = namedtuple('OffsetMatch', ['module', 'address', 'is_template', + 'is_stub', 'comment']) + +# This has not been formally established, but considering that "STUB" +# is a temporary state for a function, we assume it will appear last, +# after any other modifiers (i.e. TEMPLATE) + +# To match a reasonable variance of formatting for the offset comment +offsetCommentRegex = re.compile(r'\s*//\s*OFFSET:\s*(\w+)\s+(?:0x)?([a-f0-9]+)(\s+TEMPLATE)?(\s+STUB)?', # nopep8 + flags=re.I) + +# To match the exact syntax (text upper case, hex lower case, with spaces) +# that is used in most places +offsetCommentExactRegex = re.compile(r'^// OFFSET: [A-Z0-9]+ (0x[a-f0-9]+)( TEMPLATE)?( STUB)?$') # nopep8 + + +# The goal here is to just read whatever is on the next line, so some +# flexibility in the formatting seems OK +templateCommentRegex = re.compile(r'\s*//\s+(.*)') + + +# To remove any comment (//) or block comment (/*) and its leading spaces +# from the end of a code line +trailingCommentRegex = re.compile(r'(\s*(?://|/\*).*)$') + + +def get_template_function_name(line: str) -> str: + """Parse function signature for special TEMPLATE functions""" + template_match = templateCommentRegex.match(line) + + # If we don't match, you get whatever is on the line as the signature + if template_match is not None: + return template_match.group(1) + + return line + + +def remove_trailing_comment(line: str) -> str: + return trailingCommentRegex.sub('', line) + + +def is_blank_or_comment(line: str) -> bool: + """Helper to read ahead after the offset comment is matched. + There could be blank lines or other comments before the + function signature, and we want to skip those.""" + line_strip = line.strip() + return (len(line_strip) == 0 + or line_strip.startswith('//') + or line_strip.startswith('/*') + or line_strip.endswith('*/')) + + +def is_exact_offset_comment(line: str) -> bool: + """If the offset comment does not match our (unofficial) syntax + we may want to alert the user to fix it for style points.""" + return offsetCommentExactRegex.match(line) is not None + + +def match_offset_comment(line: str) -> OffsetMatch | None: + match = offsetCommentRegex.match(line) + if match is None: + return None + + return OffsetMatch(module=match.group(1), + address=int(match.group(2), 16), + is_template=match.group(3) is not None, + is_stub=match.group(4) is not None, + comment=line.strip()) + + +def distinct_by_module(offsets: List) -> List: + """Given a list of offset markers, return a list with distinct + module names. If module names (case-insensitive) are repeated, + choose the offset that appears first.""" + + if len(offsets) < 2: + return offsets + + # Dict maintains insertion order in python >=3.7 + offsets_dict = {} + for offset in offsets: + module_upper = offset.module.upper() + if module_upper not in offsets_dict: + offsets_dict[module_upper] = offset + + return list(offsets_dict.values()) diff --git a/tools/isledecomp/setup.py b/tools/isledecomp/setup.py new file mode 100644 index 00000000..897b802e --- /dev/null +++ b/tools/isledecomp/setup.py @@ -0,0 +1,9 @@ +from setuptools import setup, find_packages + +setup( + name='isledecomp', + version='0.1.0', + description='Python tools for the isledecomp project', + packages=find_packages(), + tests_require=['pytest'], +) diff --git a/tools/isledecomp/tests/__init__.py b/tools/isledecomp/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/isledecomp/tests/samples/basic_class.cpp b/tools/isledecomp/tests/samples/basic_class.cpp new file mode 100644 index 00000000..23ce3c39 --- /dev/null +++ b/tools/isledecomp/tests/samples/basic_class.cpp @@ -0,0 +1,29 @@ +// Sample for python unit tests +// Not part of the decomp + +// A very simple class + +class TestClass { +public: + TestClass(); + virtual ~TestClass() override; + + virtual MxResult Tickle() override; // vtable+08 + + // OFFSET: TEST 0x12345678 + inline const char* ClassName() const // vtable+0c + { + // 0xabcd1234 + return "TestClass"; + } + + // OFFSET: TEST 0xdeadbeef + inline MxBool IsA(const char* name) const override // vtable+10 + { + return !strcmp(name, TestClass::ClassName()); + } + +private: + int m_hello; + int m_hiThere; +}; diff --git a/tools/isledecomp/tests/samples/basic_file.cpp b/tools/isledecomp/tests/samples/basic_file.cpp new file mode 100644 index 00000000..6a4017b5 --- /dev/null +++ b/tools/isledecomp/tests/samples/basic_file.cpp @@ -0,0 +1,22 @@ +// Sample for python unit tests +// Not part of the decomp + +// A very simple well-formed code file + +// OFFSET: TEST 0x1234 +void function01() +{ + // TODO +} + +// OFFSET: TEST 0x2345 +void function02() +{ + // TODO +} + +// OFFSET: TEST 0x3456 +void function03() +{ + // TODO +} diff --git a/tools/isledecomp/tests/samples/inline.cpp b/tools/isledecomp/tests/samples/inline.cpp new file mode 100644 index 00000000..0bfedf6d --- /dev/null +++ b/tools/isledecomp/tests/samples/inline.cpp @@ -0,0 +1,8 @@ +// Sample for python unit tests +// Not part of the decomp + +// OFFSET: TEST 0x10000001 +inline const char* OneLineWithComment() const { return "MxDSObject"; }; // hi there + +// OFFSET: TEST 0x10000002 +inline const char* OneLine() const { return "MxDSObject"; }; diff --git a/tools/isledecomp/tests/samples/missing_offset.cpp b/tools/isledecomp/tests/samples/missing_offset.cpp new file mode 100644 index 00000000..332fed2c --- /dev/null +++ b/tools/isledecomp/tests/samples/missing_offset.cpp @@ -0,0 +1,16 @@ +// Sample for python unit tests +// Not part of the decomp + +#include + +int no_offset_comment() +{ + static int dummy = 123; + return -1; +} + +// OFFSET: TEST 0xdeadbeef +void regular_ole_function() +{ + printf("hi there"); +} diff --git a/tools/isledecomp/tests/samples/multiple_offsets.cpp b/tools/isledecomp/tests/samples/multiple_offsets.cpp new file mode 100644 index 00000000..eecdd95b --- /dev/null +++ b/tools/isledecomp/tests/samples/multiple_offsets.cpp @@ -0,0 +1,25 @@ +// Sample for python unit tests +// Not part of the decomp + +// Handling multiple offset markers + +// OFFSET: TEST 0x1234 +// OFFSET: HELLO 0x5555 +void different_modules() +{ + // TODO +} + +// OFFSET: TEST 0x2345 +// OFFSET: TEST 0x1234 +void same_module() +{ + // TODO +} + +// OFFSET: TEST 0x2002 +// OFFSET: test 0x1001 +void same_case_insensitive() +{ + // TODO +} diff --git a/tools/isledecomp/tests/samples/oneline_function.cpp b/tools/isledecomp/tests/samples/oneline_function.cpp new file mode 100644 index 00000000..8d7fdc5a --- /dev/null +++ b/tools/isledecomp/tests/samples/oneline_function.cpp @@ -0,0 +1,12 @@ +// Sample for python unit tests +// Not part of the decomp + +// OFFSET: TEST 0x1234 +void short_function() { static char* msg = "oneliner"; } + +// OFFSET: TEST 0x5555 +void function_after_one_liner() +{ + // This function comes after the previous that is on a single line. + // Do we report the offset for this one correctly? +} diff --git a/tools/isledecomp/tests/samples/out_of_order.cpp b/tools/isledecomp/tests/samples/out_of_order.cpp new file mode 100644 index 00000000..749c4f2b --- /dev/null +++ b/tools/isledecomp/tests/samples/out_of_order.cpp @@ -0,0 +1,20 @@ +// Sample for python unit tests +// Not part of the decomp + +// OFFSET: TEST 0x1001 +void function_order01() +{ + // TODO +} + +// OFFSET: TEST 0x1003 +void function_order03() +{ + // TODO +} + +// OFFSET: TEST 0x1002 +void function_order02() +{ + // TODO +} diff --git a/tools/isledecomp/tests/samples/poorly_formatted.cpp b/tools/isledecomp/tests/samples/poorly_formatted.cpp new file mode 100644 index 00000000..32dd774c --- /dev/null +++ b/tools/isledecomp/tests/samples/poorly_formatted.cpp @@ -0,0 +1,23 @@ +// Sample for python unit tests +// Not part of the decomp + +// While it's reasonable to expect a well-formed file (and clang-format +// will make sure we get one), this will put the parser through its paces. + +// OFFSET: TEST 0x1234 +void curly_with_spaces() + { + static char* msg = "hello"; + } + +// OFFSET: TEST 0x5555 +void weird_closing_curly() +{ + int x = 123; } + +// OFFSET: HELLO 0x5656 +void bad_indenting() { + if (0) +{ + int y = 5; +}} diff --git a/tools/isledecomp/tests/test_parser.py b/tools/isledecomp/tests/test_parser.py new file mode 100644 index 00000000..a55bf549 --- /dev/null +++ b/tools/isledecomp/tests/test_parser.py @@ -0,0 +1,128 @@ +import os +import pytest +from typing import List, TextIO +from isledecomp.parser import find_code_blocks +from isledecomp.parser.util import CodeBlock + +SAMPLE_DIR = os.path.join(os.path.dirname(__file__), 'samples') + + +def sample_file(filename: str) -> TextIO: + """Wrapper for opening the samples from the directory that does not + depend on the cwd where we run the test""" + full_path = os.path.join(SAMPLE_DIR, filename) + return open(full_path, 'r') + + +def code_blocks_are_sorted(blocks: List[CodeBlock]) -> bool: + """Helper to make this more idiomatic""" + just_offsets = [block.offset for block in blocks] + return just_offsets == sorted(just_offsets) + + +# Tests are below # + + +def test_sanity(): + """Read a very basic file""" + with sample_file('basic_file.cpp') as f: + blocks = find_code_blocks(f) + + assert len(blocks) == 3 + assert code_blocks_are_sorted(blocks) is True + # n.b. The parser returns line numbers as 1-based + # Function starts when we see the opening curly brace + assert blocks[0].start_line == 8 + assert blocks[0].end_line == 10 + + +def test_oneline(): + """(Assuming clang-format permits this) This sample has a function + on a single line. This will test the end-of-function detection""" + with sample_file('oneline_function.cpp') as f: + blocks = find_code_blocks(f) + + assert len(blocks) == 2 + assert blocks[0].start_line == 5 + assert blocks[0].end_line == 5 + + +def test_missing_offset(): + """What if the function doesn't have an offset comment?""" + with sample_file('missing_offset.cpp') as f: + blocks = find_code_blocks(f) + + # TODO: For now, the function without the offset will just be ignored. + # Would be the same outcome if the comment was present but mangled and + # we failed to match it. We should detect these cases in the future. + assert len(blocks) == 1 + + +def test_jumbled_case(): + """The parser just reports what it sees. It is the responsibility of + the downstream tools to do something about a jumbled file. + Just verify that we are reading it correctly.""" + with sample_file('out_of_order.cpp') as f: + blocks = find_code_blocks(f) + + assert len(blocks) == 3 + assert code_blocks_are_sorted(blocks) is False + + +def test_bad_file(): + with sample_file('poorly_formatted.cpp') as f: + blocks = find_code_blocks(f) + + assert len(blocks) == 3 + + +def test_indented(): + """Offsets for functions inside of a class will probably be indented.""" + with sample_file('basic_class.cpp') as f: + blocks = find_code_blocks(f) + + # TODO: We don't properly detect the end of these functions + # because the closing brace is indented. However... knowing where each + # function ends is less important (for now) than capturing + # all the functions that are there. + + assert len(blocks) == 2 + assert blocks[0].offset == int('0x12345678', 16) + assert blocks[0].start_line == 15 + # assert blocks[0].end_line == 18 + + assert blocks[1].offset == int('0xdeadbeef', 16) + assert blocks[1].start_line == 22 + # assert blocks[1].end_line == 24 + + +def test_inline(): + with sample_file('inline.cpp') as f: + blocks = find_code_blocks(f) + + assert len(blocks) == 2 + for block in blocks: + assert block.start_line is not None + assert block.start_line == block.end_line + + +def test_multiple_offsets(): + """If multiple offset marks appear before for a code block, take them + all but ensure module name (case-insensitive) is distinct. + Use first module occurrence in case of duplicates.""" + with sample_file('multiple_offsets.cpp') as f: + blocks = find_code_blocks(f) + + assert len(blocks) == 4 + assert blocks[0].module == 'TEST' + assert blocks[0].start_line == 9 + + assert blocks[1].module == 'HELLO' + assert blocks[1].start_line == 9 + + # Duplicate modules are ignored + assert blocks[2].start_line == 16 + assert blocks[2].offset == 0x2345 + + assert blocks[3].module == 'TEST' + assert blocks[3].offset == 0x2002 diff --git a/tools/isledecomp/tests/test_parser_util.py b/tools/isledecomp/tests/test_parser_util.py new file mode 100644 index 00000000..3fc9bb61 --- /dev/null +++ b/tools/isledecomp/tests/test_parser_util.py @@ -0,0 +1,113 @@ +import pytest +from collections import namedtuple +from typing import List +from isledecomp.parser.util import ( + is_blank_or_comment, + match_offset_comment, + is_exact_offset_comment, + distinct_by_module, +) + + +blank_or_comment_param = [ + (True, ''), + (True, '\t'), + (True, ' '), + (False, '\tint abc=123;'), + (True, '// OFFSET: LEGO1 0xdeadbeef'), + (True, ' /* Block comment beginning'), + (True, 'Block comment ending */ '), + + # TODO: does clang-format have anything to say about these cases? + (False, 'x++; // Comment folows'), + (False, 'x++; /* Block comment begins'), +] + + +@pytest.mark.parametrize('expected, line', blank_or_comment_param) +def test_is_blank_or_comment(line: str, expected: bool): + assert is_blank_or_comment(line) is expected + + +offset_comment_samples = [ + # (can_parse: bool, exact_match: bool, line: str) + # Should match both expected modules with optional STUB marker + (True, True, '// OFFSET: LEGO1 0xdeadbeef'), + (True, True, '// OFFSET: LEGO1 0xdeadbeef STUB'), + (True, True, '// OFFSET: ISLE 0x12345678'), + (True, True, '// OFFSET: ISLE 0x12345678 STUB'), + + # No trailing spaces allowed + (True, False, '// OFFSET: LEGO1 0xdeadbeef '), + (True, False, '// OFFSET: LEGO1 0xdeadbeef STUB '), + + # Must have exactly one space between elements + (True, False, '//OFFSET: ISLE 0xdeadbeef'), + (True, False, '// OFFSET:ISLE 0xdeadbeef'), + (True, False, '// OFFSET: ISLE 0xdeadbeef'), + (True, False, '// OFFSET: ISLE 0xdeadbeef'), + (True, False, '// OFFSET: ISLE 0xdeadbeef'), + (True, False, '// OFFSET: ISLE 0xdeadbeef STUB'), + + # Must have 0x prefix for hex number + (True, False, '// OFFSET: ISLE deadbeef'), + + # Offset, module name, and STUB must be uppercase + (True, False, '// offset: ISLE 0xdeadbeef'), + (True, False, '// offset: isle 0xdeadbeef'), + (True, False, '// OFFSET: LEGO1 0xdeadbeef stub'), + + # Hex string must be lowercase + (True, False, '// OFFSET: ISLE 0xDEADBEEF'), + + # TODO: How flexible should we be with matching the module name? + (True, True, '// OFFSET: OMNI 0x12345678'), + (True, True, '// OFFSET: LEG01 0x12345678'), + (True, False, '// OFFSET: hello 0x12345678'), + + # Not close enough to match + (False, False, '// OFFSET: ISLE0x12345678'), + (False, False, '// OFFSET: 0x12345678'), + (False, False, '// LEGO1: 0x12345678'), + + # Hex string shorter than 8 characters + (True, True, '// OFFSET: LEGO1 0x1234'), + + # TODO: These match but shouldn't. + # (False, False, '// OFFSET: LEGO1 0'), + # (False, False, '// OFFSET: LEGO1 0x'), +] + + +@pytest.mark.parametrize('match, exact, line', offset_comment_samples) +def test_offset_match(line: str, match: bool, exact): + did_match = match_offset_comment(line) is not None + assert did_match is match + + +@pytest.mark.parametrize('match, exact, line', offset_comment_samples) +def test_exact_offset_comment(line: str, exact: bool, match): + assert is_exact_offset_comment(line) is exact + + +# Helper for the next test: cut down version of OffsetMatch +MiniOfs = namedtuple('MiniOfs', ['module', 'value']) + +distinct_by_module_samples = [ + # empty set + ([], []), + # same module name + ([MiniOfs('TEST', 123), MiniOfs('TEST', 555)], + [MiniOfs('TEST', 123)]), + # same module name, case-insensitive + ([MiniOfs('test', 123), MiniOfs('TEST', 555)], + [MiniOfs('test', 123)]), + # duplicates, non-consecutive + ([MiniOfs('test', 123), MiniOfs('abc', 111), MiniOfs('TEST', 555)], + [MiniOfs('test', 123), MiniOfs('abc', 111)]), +] + + +@pytest.mark.parametrize('sample, expected', distinct_by_module_samples) +def test_distinct_by_module(sample: List[MiniOfs], expected: List[MiniOfs]): + assert distinct_by_module(sample) == expected diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index debc25a3..5e295f7d 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -12,6 +12,8 @@ import colorama import html import re +from isledecomp.dir import walk_source_dir +from isledecomp.parser import find_code_blocks from pystache import Renderer parser = argparse.ArgumentParser(allow_abbrev=False, @@ -413,145 +415,120 @@ def can_resolve_register_differences(original_asm, new_asm): # Generate basename of original file, used in locating OFFSET lines basename = os.path.basename(os.path.splitext(original)[0]) -pattern = '// OFFSET:' -for subdir, dirs, files in os.walk(source): - for file in files: - srcfilename = os.path.join(os.path.abspath(subdir), file) - with open(srcfilename, 'r') as srcfile: - line_no = 0 +for srcfilename in walk_source_dir(source): + with open(srcfilename, 'r') as srcfile: + blocks = find_code_blocks(srcfile) - while True: - try: - line = srcfile.readline() - line_no += 1 + for block in blocks: + if block.is_stub: + continue - if not line: - break + if block.module != basename: + continue - line = line.strip() + addr = block.offset + # Verbose flag handling + if verbose: + if addr == verbose: + found_verbose_target = True + else: + continue - if line.startswith(pattern) and not line.endswith('STUB'): - par = line[len(pattern):].strip().split() - module = par[0] - if module != basename: - continue + if block.is_template: + recinfo = syminfo.get_recompiled_address_from_name(block.signature) + if not recinfo: + continue + else: + recinfo = syminfo.get_recompiled_address(srcfilename, block.start_line) + if not recinfo: + continue - addr = int(par[1], 16) + # The effective_ratio is the ratio when ignoring differing register + # allocation vs the ratio is the true ratio. + ratio = 0.0 + effective_ratio = 0.0 + if recinfo.size: + origasm = parse_asm(origfile, addr + recinfo.start, recinfo.size) + recompasm = parse_asm(recompfile, recinfo.addr + recinfo.start, recinfo.size) - # Verbose flag handling - if verbose: - if addr == verbose: - found_verbose_target = True - else: - continue + diff = difflib.SequenceMatcher(None, origasm, recompasm) + ratio = diff.ratio() + effective_ratio = ratio - if line.endswith('TEMPLATE'): - line = srcfile.readline() - line_no += 1 - # Name comes after // comment - name = line.strip()[2:].strip() + if ratio != 1.0: + # Check whether we can resolve register swaps which are actually + # perfect matches modulo compiler entropy. + if can_resolve_register_differences(origasm, recompasm): + effective_ratio = 1.0 + else: + ratio = 0 - recinfo = syminfo.get_recompiled_address_from_name(name) - if not recinfo: - continue - else: - find_open_bracket = line - while '{' not in find_open_bracket: - find_open_bracket = srcfile.readline() - line_no += 1 + percenttext = f'{(effective_ratio * 100):.2f}%' + if not plain: + if effective_ratio == 1.0: + percenttext = colorama.Fore.GREEN + percenttext + colorama.Style.RESET_ALL + elif effective_ratio > 0.8: + percenttext = colorama.Fore.YELLOW + percenttext + colorama.Style.RESET_ALL + else: + percenttext = colorama.Fore.RED + percenttext + colorama.Style.RESET_ALL - recinfo = syminfo.get_recompiled_address(srcfilename, line_no) - if not recinfo: - continue + if effective_ratio == 1.0 and ratio != 1.0: + if plain: + percenttext += '*' + else: + percenttext += colorama.Fore.RED + '*' + colorama.Style.RESET_ALL - # The effective_ratio is the ratio when ignoring differing register - # allocation vs the ratio is the true ratio. - ratio = 0.0 - effective_ratio = 0.0 - if recinfo.size: - origasm = parse_asm(origfile, addr + recinfo.start, recinfo.size) - recompasm = parse_asm(recompfile, recinfo.addr + recinfo.start, recinfo.size) + if args.print_rec_addr: + addrs = f'0x{addr:x} / 0x{recinfo.addr:x}' + else: + addrs = hex(addr) - diff = difflib.SequenceMatcher(None, origasm, recompasm) - ratio = diff.ratio() - effective_ratio = ratio + if not verbose: + print(f' {recinfo.name} ({addrs}) is {percenttext} similar to the original') - if ratio != 1.0: - # Check whether we can resolve register swaps which are actually - # perfect matches modulo compiler entropy. - if can_resolve_register_differences(origasm, recompasm): - effective_ratio = 1.0 - else: - ratio = 0 + function_count += 1 + total_accuracy += ratio + total_effective_accuracy += effective_ratio - percenttext = f'{(effective_ratio * 100):.2f}%' - if not plain: - if effective_ratio == 1.0: - percenttext = colorama.Fore.GREEN + percenttext + colorama.Style.RESET_ALL - elif effective_ratio > 0.8: - percenttext = colorama.Fore.YELLOW + percenttext + colorama.Style.RESET_ALL - else: - percenttext = colorama.Fore.RED + percenttext + colorama.Style.RESET_ALL + if recinfo.size: + udiff = difflib.unified_diff(origasm, recompasm, n=10) - if effective_ratio == 1.0 and ratio != 1.0: + # If verbose, print the diff for that function to the output + if verbose: + if effective_ratio == 1.0: + ok_text = 'OK!' if plain else (colorama.Fore.GREEN + '✨ OK! ✨' + colorama.Style.RESET_ALL) + if ratio == 1.0: + print(f'{addrs}: {recinfo.name} 100% match.\n\n{ok_text}\n\n') + else: + print(f'{addrs}: {recinfo.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n') + else: + for line in udiff: + if line.startswith('++') or line.startswith('@@') or line.startswith('--'): + # Skip unneeded parts of the diff for the brief view + pass + elif line.startswith('+'): if plain: - percenttext += '*' + print(line) else: - percenttext += colorama.Fore.RED + '*' + colorama.Style.RESET_ALL - - if args.print_rec_addr: - addrs = f'0x{addr:x} / 0x{recinfo.addr:x}' + print(colorama.Fore.GREEN + line) + elif line.startswith('-'): + if plain: + print(line) + else: + print(colorama.Fore.RED + line) else: - addrs = hex(addr) + print(line) + if not plain: + print(colorama.Style.RESET_ALL, end='') - if not verbose: - print(f' {recinfo.name} ({addrs}) is {percenttext} similar to the original') + print(f'\n{recinfo.name} is only {percenttext} similar to the original, diff above') - function_count += 1 - total_accuracy += ratio - total_effective_accuracy += effective_ratio + # If html, record the diffs to an HTML file + if html_path: + escaped = html.escape('\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n')) + htmlinsert.append(f'{{address: "0x{addr:x}", name: "{html.escape(recinfo.name)}", matching: {effective_ratio}, diff: "{escaped}"}}') - if recinfo.size: - udiff = difflib.unified_diff(origasm, recompasm, n=10) - - # If verbose, print the diff for that function to the output - if verbose: - if effective_ratio == 1.0: - ok_text = 'OK!' if plain else (colorama.Fore.GREEN + '✨ OK! ✨' + colorama.Style.RESET_ALL) - if ratio == 1.0: - print(f'{addrs}: {recinfo.name} 100% match.\n\n{ok_text}\n\n') - else: - print(f'{addrs}: {recinfo.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n') - else: - for line in udiff: - if line.startswith('++') or line.startswith('@@') or line.startswith('--'): - # Skip unneeded parts of the diff for the brief view - pass - elif line.startswith('+'): - if plain: - print(line) - else: - print(colorama.Fore.GREEN + line) - elif line.startswith('-'): - if plain: - print(line) - else: - print(colorama.Fore.RED + line) - else: - print(line) - if not plain: - print(colorama.Style.RESET_ALL, end='') - - print(f'\n{recinfo.name} is only {percenttext} similar to the original, diff above') - - # If html, record the diffs to an HTML file - if html_path: - escaped = html.escape('\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n')) - htmlinsert.append(f'{{address: "0x{addr:x}", name: "{html.escape(recinfo.name)}", matching: {effective_ratio}, diff: "{escaped}"}}') - - except UnicodeDecodeError: - break def gen_html(html_file, data): output_data = Renderer().render_path(get_file_in_script_dir('template.html'), diff --git a/tools/reccmp/requirements.txt b/tools/reccmp/requirements.txt index b4f969a7..c7de0d0c 100644 --- a/tools/reccmp/requirements.txt +++ b/tools/reccmp/requirements.txt @@ -1,3 +1,4 @@ capstone colorama -pystache +isledecomp +pystache \ No newline at end of file