diff --git a/.clang-format b/.clang-format index 4ff99b84..d305f434 100644 --- a/.clang-format +++ b/.clang-format @@ -21,6 +21,14 @@ IndentAccessModifiers: false IndentWidth: 4 InsertNewlineAtEOF: true PointerAlignment: Left +QualifierAlignment: Custom +QualifierOrder: + - inline + - static + - friend + - const + - volatile + - type SpaceAfterCStyleCast: true TabWidth: 4 UseTab: ForContinuationAndIndentation diff --git a/CMakeLists.txt b/CMakeLists.txt index 14882a1e..a297f7f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,12 +163,14 @@ add_library(lego1 SHARED LEGO1/mxramstreamcontroller.cpp LEGO1/mxramstreamprovider.cpp LEGO1/mxregion.cpp + LEGO1/mxregionlist.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp LEGO1/mxsmkpresenter.cpp LEGO1/mxsoundmanager.cpp LEGO1/mxsoundpresenter.cpp LEGO1/mxstillpresenter.cpp + LEGO1/mxstreamchunklist.cpp LEGO1/mxstreamcontroller.cpp LEGO1/mxstreamer.cpp LEGO1/mxstreamprovider.cpp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b70c45b7..9a20eb09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ We are currently using [clang-format](https://clang.llvm.org/docs/ClangFormat.ht - `m_camelCase` for member variables. - `g_camelCase` for global variables. - `p_camelCase` for function parameters. -- Instead of C++ primitives (e.g. `int`, `long`, etc.), use types in `mxtypes.h` instead. This will help us ensure that variables will be the correct size regardless of the underlying compiler/platform/architecture. +- Instead of C++ primitives (e.g. `int`, `long`, etc.), use types in [`mxtypes.h`](LEGO1/mxtypes.h) instead. This will help us ensure that variables will be the correct size regardless of the underlying compiler/platform/architecture. ## Questions? diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 8c38315e..775f038c 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -95,7 +95,7 @@ void IsleApp::Close() if (Lego()) { GameState()->Save(0); if (InputManager()) { - InputManager()->QueueEvent(KEYDOWN, 0, 0, 0, 0x20); + InputManager()->QueueEvent(c_notificationKeyPress, 0, 0, 0, 0x20); } VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->RemoveAll(NULL); @@ -431,22 +431,22 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return DefWindowProcA(hWnd, uMsg, wParam, lParam); } keyCode = wParam; - type = KEYDOWN; + type = c_notificationKeyPress; break; case WM_MOUSEMOVE: g_mousemoved = 1; - type = MOUSEMOVE; + type = c_notificationMouseMove; break; case WM_TIMER: - type = TIMER; + type = c_notificationTimer; break; case WM_LBUTTONDOWN: g_mousedown = 1; - type = MOUSEDOWN; + type = c_notificationButtonDown; break; case WM_LBUTTONUP: g_mousedown = 0; - type = MOUSEUP; + type = c_notificationButtonUp; break; case 0x5400: if (g_isle) { @@ -462,7 +462,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (InputManager()) { InputManager()->QueueEvent(type, wParam, LOWORD(lParam), HIWORD(lParam), keyCode); } - if (g_isle && g_isle->m_drawCursor && type == MOUSEMOVE) { + if (g_isle && g_isle->m_drawCursor && type == c_notificationMouseMove) { int x = LOWORD(lParam); int y = HIWORD(lParam); if (x >= 640) { diff --git a/LEGO1/define.cpp b/LEGO1/define.cpp index 8eb1f466..ea57cbb7 100644 --- a/LEGO1/define.cpp +++ b/LEGO1/define.cpp @@ -1,5 +1,15 @@ #include "define.h" +// 0x1010141c +MxU32 g_mxcoreCount[101] = {0, -6643, -5643, -5058, -4643, -4321, -4058, -3836, -3643, -3473, -3321, -3184, -3058, + -2943, -2836, -2736, -2643, -2556, -2473, -2395, -2321, -2251, -2184, -2120, -2058, -2000, + -1943, -1888, -1836, -1785, -1736, -1689, -1643, -1599, -1556, -1514, -1473, -1434, -1395, + -1358, -1321, -1286, -1251, -1217, -1184, -1152, -1120, -1089, -1058, -1029, -1000, -971, + -943, -915, -888, -862, -836, -810, -785, -761, -736, -713, -689, -666, -643, + -621, -599, -577, -556, -535, -514, -494, -473, -454, -434, -415, -395, -377, + -358, -340, -321, -304, -286, -268, -251, -234, -217, -200, -184, -168, -152, + -136, -120, -104, -89, -74, -58, -43, -29, -14, 0}; + // 0x10101eac const char* g_parseExtraTokens = ":;"; diff --git a/LEGO1/define.h b/LEGO1/define.h index fe3f2e9d..2089032d 100644 --- a/LEGO1/define.h +++ b/LEGO1/define.h @@ -1,6 +1,9 @@ #ifndef DEFINE_H #define DEFINE_H +#include "mxtypes.h" + +extern MxU32 g_mxcoreCount[101]; extern const char* g_parseExtraTokens; extern const char* g_strWORLD; extern const char* g_strACTION; diff --git a/LEGO1/legoactor.cpp b/LEGO1/legoactor.cpp index ace8a47c..31c6da6f 100644 --- a/LEGO1/legoactor.cpp +++ b/LEGO1/legoactor.cpp @@ -3,43 +3,49 @@ DECOMP_SIZE_ASSERT(LegoActor, 0x78) // Probably in header -// OFFSET: LEGO1 0x10002cc0 STUB -void LegoActor::VTable0x50() +// OFFSET: LEGO1 0x10002cc0 +MxFloat LegoActor::VTable0x50() { - // TODO + return m_unk68; } -// OFFSET: LEGO1 0x10002cd0 STUB -void LegoActor::VTable0x54() +// OFFSET: LEGO1 0x10002cd0 +void LegoActor::VTable0x54(MxFloat p_unk) { - // TODO + m_unk68 = p_unk; } -// OFFSET: LEGO1 0x10002ce0 STUB -void LegoActor::VTable0x58() +// OFFSET: LEGO1 0x10002ce0 +void LegoActor::VTable0x58(MxFloat p_unk) { - // TODO + m_unk70 = p_unk; } -// OFFSET: LEGO1 0x10002cf0 STUB -void LegoActor::VTable0x5c() +// OFFSET: LEGO1 0x10002cf0 +MxFloat LegoActor::VTable0x5c() { - // TODO + return m_unk70; } -// OFFSET: LEGO1 0x10002d00 STUB -void LegoActor::VTable0x60() +// OFFSET: LEGO1 0x10002d00 +undefined LegoActor::VTable0x60() { - // TODO + return m_unk74; } -// OFFSET: LEGO1 0x10002d10 STUB -void LegoActor::VTable0x64() +// OFFSET: LEGO1 0x10002d10 +void LegoActor::VTable0x64(undefined p_unk) { - // TODO + m_unk74 = p_unk; } // End header +// OFFSET: LEGO1 0x1002d110 LegoActor::LegoActor() { + m_unk68 = 0.0f; + m_unk6c = 0; + m_unk70 = 0.0f; + m_unk10 = 0; + m_unk74 = 0; } diff --git a/LEGO1/legoactor.h b/LEGO1/legoactor.h index 4c943cf6..f4096b06 100644 --- a/LEGO1/legoactor.h +++ b/LEGO1/legoactor.h @@ -23,15 +23,18 @@ class LegoActor : public LegoEntity { return !strcmp(name, LegoActor::ClassName()) || LegoEntity::IsA(name); } - virtual void VTable0x50(); // vtable+0x50 - virtual void VTable0x54(); // vtable+0x54 - virtual void VTable0x58(); // vtable+0x58 - virtual void VTable0x5c(); // vtable+0x5c - virtual void VTable0x60(); // vtable+0x60 - virtual void VTable0x64(); // vtable+0x64 + virtual MxFloat VTable0x50(); // vtable+0x50 + virtual void VTable0x54(MxFloat p_unk); // vtable+0x54 + virtual void VTable0x58(MxFloat p_unk); // vtable+0x58 + virtual MxFloat VTable0x5c(); // vtable+0x5c + virtual undefined VTable0x60(); // vtable+0x60 + virtual void VTable0x64(undefined p_unk); // vtable+0x64 private: - undefined unk68[0x10]; + MxFloat m_unk68; + undefined4 m_unk6c; + MxFloat m_unk70; + undefined m_unk74; }; #endif // LEGOACTOR_H diff --git a/LEGO1/legobuildingmanager.cpp b/LEGO1/legobuildingmanager.cpp index 3c6b26b1..b4450e2e 100644 --- a/LEGO1/legobuildingmanager.cpp +++ b/LEGO1/legobuildingmanager.cpp @@ -3,10 +3,10 @@ // 0x100f37cc int g_buildingManagerConfig = 1; -// OFFSET: LEGO1 0x1002f8c0 STUB +// OFFSET: LEGO1 0x1002f8c0 LegoBuildingManager::LegoBuildingManager() { - // TODO + Init(); } // OFFSET: LEGO1 0x1002f960 STUB diff --git a/LEGO1/legoentity.cpp b/LEGO1/legoentity.cpp index 19820154..2a9b4b76 100644 --- a/LEGO1/legoentity.cpp +++ b/LEGO1/legoentity.cpp @@ -3,6 +3,7 @@ #include "define.h" #include "legoomni.h" #include "legoutil.h" +#include "legoworld.h" DECOMP_SIZE_ASSERT(LegoEntity, 0x68) @@ -60,12 +61,12 @@ void LegoEntity::Destroy(MxBool p_fromDestructor) Init(); } -// OFFSET: LEGO1 0x10010880 STUB +// OFFSET: LEGO1 0x10010880 void LegoEntity::SetWorld() { LegoWorld* world = GetCurrentWorld(); if (world != NULL && world != (LegoWorld*) this) { - // TODO: world->AddEntity(this); + world->VTable0x58(this); } } diff --git a/LEGO1/legoentity.h b/LEGO1/legoentity.h index 1da99f3b..c0a16c32 100644 --- a/LEGO1/legoentity.h +++ b/LEGO1/legoentity.h @@ -13,10 +13,7 @@ class LegoEntity : public MxEntity { public: // Inlined at 0x100853f7 - inline LegoEntity() - { - // TODO - } + inline LegoEntity() { Init(); } __declspec(dllexport) virtual ~LegoEntity() override; // vtable+0x0 diff --git a/LEGO1/legoentitypresenter.cpp b/LEGO1/legoentitypresenter.cpp index a8d4bc8b..f3ac23c5 100644 --- a/LEGO1/legoentitypresenter.cpp +++ b/LEGO1/legoentitypresenter.cpp @@ -1,19 +1,47 @@ #include "legoentitypresenter.h" +#include "legoomni.h" +#include "legovideomanager.h" + +DECOMP_SIZE_ASSERT(LegoEntityPresenter, 0x50); + // OFFSET: LEGO1 0x10053440 LegoEntityPresenter::LegoEntityPresenter() { Init(); } -// OFFSET: LEGO1 0x100535d0 STUB -LegoEntityPresenter::~LegoEntityPresenter() -{ - // TODO -} - -// OFFSET: LEGO1 0x100535c0 STUB +// OFFSET: LEGO1 0x100535c0 void LegoEntityPresenter::Init() { - // TODO + m_unk4c = 0; +} + +// OFFSET: LEGO1 0x100535d0 +LegoEntityPresenter::~LegoEntityPresenter() +{ + Destroy(TRUE); +} + +// OFFSET: LEGO1 0x10053630 +undefined4 LegoEntityPresenter::vtable6c(undefined4 p_unknown) +{ + m_unk4c = p_unknown; + return 0; +} + +// OFFSET: LEGO1 0x10053640 +void LegoEntityPresenter::Destroy(MxBool p_fromDestructor) +{ + if (VideoManager()) { + VideoManager()->RemovePresenter(*this); + } + + Init(); +} + +// OFFSET: LEGO1 0x10053670 +void LegoEntityPresenter::Destroy() +{ + Destroy(FALSE); } diff --git a/LEGO1/legoentitypresenter.h b/LEGO1/legoentitypresenter.h index 30360919..2ee9f701 100644 --- a/LEGO1/legoentitypresenter.h +++ b/LEGO1/legoentitypresenter.h @@ -4,6 +4,7 @@ #include "mxcompositepresenter.h" // VTABLE 0x100d8398 +// SIZE 0x50 class LegoEntityPresenter : public MxCompositePresenter { public: LegoEntityPresenter(); @@ -22,8 +23,14 @@ class LegoEntityPresenter : public MxCompositePresenter { return !strcmp(name, LegoEntityPresenter::ClassName()) || MxCompositePresenter::IsA(name); } + virtual void Destroy() override; // vtable+0x38 + virtual void Init(); // vtable+0x68 + virtual undefined4 vtable6c(undefined4 p_unknown); // vtable+0x6c + private: - void Init(); + void Destroy(MxBool p_fromDestructor); + + undefined4 m_unk4c; }; #endif // LEGOENTITYPRESENTER_H diff --git a/LEGO1/legoeventnotificationparam.cpp b/LEGO1/legoeventnotificationparam.cpp index 70e0de00..b6abd2c4 100644 --- a/LEGO1/legoeventnotificationparam.cpp +++ b/LEGO1/legoeventnotificationparam.cpp @@ -2,4 +2,4 @@ #include "decomp.h" -DECOMP_SIZE_ASSERT(LegoEventNotificationParam, 0x1c); +DECOMP_SIZE_ASSERT(LegoEventNotificationParam, 0x20); diff --git a/LEGO1/legoeventnotificationparam.h b/LEGO1/legoeventnotificationparam.h index f53fb822..3916771d 100644 --- a/LEGO1/legoeventnotificationparam.h +++ b/LEGO1/legoeventnotificationparam.h @@ -7,16 +7,28 @@ // VTABLE 0x100d6aa0 class LegoEventNotificationParam : public MxNotificationParam { public: - inline LegoEventNotificationParam() : MxNotificationParam((MxParamType) 0, NULL) {} + inline LegoEventNotificationParam() : MxNotificationParam(PARAM_NONE, NULL) {} + inline LegoEventNotificationParam( + NotificationId p_type, + MxCore* p_sender, + MxU8 p_modifier, + MxS32 p_x, + MxS32 p_y, + MxU8 p_key + ) + : MxNotificationParam(p_type, p_sender), m_modifier(p_modifier), m_x(p_x), m_y(p_y), m_key(p_key), m_unk1c(0) + { + } virtual ~LegoEventNotificationParam() override {} // vtable+0x0 (scalar deleting destructor) - inline MxU8 GetKey() { return m_key; } + inline MxU8 GetKey() const { return m_key; } protected: MxU8 m_modifier; // 0x0c MxS32 m_x; // 0x10 MxS32 m_y; // 0x14 MxU8 m_key; // 0x18 + MxU32 m_unk1c; // 0x1c }; #endif // LEGOEVENTNOTIFICATIONPARAM_H diff --git a/LEGO1/legogamestate.cpp b/LEGO1/legogamestate.cpp index 0473a07f..e95a7470 100644 --- a/LEGO1/legogamestate.cpp +++ b/LEGO1/legogamestate.cpp @@ -2,6 +2,7 @@ #include "infocenterstate.h" #include "legoomni.h" +#include "legoroi.h" #include "legostate.h" #include "legostream.h" #include "mxobjectfactory.h" @@ -43,6 +44,8 @@ extern const char* s_endOfVariables; LegoGameState::LegoGameState() { // TODO + SetROIHandlerFunction(); + m_stateCount = 0; m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68"); VariableTable()->SetVariable(m_backgroundColor); @@ -57,10 +60,22 @@ LegoGameState::LegoGameState() SerializeScoreHistory(1); } -// OFFSET: LEGO1 0x10039720 STUB +// OFFSET: LEGO1 0x10039720 LegoGameState::~LegoGameState() { - // TODO + LegoROI::SetSomeHandlerFunction(NULL); + + if (m_stateCount) { + for (MxS16 i = 0; i < m_stateCount; i++) { + LegoState* state = m_stateArray[i]; + if (state) + delete state; + } + + delete[] m_stateArray; + } + + delete[] m_savePath; } // OFFSET: LEGO1 0x10039c60 STUB @@ -149,6 +164,12 @@ void LegoGameState::SerializeScoreHistory(MxS16 p) // TODO } +// OFFSET: LEGO1 0x1003cea0 +void LegoGameState::SetSomeEnumState(undefined4 p_state) +{ + m_unk10 = p_state; +} + // OFFSET: LEGO1 0x10039f00 void LegoGameState::SetSavePath(char* p_savePath) { @@ -163,6 +184,33 @@ void LegoGameState::SetSavePath(char* p_savePath) m_savePath = NULL; } +// OFFSET: LEGO1 0x1003bac0 +void LegoGameState::SetROIHandlerFunction() +{ + LegoROI::SetSomeHandlerFunction(&ROIHandlerFunction); +} + +// OFFSET: LEGO1 0x1003bad0 +MxBool ROIHandlerFunction(char* p_input, char* p_output, MxU32 p_copyLen) +{ + if (p_output != NULL && p_copyLen != 0 && + (strnicmp(p_input, "INDIR-F-", strlen("INDIR-F-")) == 0 || + strnicmp(p_input, "INDIR-G-", strlen("INDIR-F-")) == 0)) { + + char buf[256]; + sprintf(buf, "c_%s", &p_input[strlen("INDIR-F-")]); + + const char* value = VariableTable()->GetVariable(buf); + if (value != NULL) { + strncpy(p_output, value, p_copyLen); + p_output[p_copyLen - 1] = '\0'; + return TRUE; + } + } + + return FALSE; +} + // OFFSET: LEGO1 0x1003bbb0 LegoState* LegoGameState::GetState(COMPAT_CONST char* p_stateName) { diff --git a/LEGO1/legogamestate.h b/LEGO1/legogamestate.h index 03455a37..82ff4d9c 100644 --- a/LEGO1/legogamestate.h +++ b/LEGO1/legogamestate.h @@ -37,9 +37,12 @@ class LegoGameState { inline MxU32 GetUnknown10() { return m_unk10; } inline void SetUnknown424(undefined4 p_unk424) { m_unk424 = p_unk424; } + void SetSomeEnumState(undefined4 p_state); + private: void RegisterState(LegoState* p_state); MxResult WriteEndOfVariables(LegoStream* p_stream); + void SetROIHandlerFunction(); private: char* m_savePath; // 0x0 @@ -58,4 +61,6 @@ class LegoGameState { undefined4 m_unk42c; }; +MxBool ROIHandlerFunction(char* p_0, char* p_output, MxU32 p_copyLen); + #endif // LEGOGAMESTATE_H diff --git a/LEGO1/legoinputmanager.cpp b/LEGO1/legoinputmanager.cpp index 0fd1d22d..e9a82cc6 100644 --- a/LEGO1/legoinputmanager.cpp +++ b/LEGO1/legoinputmanager.cpp @@ -9,10 +9,10 @@ DECOMP_SIZE_ASSERT(LegoInputManager, 0x338); // OFFSET: LEGO1 0x1005b790 LegoInputManager::LegoInputManager() { - m_eventQueue = NULL; + m_unk0x5c = NULL; m_world = NULL; m_camera = NULL; - m_unk0x68 = NULL; + m_eventQueue = NULL; m_unk0x80 = 0; m_timer = 0; m_unk0x6c = 0; @@ -36,7 +36,7 @@ LegoInputManager::LegoInputManager() // OFFSET: LEGO1 0x1005b8b0 STUB MxResult LegoInputManager::Tickle() { - // TODO + ProcessEvents(); return SUCCESS; } @@ -46,19 +46,28 @@ LegoInputManager::~LegoInputManager() Destroy(); } +// OFFSET: LEGO1 0x1005b960 +MxResult LegoInputManager::Create(HWND p_hwnd) +{ + // TODO + if (m_eventQueue == NULL) + m_eventQueue = new LegoEventQueue(); + return SUCCESS; +} + // OFFSET: LEGO1 0x1005bfe0 void LegoInputManager::Destroy() { ReleaseDX(); + if (m_unk0x5c) + delete m_unk0x5c; + m_unk0x5c = NULL; + if (m_eventQueue) delete m_eventQueue; m_eventQueue = NULL; - if (m_unk0x68) - delete m_unk0x68; - m_unk0x68 = NULL; - if (m_controlManager) delete m_controlManager; } @@ -215,10 +224,34 @@ void LegoInputManager::ClearWorld() m_world = NULL; } -// OFFSET: LEGO1 0x1005c740 STUB -void LegoInputManager::QueueEvent(NotificationId id, unsigned char p2, MxLong p3, MxLong p4, unsigned char p5) +// OFFSET: LEGO1 0x1005c740 +void LegoInputManager::QueueEvent(NotificationId p_id, MxU8 p_modifier, MxLong p_x, MxLong p_y, MxU8 p_key) +{ + LegoEventNotificationParam param = LegoEventNotificationParam(p_id, NULL, p_modifier, p_x, p_y, p_key); + + if (((!m_unk0x88) || ((m_unk0x335 && (param.GetType() == c_notificationButtonDown)))) || + ((m_unk0x336 && (p_key == ' ')))) { + ProcessOneEvent(param); + } +} + +// OFFSET: LEGO1 0x1005c820 +void LegoInputManager::ProcessEvents() +{ + MxAutoLocker lock(&m_criticalSection); + + LegoEventNotificationParam event; + while (m_eventQueue->Dequeue(event)) { + if (ProcessOneEvent(event)) + break; + } +} + +// OFFSET: LEGO1 0x1005c9c0 STUB +MxBool LegoInputManager::ProcessOneEvent(LegoEventNotificationParam& p_param) { // TODO + return FALSE; } // OFFSET: LEGO1 0x1005cfb0 diff --git a/LEGO1/legoinputmanager.h b/LEGO1/legoinputmanager.h index d0059605..c583a64a 100644 --- a/LEGO1/legoinputmanager.h +++ b/LEGO1/legoinputmanager.h @@ -6,21 +6,14 @@ #include "legoworld.h" #include "mxlist.h" #include "mxpresenter.h" +#include "mxqueue.h" #include -enum NotificationId { - NONE = 0, - KEYDOWN = 7, - MOUSEUP = 8, - MOUSEDOWN = 9, - MOUSEMOVE = 10, - TIMER = 15 -}; - class LegoControlManager; -// TODO Really a MxQueue, but we don't have one of those -class LegoEventQueue : public MxList {}; + +// VTABLE 0x100d8800 +class LegoEventQueue : public MxQueue {}; // VTABLE 0x100d8760 // SIZE 0x338 @@ -29,12 +22,13 @@ class LegoInputManager : public MxPresenter { LegoInputManager(); virtual ~LegoInputManager() override; - __declspec(dllexport) void QueueEvent(NotificationId id, unsigned char p2, MxLong p3, MxLong p4, unsigned char p5); + __declspec(dllexport) void QueueEvent(NotificationId p_id, MxU8 p_modifier, MxLong p_x, MxLong p_y, MxU8 p_key); __declspec(dllexport) void Register(MxCore*); __declspec(dllexport) void UnRegister(MxCore*); virtual MxResult Tickle() override; // vtable+0x8 + MxResult Create(HWND p_hwnd); void Destroy(); void CreateAndAcquireKeyboard(HWND hwnd); void ReleaseDX(); @@ -53,12 +47,15 @@ class LegoInputManager : public MxPresenter { inline LegoControlManager* GetControlManager() { return m_controlManager; } inline LegoWorld* GetWorld() { return m_world; } + void ProcessEvents(); + MxBool ProcessOneEvent(LegoEventNotificationParam& p_param); + // private: MxCriticalSection m_criticalSection; - LegoEventQueue* m_eventQueue; // list or hash table + MxList* m_unk0x5c; // list or hash table LegoCameraController* m_camera; LegoWorld* m_world; - MxList* m_unk0x68; // list or hash table + LegoEventQueue* m_eventQueue; // +0x68 undefined4 m_unk0x6c; undefined4 m_unk0x70; undefined4 m_unk0x74; @@ -83,4 +80,37 @@ class LegoInputManager : public MxPresenter { MxBool m_unk0x336; }; +// OFFSET: LEGO1 0x1005bb80 TEMPLATE +// MxListParent::Compare + +// OFFSET: LEGO1 0x1005bc30 TEMPLATE +// MxListParent::Destroy + +// OFFSET: LEGO1 0x1005bc80 TEMPLATE +// MxList::~MxList + +// OFFSET: LEGO1 0x1005bd50 TEMPLATE +// MxListParent::`scalar deleting destructor' + +// OFFSET: LEGO1 0x1005bdc0 TEMPLATE +// MxList::`scalar deleting destructor' + +// OFFSET: LEGO1 0x1005beb0 TEMPLATE +// LegoEventQueue::`scalar deleting destructor' + +// OFFSET: LEGO1 0x1005bf70 TEMPLATE +// MxQueue::`scalar deleting destructor' + +// OFFSET: LEGO1 0x1005d010 TEMPLATE +// MxListEntry::GetValue + +// VTABLE 0x100d87e8 TEMPLATE +// class MxQueue + +// VTABLE 0x100d87d0 TEMPLATE +// class MxList + +// VTABLE 0x100d87b8 TEMPLATE +// class MxListParent + #endif // LEGOINPUTMANAGER_H diff --git a/LEGO1/legonavcontroller.cpp b/LEGO1/legonavcontroller.cpp index 5b5fc38d..eefbbed1 100644 --- a/LEGO1/legonavcontroller.cpp +++ b/LEGO1/legonavcontroller.cpp @@ -1,5 +1,6 @@ #include "legonavcontroller.h" +#include "legoinputmanager.h" #include "legoomni.h" #include "legoutil.h" #include "legovideomanager.h" @@ -106,18 +107,14 @@ LegoNavController::LegoNavController() MxTimer* timer = Timer(); this->m_time = timer->GetTime(); - // TODO: InputManager() - // LegoInputManager* inputManager = InputManager(); - // inputManager->Register(this); + InputManager()->Register(this); } -// TODO: InputManager() // OFFSET: LEGO1 0x10054c30 -// LegoNavController::~LegoNavController() -// { -// LegoInputManager* inputManager = InputManager(); -// inputManager->UnRegister(this); -// } +LegoNavController::~LegoNavController() +{ + InputManager()->UnRegister(this); +} // OFFSET: LEGO1 0x10054ca0 void LegoNavController::SetControlMax(int p_hMax, int p_vMax) diff --git a/LEGO1/legonavcontroller.h b/LEGO1/legonavcontroller.h index 65b9f5ab..f7cfa3da 100644 --- a/LEGO1/legonavcontroller.h +++ b/LEGO1/legonavcontroller.h @@ -37,7 +37,7 @@ class LegoNavController : public MxCore { ); LegoNavController(); - // virtual ~LegoNavController(); // vtable+0x0 + virtual ~LegoNavController() override; // vtable+0x0 // OFFSET: LEGO1 0x10054b80 inline const char* ClassName() const override // vtable+0xc diff --git a/LEGO1/legoobjectfactory.cpp b/LEGO1/legoobjectfactory.cpp index b26686df..db59ad5e 100644 --- a/LEGO1/legoobjectfactory.cpp +++ b/LEGO1/legoobjectfactory.cpp @@ -31,8 +31,8 @@ MxCore* LegoObjectFactory::Create(const char* p_name) } } -// OFFSET: LEGO1 0x1000fb30 STUB +// OFFSET: LEGO1 0x1000fb30 void LegoObjectFactory::Destroy(MxCore* p_object) { - // TODO + delete p_object; } diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index a37d9776..0a9b6b31 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -1,18 +1,110 @@ #include "legoomni.h" +#include "gifmanager.h" +#include "legoanimationmanager.h" +#include "legobuildingmanager.h" #include "legogamestate.h" #include "legoinputmanager.h" #include "legoobjectfactory.h" +#include "legoplantmanager.h" +#include "legosoundmanager.h" #include "legoutil.h" +#include "legovideomanager.h" #include "legoworld.h" +#include "mxautolocker.h" #include "mxbackgroundaudiomanager.h" #include "mxdsfile.h" +#include "mxomnicreateflags.h" +#include "mxomnicreateparam.h" +#include "mxticklemanager.h" +#include "mxtransitionmanager.h" + +// 0x100f451c +MxAtomId* g_copterScript = NULL; + +// 0x100f4520 +MxAtomId* g_dunecarScript = NULL; + +// 0x100f4524 +MxAtomId* g_jetskiScript = NULL; + +// 0x100f4528 +MxAtomId* g_racecarScript = NULL; + +// 0x100f452c +MxAtomId* g_carraceScript = NULL; + +// 0x100f4530 +MxAtomId* g_carracerScript = NULL; + +// 0x100f4534 +MxAtomId* g_jetraceScript = NULL; + +// 0x100f4538 +MxAtomId* g_jetracerScript = NULL; + +// 0x100f453c +MxAtomId* g_isleScript = NULL; + +// 0x100f4540 +MxAtomId* g_elevbottScript = NULL; + +// 0x100f4544 +MxAtomId* g_infodoorScript = NULL; + +// 0x100f4548 +MxAtomId* g_infomainScript = NULL; + +// 0x100f454c +MxAtomId* g_infoscorScript = NULL; + +// 0x100f4550 +MxAtomId* g_regbookScript = NULL; + +// 0x100f4554 +MxAtomId* g_histbookScript = NULL; + +// 0x100f4558 +MxAtomId* g_hospitalScript = NULL; + +// 0x100f455c +MxAtomId* g_policeScript = NULL; + +// 0x100f4560 +MxAtomId* g_garageScript = NULL; + +// 0x100f4564 +MxAtomId* g_act2mainScript = NULL; + +// 0x100f4568 +MxAtomId* g_act3Script = NULL; + +// 0x100f456c +MxAtomId* g_jukeboxScript = NULL; + +// 0x100f4570 +MxAtomId* g_pz5Script = NULL; + +// 0x100f4574 +MxAtomId* g_introScript = NULL; + +// 0x100f4578 +MxAtomId* g_testScript = NULL; + +// 0x100f457c +MxAtomId* g_jukeboxwScript = NULL; + +// 0x100f4580c +MxAtomId* g_sndAnimScript = NULL; + +// 0x100f4584 +MxAtomId* g_creditsScript = NULL; // 0x100f4588 MxAtomId* g_nocdSourceName = NULL; -// 0x100f456c -MxAtomId* g_jukeboxScript = NULL; +// 0x100f6718 +const char* g_current = "current"; // 0x101020e8 void (*g_omniUserMessage)(const char*, int); @@ -42,6 +134,13 @@ 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&) { @@ -212,12 +311,29 @@ GifManager* GetGifManager() return LegoOmni::GetInstance()->GetGifManager(); } +// OFFSET: LEGO1 0x100158e0 +MxDSAction& GetCurrentAction() +{ + return LegoOmni::GetInstance()->GetCurrentAction(); +} + // OFFSET: LEGO1 0x10015900 MxTransitionManager* TransitionManager() { return LegoOmni::GetInstance()->GetTransitionManager(); } +// OFFSET: LEGO1 0x10015910 +void PlayMusic(MxU32 p_index) +{ + // index is the entityid of the music in jukebox.si + MxDSAction action; + action.SetAtomId(*g_jukeboxScript); + action.SetObjectId(p_index); + + LegoOmni::GetInstance()->GetBackgroundAudioManager()->PlayMusic(action, 5, 4); +} + // OFFSET: LEGO1 0x100c0280 MxDSObject* CreateStreamObject(MxDSFile* p_file, MxS16 p_ofs) { @@ -259,7 +375,7 @@ const char* GetNoCD_SourceName() return g_nocdSourceName->GetInternal(); } -// OFFSET: LEGO1 0x1005b5f0 +// OFFSET: LEGO1 0x1005b5f0 STUB MxLong LegoOmni::Notify(MxParam& p) { // TODO @@ -302,16 +418,83 @@ void LegoOmni::Init() m_transitionManager = NULL; } -// OFFSET: LEGO1 0x10058e70 STUB +// OFFSET: LEGO1 0x1001a700 STUB +void FUN_1001a700() +{ + // TODO +} + +// OFFSET: LEGO1 0x10058e70 MxResult LegoOmni::Create(MxOmniCreateParam& p) { - MxOmni::Create(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(); - m_gameState = new LegoGameState(); - m_bkgAudioManager = new MxBackgroundAudioManager(); + if (m_objectFactory == NULL) + return FAILURE; - return SUCCESS; + 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 @@ -337,18 +520,33 @@ MxResult LegoOmni::DeleteObject(MxDSAction& ds) return FAILURE; } -// OFFSET: LEGO1 0x1005b3c0 STUB +// OFFSET: LEGO1 0x1005b3c0 MxBool LegoOmni::DoesEntityExist(MxDSAction& ds) { - // TODO - return TRUE; + if (MxOmni::DoesEntityExist(ds)) { + if (FindByEntityIdOrAtomId(ds.GetAtomId(), ds.GetObjectId()) == NULL) { + return TRUE; + } + } + return FALSE; } -// OFFSET: LEGO1 0x1005b2f0 STUB -int LegoOmni::Vtable0x30(char*, int, MxCore*) +// OFFSET: LEGO1 0x1005b2f0 +MxEntity* LegoOmni::FindWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter) { - // TODO - return 0; + 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 @@ -371,3 +569,99 @@ void LegoOmni::StopTimer() MxOmni::StopTimer(); SetAppCursor(0); } + +// OFFSET: LEGO1 0x100528e0 +void RegisterScripts() +{ + g_copterScript = new MxAtomId("\\lego\\scripts\\build\\copter", LookupMode_LowerCase2); + g_dunecarScript = new MxAtomId("\\lego\\scripts\\build\\dunecar", LookupMode_LowerCase2); + g_jetskiScript = new MxAtomId("\\lego\\scripts\\build\\jetski", LookupMode_LowerCase2); + g_racecarScript = new MxAtomId("\\lego\\scripts\\build\\racecar", LookupMode_LowerCase2); + g_carraceScript = new MxAtomId("\\lego\\scripts\\race\\carrace", LookupMode_LowerCase2); + g_carracerScript = new MxAtomId("\\lego\\scripts\\race\\carracer", LookupMode_LowerCase2); + g_jetraceScript = new MxAtomId("\\lego\\scripts\\race\\jetrace", LookupMode_LowerCase2); + g_jetracerScript = new MxAtomId("\\lego\\scripts\\race\\jetracer", LookupMode_LowerCase2); + g_isleScript = new MxAtomId("\\lego\\scripts\\isle\\isle", LookupMode_LowerCase2); + g_elevbottScript = new MxAtomId("\\lego\\scripts\\infocntr\\elevbott", LookupMode_LowerCase2); + g_infodoorScript = new MxAtomId("\\lego\\scripts\\infocntr\\infodoor", LookupMode_LowerCase2); + g_infomainScript = new MxAtomId("\\lego\\scripts\\infocntr\\infomain", LookupMode_LowerCase2); + g_infoscorScript = new MxAtomId("\\lego\\scripts\\infocntr\\infoscor", LookupMode_LowerCase2); + g_regbookScript = new MxAtomId("\\lego\\scripts\\infocntr\\regbook", LookupMode_LowerCase2); + g_histbookScript = new MxAtomId("\\lego\\scripts\\infocntr\\histbook", LookupMode_LowerCase2); + g_hospitalScript = new MxAtomId("\\lego\\scripts\\hospital\\hospital", LookupMode_LowerCase2); + g_policeScript = new MxAtomId("\\lego\\scripts\\police\\police", LookupMode_LowerCase2); + g_garageScript = new MxAtomId("\\lego\\scripts\\garage\\garage", LookupMode_LowerCase2); + g_act2mainScript = new MxAtomId("\\lego\\scripts\\act2\\act2main", LookupMode_LowerCase2); + g_act3Script = new MxAtomId("\\lego\\scripts\\act3\\act3", LookupMode_LowerCase2); + g_jukeboxScript = new MxAtomId("\\lego\\scripts\\isle\\jukebox", LookupMode_LowerCase2); + g_pz5Script = new MxAtomId("\\lego\\scripts\\isle\\pz5", LookupMode_LowerCase2); + g_introScript = new MxAtomId("\\lego\\scripts\\intro", LookupMode_LowerCase2); + g_testScript = new MxAtomId("\\lego\\scripts\\test\\test", LookupMode_LowerCase2); + g_jukeboxwScript = new MxAtomId("\\lego\\scripts\\isle\\jukeboxw", LookupMode_LowerCase2); + g_sndAnimScript = new MxAtomId("\\lego\\scripts\\sndanim", LookupMode_LowerCase2); + g_creditsScript = new MxAtomId("\\lego\\scripts\\credits", LookupMode_LowerCase2); + g_nocdSourceName = new MxAtomId("\\lego\\scripts\\nocd", LookupMode_LowerCase2); +} + +// OFFSET: LEGO1 0x100530c0 +void UnregisterScripts() +{ + delete g_copterScript; + delete g_dunecarScript; + delete g_jetskiScript; + delete g_racecarScript; + delete g_carraceScript; + delete g_carracerScript; + delete g_jetraceScript; + delete g_jetracerScript; + delete g_isleScript; + delete g_elevbottScript; + delete g_infodoorScript; + delete g_infomainScript; + delete g_infoscorScript; + delete g_regbookScript; + delete g_histbookScript; + delete g_hospitalScript; + delete g_policeScript; + delete g_garageScript; + delete g_act2mainScript; + delete g_act3Script; + delete g_jukeboxScript; + delete g_pz5Script; + delete g_introScript; + delete g_testScript; + delete g_jukeboxwScript; + delete g_sndAnimScript; + delete g_creditsScript; + delete g_nocdSourceName; + + g_copterScript = NULL; + g_dunecarScript = NULL; + g_jetskiScript = NULL; + g_racecarScript = NULL; + g_carraceScript = NULL; + g_carracerScript = NULL; + g_jetraceScript = NULL; + g_jetracerScript = NULL; + g_isleScript = NULL; + g_elevbottScript = NULL; + g_infodoorScript = NULL; + g_infomainScript = NULL; + g_infoscorScript = NULL; + g_regbookScript = NULL; + g_histbookScript = NULL; + g_hospitalScript = NULL; + g_policeScript = NULL; + g_garageScript = NULL; + g_act2mainScript = NULL; + g_act3Script = NULL; + g_jukeboxScript = NULL; + g_pz5Script = NULL; + g_introScript = NULL; + g_testScript = NULL; + g_testScript = NULL; + g_jukeboxwScript = NULL; + g_sndAnimScript = NULL; + g_creditsScript = NULL; + g_nocdSourceName = NULL; +} diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index b8b9c1d5..3406bd6c 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -26,6 +26,35 @@ class MxBackgroundAudioManager; class MxDSFile; class MxTransitionManager; +extern MxAtomId* g_copterScript; +extern MxAtomId* g_dunecarScript; +extern MxAtomId* g_jetskiScript; +extern MxAtomId* g_racecarScript; +extern MxAtomId* g_carraceScript; +extern MxAtomId* g_carracerScript; +extern MxAtomId* g_jetraceScript; +extern MxAtomId* g_jetracerScript; +extern MxAtomId* g_isleScript; +extern MxAtomId* g_elevbottScript; +extern MxAtomId* g_infodoorScript; +extern MxAtomId* g_infomainScript; +extern MxAtomId* g_infoscorScript; +extern MxAtomId* g_regbookScript; +extern MxAtomId* g_histbookScript; +extern MxAtomId* g_hospitalScript; +extern MxAtomId* g_policeScript; +extern MxAtomId* g_garageScript; +extern MxAtomId* g_act2mainScript; +extern MxAtomId* g_act3Script; +extern MxAtomId* g_jukeboxScript; +extern MxAtomId* g_pz5Script; +extern MxAtomId* g_introScript; +extern MxAtomId* g_testScript; +extern MxAtomId* g_jukeboxwScript; +extern MxAtomId* g_sndAnimScript; +extern MxAtomId* g_creditsScript; +extern MxAtomId* g_nocdSourceName; + // VTABLE 0x100d8638 // SIZE: 0x140 class LegoOmni : public MxOmni { @@ -54,16 +83,18 @@ class LegoOmni : public MxOmni { return !strcmp(name, LegoOmni::ClassName()) || MxOmni::IsA(name); } - virtual void Init() override; // vtable+14 - virtual MxResult Create(MxOmniCreateParam& p) override; // vtable+18 - virtual void Destroy() override; // vtable+1c - virtual MxResult Start(MxDSAction* action) override; // vtable+20 - virtual MxResult DeleteObject(MxDSAction& ds) override; // vtable+24 - virtual MxBool DoesEntityExist(MxDSAction& ds) override; // vtable+28 - virtual int Vtable0x30(char*, int, MxCore*) override; // vtable+30 - virtual void NotifyCurrentEntity(MxNotificationParam* p_param) override; // vtable+34 - virtual void StartTimer() override; // vtable+38 - virtual void StopTimer() override; // vtable+3c + virtual void Init() override; // vtable+14 + virtual MxResult Create(MxOmniCreateParam& p) override; // vtable+18 + virtual void Destroy() override; // vtable+1c + virtual MxResult Start(MxDSAction* action) override; // vtable+20 + virtual MxResult DeleteObject(MxDSAction& ds) override; // vtable+24 + virtual MxBool DoesEntityExist(MxDSAction& ds) override; // vtable+28 + virtual MxEntity* FindWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter) override; // vtable+30 + virtual void NotifyCurrentEntity(MxNotificationParam* p_param) override; // vtable+34 + virtual void StartTimer() override; // vtable+38 + virtual void StopTimer() override; // vtable+3c + + LegoEntity* FindByEntityIdOrAtomId(const MxAtomId& p_atom, MxS32 p_entityid); LegoVideoManager* GetVideoManager() { return (LegoVideoManager*) m_videoManager; } LegoSoundManager* GetSoundManager() { return (LegoSoundManager*) m_soundManager; } @@ -79,6 +110,7 @@ class LegoOmni : public MxOmni { LegoGameState* GetGameState() { return m_gameState; } MxBackgroundAudioManager* GetBackgroundAudioManager() { return m_bkgAudioManager; } MxTransitionManager* GetTransitionManager() { return m_transitionManager; } + MxDSAction& GetCurrentAction() { return m_action; } private: undefined4 m_unk68; @@ -124,5 +156,9 @@ LegoPlantManager* PlantManager(); MxBool KeyValueStringParse(char*, const char*, const char*); LegoWorld* GetCurrentWorld(); GifManager* GetGifManager(); +MxDSAction& GetCurrentAction(); + +void RegisterScripts(); +void UnregisterScripts(); #endif // LEGOOMNI_H diff --git a/LEGO1/legoroi.cpp b/LEGO1/legoroi.cpp index f177cd8b..a458fa60 100644 --- a/LEGO1/legoroi.cpp +++ b/LEGO1/legoroi.cpp @@ -1,16 +1,96 @@ #include "legoroi.h" -// 0x10101368 -int g_roiConfig = 100; +#include -// OFFSET: LEGO1 0x100a9e10 -void LegoROI::SetDisplayBB(int p_displayBB) -{ - // Intentionally empty function -} +// SIZE 0x14 +typedef struct { + const char* m_name; + MxS32 m_red; + MxS32 m_green; + MxS32 m_blue; + MxS32 m_unk10; +} ROIColorAlias; + +// 0x100dbe28 +const double g_normalizeByteToFloat = 1.0 / 255; + +// 0x101011b0 +ROIColorAlias g_roiColorAliases[22] = { + {"lego black", 0x21, 0x21, 0x21, 0}, {"lego black f", 0x21, 0x21, 0x21, 0}, + {"lego black flat", 0x21, 0x21, 0x21, 0}, {"lego blue", 0x00, 0x54, 0x8c, 0}, + {"lego blue flat", 0x00, 0x54, 0x8c, 0}, {"lego brown", 0x4a, 0x23, 0x1a, 0}, + {"lego brown flt", 0x4a, 0x23, 0x1a, 0}, {"lego brown flat", 0x4a, 0x23, 0x1a, 0}, + {"lego drk grey", 0x40, 0x40, 0x40, 0}, {"lego drk grey flt", 0x40, 0x40, 0x40, 0}, + {"lego dk grey flt", 0x40, 0x40, 0x40, 0}, {"lego green", 0x00, 0x78, 0x2d, 0}, + {"lego green flat", 0x00, 0x78, 0x2d, 0}, {"lego lt grey", 0x82, 0x82, 0x82, 0}, + {"lego lt grey flt", 0x82, 0x82, 0x82, 0}, {"lego lt grey fla", 0x82, 0x82, 0x82, 0}, + {"lego red", 0xcb, 0x12, 0x20, 0}, {"lego red flat", 0xcb, 0x12, 0x20, 0}, + {"lego white", 0xfa, 0xfa, 0xfa, 0}, {"lego white flat", 0xfa, 0xfa, 0xfa, 0}, + {"lego yellow", 0xff, 0xb9, 0x00, 0}, {"lego yellow flat", 0xff, 0xb9, 0x00, 0}, +}; + +// 0x10101368 +MxS32 g_roiConfig = 100; + +// 0x101013ac +ROIHandler g_someHandlerFunction = NULL; // OFFSET: LEGO1 0x100a81c0 -void LegoROI::configureLegoROI(int p_roi) +void LegoROI::configureLegoROI(MxS32 p_roi) { g_roiConfig = p_roi; } + +// OFFSET: LEGO1 0x100a9bf0 +MxBool LegoROI::CallTheHandlerFunction( + char* p_param, + MxFloat& p_red, + MxFloat& p_green, + MxFloat& p_blue, + MxFloat& p_other +) +{ + // TODO + if (p_param == NULL) + return FALSE; + + if (g_someHandlerFunction) { + char buf[32]; + if (g_someHandlerFunction(p_param, buf, 32)) + p_param = buf; + } + + return ColorAliasLookup(p_param, p_red, p_green, p_blue, p_other); +} + +// OFFSET: LEGO1 0x100a9c50 +MxBool LegoROI::ColorAliasLookup(char* p_param, MxFloat& p_red, MxFloat& p_green, MxFloat& p_blue, MxFloat& p_other) +{ + // TODO: this seems awfully hacky for these devs. is there a dynamic way + // to represent `the end of this array` that would improve this? + MxU32 i = 0; + do { + if (strcmpi(g_roiColorAliases[i].m_name, p_param) == 0) { + p_red = g_roiColorAliases[i].m_red * g_normalizeByteToFloat; + p_green = g_roiColorAliases[i].m_green * g_normalizeByteToFloat; + p_blue = g_roiColorAliases[i].m_blue * g_normalizeByteToFloat; + p_other = g_roiColorAliases[i].m_unk10 * g_normalizeByteToFloat; + return TRUE; + } + i++; + } while ((MxS32*) &g_roiColorAliases[i] < &g_roiConfig); + + return FALSE; +} + +// OFFSET: LEGO1 0x100a9d30 +void LegoROI::SetSomeHandlerFunction(ROIHandler p_func) +{ + g_someHandlerFunction = p_func; +} + +// OFFSET: LEGO1 0x100a9e10 +void LegoROI::SetDisplayBB(MxS32 p_displayBB) +{ + // Intentionally empty function +} diff --git a/LEGO1/legoroi.h b/LEGO1/legoroi.h index 9585f42b..341c9bd2 100644 --- a/LEGO1/legoroi.h +++ b/LEGO1/legoroi.h @@ -1,10 +1,24 @@ #ifndef LEGOROI_H #define LEGOROI_H +#include "mxtypes.h" + +typedef MxBool (*ROIHandler)(char*, char*, MxU32); + class LegoROI { public: - __declspec(dllexport) void SetDisplayBB(int p_displayBB); - __declspec(dllexport) static void configureLegoROI(int p_roi); + __declspec(dllexport) void SetDisplayBB(MxS32 p_displayBB); + __declspec(dllexport) static void configureLegoROI(MxS32 p_roi); + + static void SetSomeHandlerFunction(ROIHandler p_func); + static MxBool CallTheHandlerFunction( + char* p_param, + MxFloat& p_red, + MxFloat& p_green, + MxFloat& p_blue, + MxFloat& p_other + ); + static MxBool ColorAliasLookup(char* p_param, MxFloat& p_red, MxFloat& p_green, MxFloat& p_blue, MxFloat& p_other); }; #endif // LEGOROI_H diff --git a/LEGO1/legotexturepresenter.cpp b/LEGO1/legotexturepresenter.cpp index 56925d97..2e9dba68 100644 --- a/LEGO1/legotexturepresenter.cpp +++ b/LEGO1/legotexturepresenter.cpp @@ -1,7 +1,17 @@ #include "legotexturepresenter.h" -// OFFSET: LEGO1 0x1004eb40 STUB +#include "legoomni.h" +#include "legovideomanager.h" + +// OFFSET: LEGO1 0x1004eb40 LegoTexturePresenter::~LegoTexturePresenter() { - // TODO + VideoManager()->RemovePresenter(*this); +} + +// OFFSET: LEGO1 0x1004ebb0 +MxResult LegoTexturePresenter::AddToManager() +{ + VideoManager()->AddPresenter(*this); + return SUCCESS; } diff --git a/LEGO1/legotexturepresenter.h b/LEGO1/legotexturepresenter.h index 50d6f86c..e39e4758 100644 --- a/LEGO1/legotexturepresenter.h +++ b/LEGO1/legotexturepresenter.h @@ -21,6 +21,8 @@ class LegoTexturePresenter : public MxMediaPresenter { { return !strcmp(name, LegoTexturePresenter::ClassName()) || MxMediaPresenter::IsA(name); } + + virtual MxResult AddToManager() override; // vtable+0x34 }; #endif // LEGOTEXTUREPRESENTER_H diff --git a/LEGO1/legovideomanager.cpp b/LEGO1/legovideomanager.cpp index 775c2e8c..55f3da33 100644 --- a/LEGO1/legovideomanager.cpp +++ b/LEGO1/legovideomanager.cpp @@ -2,16 +2,57 @@ DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590); -// OFFSET: LEGO1 0x1007aa20 STUB +// OFFSET: LEGO1 0x1007aa20 LegoVideoManager::LegoVideoManager() { - // TODO + m_unk64 = 0; + m_3dManager = NULL; + m_unk6c = 0; + m_direct3d = 0; + m_unk0xe6 = FALSE; + memset(m_unk0x78, 0, sizeof(m_unk0x78)); + m_unk0x78[0] = 0x6c; + m_unk4e8 = 0; + m_isFullscreenMovie = FALSE; + m_palette = NULL; + m_prefCounter = NULL; + m_cursorMoved = FALSE; + m_cursorX = m_cursorY; + m_cursorYCopy = m_cursorY; + m_cursorXCopy = m_cursorY; + m_unk0x514 = 0; + m_unk0x500 = FALSE; + m_drawFPS = FALSE; + m_unk0x528 = 0; + m_arialFont = NULL; + m_unk0xe5 = FALSE; + m_unk0x554 = 0; + m_initialized = FALSE; } -// OFFSET: LEGO1 0x1007ab40 STUB +// OFFSET: LEGO1 0x1007ab40 LegoVideoManager::~LegoVideoManager() { - // TODO + Destroy(); + delete m_palette; +} + +// OFFSET: LEGO1 0x1007b5e0 +void LegoVideoManager::Destroy() +{ + // todo: delete m_unk0x512 + // todo: delete m_unk0x258 + if (m_arialFont != NULL) { + DeleteObject(m_arialFont); + m_arialFont = NULL; + } + + // delete m_unk64; //TODO: delete d3drm + + delete m_3dManager; + MxVideoManager::Destroy(); + // todo: delete m_unk4e8 + delete[] m_prefCounter; } // OFFSET: LEGO1 0x1007c560 STUB diff --git a/LEGO1/legovideomanager.h b/LEGO1/legovideomanager.h index b845e8a8..a6d2f89f 100644 --- a/LEGO1/legovideomanager.h +++ b/LEGO1/legovideomanager.h @@ -33,20 +33,42 @@ class LegoVideoManager : public MxVideoManager { this->m_videoParam.GetPalette()->SetOverrideSkyColor(p_shouldOverride); } + virtual void Destroy() override; // vtable+0x18 + private: undefined4 m_unk64; - Lego3DManager* m_3dManager; + Lego3DManager* m_3dManager; // 0x68 undefined4 m_unk6c; undefined4 m_unk70; - MxDirect3D* m_direct3d; - undefined m_pad0x78[0x6c]; + MxDirect3D* m_direct3d; // 0x74 + undefined4 m_unk0x78[27]; MxBool m_unk0xe4; - undefined m_pad0xe8[0x41c]; + MxBool m_unk0xe5; + MxBool m_unk0xe6; + PALETTEENTRY m_paletteEntries[256]; // 0xe7 + undefined m_padding0x4e7; + undefined4 m_unk4e8; + MxBool m_isFullscreenMovie; // 0x4ec + MxPalette* m_palette; // 0x4f0 + LARGE_INTEGER* m_prefCounter; // 0x4f4 + undefined m_padding0x4f4[8]; + MxBool m_unk0x500; MxBool m_cursorMoved; // 0x501 - undefined m_pad0x502[0x8]; - MxS32 m_cursorX; // 0x50c - MxS32 m_cursorY; // 0x510 - undefined m_pad0x514[0x7c]; + MxS32 m_cursorXCopy; // 0x504 + MxS32 m_cursorYCopy; // 0x508 + MxS32 m_cursorX; // 0x50c + MxS32 m_cursorY; // 0x510 + undefined4 m_unk0x514; + undefined m_pad0x518[0x10]; + undefined4 m_unk0x528; + MxBool m_drawFPS; // 0x52c + RECT m_fpsRect; // 0x530 + HFONT m_arialFont; // 0x540 + SIZE m_fpsSize; // 0x544 + undefined m_pad0x54c[8]; + undefined m_unk0x554; + MxBool m_initialized; // 0x555 + undefined m_pad0x556[0x39]; }; #endif // LEGOVIDEOMANAGER_H diff --git a/LEGO1/legoworldpresenter.cpp b/LEGO1/legoworldpresenter.cpp index 44e8022d..1e1d7558 100644 --- a/LEGO1/legoworldpresenter.cpp +++ b/LEGO1/legoworldpresenter.cpp @@ -1,9 +1,12 @@ #include "legoworldpresenter.h" -// OFFSET: LEGO1 0x100665c0 STUB +// 0x100f75d4 +undefined4 g_LegoWorldPresenterQuality = 1; + +// OFFSET: LEGO1 0x100665c0 LegoWorldPresenter::LegoWorldPresenter() { - // TODO + m_unk50 = 50000; } // OFFSET: LEGO1 0x10066770 STUB @@ -12,8 +15,8 @@ LegoWorldPresenter::~LegoWorldPresenter() // TODO } -// OFFSET: LEGO1 0x100665b0 STUB -void LegoWorldPresenter::configureLegoWorldPresenter(int param_1) +// OFFSET: LEGO1 0x100665b0 +void LegoWorldPresenter::configureLegoWorldPresenter(int p_quality) { - // TODO + g_LegoWorldPresenterQuality = p_quality; } diff --git a/LEGO1/legoworldpresenter.h b/LEGO1/legoworldpresenter.h index 284c0437..da9b0e2d 100644 --- a/LEGO1/legoworldpresenter.h +++ b/LEGO1/legoworldpresenter.h @@ -24,6 +24,9 @@ class LegoWorldPresenter : public LegoEntityPresenter { { return !strcmp(name, LegoWorldPresenter::ClassName()) || LegoEntityPresenter::IsA(name); } + +private: + undefined4 m_unk50; }; #endif // LEGOWORLDPRESENTER_H diff --git a/LEGO1/mxactionnotificationparam.h b/LEGO1/mxactionnotificationparam.h index 3255f91d..7f825a21 100644 --- a/LEGO1/mxactionnotificationparam.h +++ b/LEGO1/mxactionnotificationparam.h @@ -8,7 +8,12 @@ // SIZE 0x14 class MxActionNotificationParam : public MxNotificationParam { public: - inline MxActionNotificationParam(MxParamType p_type, MxCore* p_sender, MxDSAction* p_action, MxBool p_reallocAction) + inline MxActionNotificationParam( + NotificationId p_type, + MxCore* p_sender, + MxDSAction* p_action, + MxBool p_reallocAction + ) : MxNotificationParam(p_type, p_sender) { MxDSAction* oldAction = p_action; @@ -50,7 +55,7 @@ class MxActionNotificationParam : public MxNotificationParam { class MxEndActionNotificationParam : public MxActionNotificationParam { public: inline MxEndActionNotificationParam( - MxParamType p_type, + NotificationId p_type, MxCore* p_sender, MxDSAction* p_action, MxBool p_reallocAction diff --git a/LEGO1/mxbackgroundaudiomanager.cpp b/LEGO1/mxbackgroundaudiomanager.cpp index e9106177..26d399f7 100644 --- a/LEGO1/mxbackgroundaudiomanager.cpp +++ b/LEGO1/mxbackgroundaudiomanager.cpp @@ -1,6 +1,10 @@ #include "mxbackgroundaudiomanager.h" +#include "legoomni.h" +#include "mxcompositepresenter.h" +#include "mxdssound.h" #include "mxomni.h" +#include "mxpresenter.h" #include "mxstreamer.h" #include "mxticklemanager.h" @@ -14,7 +18,7 @@ MxBackgroundAudioManager::MxBackgroundAudioManager() m_unk138 = 0; m_unk13c = 0; m_unk140 = 0; - m_unk144 = 0; + m_targetVolume = 0; m_unk148 = 0; m_musicEnabled = FALSE; } @@ -47,6 +51,32 @@ void MxBackgroundAudioManager::Stop() 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) { @@ -106,3 +136,191 @@ void MxBackgroundAudioManager::DestroyMusic() m_musicEnabled = FALSE; } } + +// 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->vtable60(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() +{ + switch (m_unk13c) { + case MxPresenter::TickleState_Starting: + FadeInOrFadeOut(); + return SUCCESS; + case MxPresenter::TickleState_Streaming: + FUN_1007ee70(); + return SUCCESS; + case MxPresenter::TickleState_Repeating: + FUN_1007ef40(); + return SUCCESS; + default: + return SUCCESS; + } +} + +// OFFSET: LEGO1 0x1007ee70 +void MxBackgroundAudioManager::FUN_1007ee70() +{ + if (m_unka0 && m_unka0->GetAction()) { + DeleteObject(*m_unk138->GetAction()); + } + + if (m_unk138) { + m_unka0 = m_unk138; + m_action1 = m_action2; + m_unk138 = NULL; + m_action2.SetObjectId(-1); + m_action2.SetAtomId(MxAtomId()); + m_unk13c = NULL; + } +} + +// OFFSET: LEGO1 0x1007ef40 +void MxBackgroundAudioManager::FUN_1007ef40() +{ + MxU32 compare; + MxU32 volume; + if (m_unka0 == NULL) { + if (m_unk138) { + compare = 30; + if (m_unk148 == 0) { + compare = m_unk148; + } + volume = m_unk138->vtable5c(); + if (volume < compare) { + if (m_unk140 + m_unk138->vtable5c() <= compare) { + compare = m_unk140 + compare; + } + m_unk138->vtable60(compare); + } + else { + m_unk138->vtable60(compare); + m_unka0 = m_unk138; + m_action1 = m_action2; + m_unk138 = NULL; + m_action2.SetObjectId(-1); + m_action2.SetAtomId(MxAtomId()); + m_unk13c = NULL; + } + } + } + else if (m_unka0->GetAction() != NULL) { + if (m_unka0->vtable5c() == 0) { + DeleteObject(*m_unka0->GetAction()); + } + else { + compare = m_unka0->vtable5c(); + volume = 0; + if (compare != m_unk140 && -1 < compare - m_unk140) { + volume = m_unka0->vtable5c() - m_unk140; + } + m_unk138->vtable60(volume); + } + } +} + +// OFFSET: LEGO1 0x1007f0e0 +void MxBackgroundAudioManager::FadeInOrFadeOut() +{ + // This function probably is the fade in/out routine + if (m_unka0 != NULL) { + undefined4 volume = m_unka0->vtable5c(); + MxU32 compare = 30; + if (m_unk148 == 0) { + compare = m_targetVolume; + } + + if (volume < compare) { + volume = m_unk140 + volume; + if (compare <= volume) { + volume = compare; + } + m_unka0->vtable60(volume); + } + else if (compare < volume) { + volume = volume - m_unk140; + if (volume <= compare) { + volume = compare; + } + m_unka0->vtable60(volume); + } + else { + m_unka0->vtable60(volume); + m_unk13c = 0; + } + } + else { + m_unk13c = 0; + } +} diff --git a/LEGO1/mxbackgroundaudiomanager.h b/LEGO1/mxbackgroundaudiomanager.h index a306ef2a..6ff05bb3 100644 --- a/LEGO1/mxbackgroundaudiomanager.h +++ b/LEGO1/mxbackgroundaudiomanager.h @@ -1,9 +1,11 @@ #ifndef MXBACKGROUNDAUDIOMANAGER_H #define MXBACKGROUNDAUDIOMANAGER_H +#include "mxaudiopresenter.h" #include "mxcore.h" #include "mxdsaction.h" #include "mxnotificationmanager.h" +#include "mxpresenter.h" #include "mxtypes.h" // VTABLE 0x100d9fe8 @@ -13,6 +15,9 @@ class MxBackgroundAudioManager : public MxCore { MxBackgroundAudioManager(); virtual ~MxBackgroundAudioManager() override; + virtual MxLong Notify(MxParam& p) override; // vtable+0x04 + virtual MxResult Tickle() override; // vtable+0x08 + // OFFSET: LEGO1 0x1007eb70 inline virtual const char* ClassName() const override // vtable+0x0c { @@ -26,10 +31,20 @@ class MxBackgroundAudioManager : public MxCore { return !strcmp(name, MxBackgroundAudioManager::ClassName()) || MxCore::IsA(name); } + void StartAction(MxParam& p); + void StopAction(MxParam& p); + MxResult PlayMusic(MxDSAction& p_action, undefined4 p_unknown, undefined4 p_unknown2); + + void FUN_1007ee70(); + void FUN_1007ef40(); + void FadeInOrFadeOut(); + __declspec(dllexport) void Enable(unsigned char p); virtual MxResult Create(MxAtomId& p_script, MxU32 p_frequencyMS); void Stop(); + void LowerVolume(); + void RaiseVolume(); private: void Init(); @@ -38,12 +53,12 @@ class MxBackgroundAudioManager : public MxCore { MxBool m_musicEnabled; // 0x8 MxDSAction m_action1; // 0xc - MxS32 m_unka0; + MxAudioPresenter* m_unka0; MxDSAction m_action2; // 0xa4 - MxS32 m_unk138; + MxAudioPresenter* m_unk138; MxS32 m_unk13c; MxS32 m_unk140; - MxS32 m_unk144; + MxS32 m_targetVolume; MxS16 m_unk148; MxAtomId m_script; }; diff --git a/LEGO1/mxcollection.h b/LEGO1/mxcollection.h new file mode 100644 index 00000000..0f32a064 --- /dev/null +++ b/LEGO1/mxcollection.h @@ -0,0 +1,25 @@ +#ifndef MXCOLLECTION_H +#define MXCOLLECTION_H + +#include "mxcore.h" + +template +class MxCollection : public MxCore { +public: + MxCollection() + { + m_count = 0; + m_customDestructor = Destroy; + } + + virtual ~MxCollection() {} + + static void Destroy(T){}; + virtual MxS8 Compare(T, T) { return 0; } + +protected: + MxU32 m_count; // +0x8 + void (*m_customDestructor)(T); // +0xc +}; + +#endif // MXCOLLECTION_H diff --git a/LEGO1/mxcompositepresenter.cpp b/LEGO1/mxcompositepresenter.cpp index 219b140c..b702acda 100644 --- a/LEGO1/mxcompositepresenter.cpp +++ b/LEGO1/mxcompositepresenter.cpp @@ -16,3 +16,29 @@ MxCompositePresenter::~MxCompositePresenter() { NotificationManager()->Unregister(this); } + +// OFFSET: LEGO1 0x100b67f0 STUB +void MxCompositePresenter::VTable0x58() +{ + // TODO +} + +// OFFSET: LEGO1 0x100b69b0 STUB +void MxCompositePresenter::VTable0x5c() +{ + // TODO +} + +// OFFSET: LEGO1 0x100b6b40 STUB +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/mxcompositepresenter.h b/LEGO1/mxcompositepresenter.h index f7fbd1cf..c8eedfaf 100644 --- a/LEGO1/mxcompositepresenter.h +++ b/LEGO1/mxcompositepresenter.h @@ -24,6 +24,12 @@ class MxCompositePresenter : public MxPresenter { return !strcmp(name, MxCompositePresenter::ClassName()) || MxPresenter::IsA(name); } + virtual void VTable0x58(); + virtual void VTable0x5c(); + virtual void VTable0x60(undefined4 p_unknown); + virtual MxBool VTable0x64(undefined4 p_unknown); + +private: MxUnkList m_list; }; diff --git a/LEGO1/mxcontrolpresenter.cpp b/LEGO1/mxcontrolpresenter.cpp index 158e7460..443fe0dc 100644 --- a/LEGO1/mxcontrolpresenter.cpp +++ b/LEGO1/mxcontrolpresenter.cpp @@ -1,5 +1,8 @@ #include "mxcontrolpresenter.h" +#include "legoomni.h" +#include "mxticklemanager.h" + DECOMP_SIZE_ASSERT(MxControlPresenter, 0x5c) // OFFSET: LEGO1 0x10043f50 @@ -12,3 +15,21 @@ MxControlPresenter::MxControlPresenter() this->m_unk58 = 0; this->m_unk54 = 0; } + +// OFFSET: LEGO1 0x10044110 +MxControlPresenter::~MxControlPresenter() +{ + if (this->m_unk58) { + delete this->m_unk58; + } +} + +// OFFSET: LEGO1 0x10044610 +void MxControlPresenter::ReadyTickle() +{ + MxPresenter::ParseExtra(); + TickleManager()->UnregisterClient(this); + + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Repeating; +} diff --git a/LEGO1/mxcontrolpresenter.h b/LEGO1/mxcontrolpresenter.h index 29a7121a..489451be 100644 --- a/LEGO1/mxcontrolpresenter.h +++ b/LEGO1/mxcontrolpresenter.h @@ -9,6 +9,7 @@ class MxControlPresenter : public MxCompositePresenter { public: MxControlPresenter(); + virtual ~MxControlPresenter() override; // OFFSET: LEGO1 0x10044000 inline virtual const char* ClassName() const override // vtable+0x0c @@ -23,13 +24,15 @@ class MxControlPresenter : public MxCompositePresenter { return !strcmp(name, MxControlPresenter::ClassName()) || MxCompositePresenter::IsA(name); } + virtual void ReadyTickle() override; // vtable+0x18 + private: undefined2 m_unk4c; MxS16 m_unk4e; undefined m_unk50; undefined2 m_unk52; undefined2 m_unk54; - undefined4 m_unk58; + undefined4* m_unk58; }; #endif // MXCONTROLPRESENTER_H diff --git a/LEGO1/mxcore.cpp b/LEGO1/mxcore.cpp index 0443f7bf..8e2ac5a1 100644 --- a/LEGO1/mxcore.cpp +++ b/LEGO1/mxcore.cpp @@ -1,13 +1,12 @@ #include "mxcore.h" -// 0x1010141c -unsigned int g_mxcoreCount = 0; +#include "define.h" // OFFSET: LEGO1 0x100ae1a0 MxCore::MxCore() { - m_id = g_mxcoreCount; - g_mxcoreCount++; + m_id = g_mxcoreCount[0]; + g_mxcoreCount[0]++; } // OFFSET: LEGO1 0x100ae1e0 diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index 1ca8a906..899e3371 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -13,9 +13,9 @@ class MxParam; class MxCore { public: __declspec(dllexport) MxCore(); - __declspec(dllexport) virtual ~MxCore(); // vtable+00 - __declspec(dllexport) virtual MxResult Notify(MxParam& p); // vtable+04 - virtual MxResult Tickle(); // vtable+08 + __declspec(dllexport) virtual ~MxCore(); // vtable+00 + __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 diff --git a/LEGO1/mxdiskstreamprovider.cpp b/LEGO1/mxdiskstreamprovider.cpp index b5dabe4a..0c422b99 100644 --- a/LEGO1/mxdiskstreamprovider.cpp +++ b/LEGO1/mxdiskstreamprovider.cpp @@ -81,7 +81,7 @@ MxResult MxDiskStreamProvider::WaitForWorkToComplete() return SUCCESS; } -// OFFSET: LEGO1 0x100d1760 STUB +// OFFSET: LEGO1 0x100d18f0 STUB void MxDiskStreamProvider::PerformWork() { // TODO diff --git a/LEGO1/mxdisplaysurface.cpp b/LEGO1/mxdisplaysurface.cpp index 28309109..2e3f8b5a 100644 --- a/LEGO1/mxdisplaysurface.cpp +++ b/LEGO1/mxdisplaysurface.cpp @@ -82,8 +82,8 @@ MxResult MxDisplaySurface::Create(MxVideoParam& p_videoParam) } if (this->m_videoParam.flags().GetFullScreen()) { - MxS32 width = this->m_videoParam.GetRect().m_right - this->m_videoParam.GetRect().m_left + 1; - MxS32 height = this->m_videoParam.GetRect().m_bottom - this->m_videoParam.GetRect().m_top + 1; + MxS32 width = this->m_videoParam.GetRect().GetWidth(); + MxS32 height = this->m_videoParam.GetRect().GetHeight(); if (lpDirectDraw->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)) goto done; @@ -129,8 +129,8 @@ MxResult MxDisplaySurface::Create(MxVideoParam& p_videoParam) memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS; - ddsd.dwWidth = this->m_videoParam.GetRect().m_right - this->m_videoParam.GetRect().m_left + 1; - ddsd.dwHeight = this->m_videoParam.GetRect().m_bottom - this->m_videoParam.GetRect().m_top + 1; + ddsd.dwWidth = this->m_videoParam.GetRect().GetWidth(); + ddsd.dwHeight = this->m_videoParam.GetRect().GetHeight(); ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE | DDSCAPS_OFFSCREENPLAIN; if (!this->m_videoParam.flags().GetBackBuffers()) diff --git a/LEGO1/mxdsaction.cpp b/LEGO1/mxdsaction.cpp index 6dc334ec..3dc58a99 100644 --- a/LEGO1/mxdsaction.cpp +++ b/LEGO1/mxdsaction.cpp @@ -28,7 +28,7 @@ MxDSAction::MxDSAction() this->m_up.Fill(FLT_MAX); this->m_unk84 = NULL; this->m_unk88 = 0; - this->m_omni = NULL; + this->m_unk8c = NULL; this->m_unkTimingField = INT_MIN; } @@ -54,7 +54,7 @@ void MxDSAction::CopyFrom(MxDSAction& p_dsAction) AppendData(p_dsAction.m_extraLength, p_dsAction.m_extraData); this->m_unk84 = p_dsAction.m_unk84; this->m_unk88 = p_dsAction.m_unk88; - this->m_omni = p_dsAction.m_omni; + this->m_unk8c = p_dsAction.m_unk8c; this->m_unkTimingField = p_dsAction.m_unkTimingField; } @@ -196,11 +196,8 @@ MxLong MxDSAction::GetUnkTimingField() return this->m_unkTimingField; } -// Win32 defines GetCurrentTime to GetTickCount -#undef GetCurrentTime - // OFFSET: LEGO1 0x100adcd0 -MxLong MxDSAction::GetCurrentTime() +MxLong MxDSAction::GetElapsedTime() { return Timer()->GetTime() - this->m_unkTimingField; } diff --git a/LEGO1/mxdsaction.h b/LEGO1/mxdsaction.h index 72d7afac..e986438f 100644 --- a/LEGO1/mxdsaction.h +++ b/LEGO1/mxdsaction.h @@ -17,7 +17,8 @@ class MxDSAction : public MxDSObject { Flag_Bit4 = 0x08, Flag_Bit5 = 0x10, Flag_Enabled = 0x20, - Flag_Parsed = 0x80, + Flag_Bit7 = 0x40, + Flag_World = 0x80, Flag_Bit9 = 0x200, Flag_Bit10 = 0x400, }; @@ -50,7 +51,7 @@ class MxDSAction : public MxDSObject { virtual MxBool HasId(MxU32 p_objectId); // vtable+34; virtual void SetUnkTimingField(MxLong p_unkTimingField); // vtable+38; virtual MxLong GetUnkTimingField(); // vtable+3c; - virtual MxLong GetCurrentTime(); // vtable+40; + virtual MxLong GetElapsedTime(); // vtable+40; void AppendData(MxU16 p_extraLength, const char* p_extraData); @@ -63,7 +64,8 @@ class MxDSAction : public MxDSObject { inline void SetLoopCount(MxS32 p_loopCount) { m_loopCount = p_loopCount; } inline const MxVector3Data& GetLocation() const { return m_location; } inline void SetUnknown84(MxCore* p_unk84) { m_unk84 = p_unk84; } - inline void SetOmni(MxOmni* p_omni) { m_omni = p_omni; } + inline MxCore* GetUnknown8c() { return m_unk8c; } + inline void SetUnknown8c(MxCore* p_unk8c) { m_unk8c = p_unk8c; } inline MxBool IsLooping() const { return m_flags & Flag_Looping; } inline MxBool IsBit3() const { return m_flags & Flag_Bit3; } @@ -85,7 +87,7 @@ class MxDSAction : public MxDSObject { MxU16 m_extraLength; MxCore* m_unk84; undefined4 m_unk88; - MxOmni* m_omni; // 0x8c + MxCore* m_unk8c; protected: MxLong m_unkTimingField; // 0x90 diff --git a/LEGO1/mxdsactionlist.cpp b/LEGO1/mxdsactionlist.cpp index 394512e5..2959ffcd 100644 --- a/LEGO1/mxdsactionlist.cpp +++ b/LEGO1/mxdsactionlist.cpp @@ -6,13 +6,9 @@ DECOMP_SIZE_ASSERT(MxDSActionList, 0x1c); DECOMP_SIZE_ASSERT(MxDSActionListCursor, 0x10); // OFFSET: LEGO1 0x100c9c90 -MxS8 MxDSActionList::Compare(MxDSAction* p_var0, MxDSAction* p_var1) +MxS8 MxDSActionList::Compare(MxDSAction* p_a, MxDSAction* p_b) { - if (p_var1 == p_var0) - return 0; - if (p_var1 <= p_var0) - return 1; - return -1; + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; } // OFFSET: LEGO1 0x100c9cb0 diff --git a/LEGO1/mxdsactionlist.h b/LEGO1/mxdsactionlist.h index 3dc9798a..d3bafbbb 100644 --- a/LEGO1/mxdsactionlist.h +++ b/LEGO1/mxdsactionlist.h @@ -12,7 +12,7 @@ class MxDSActionList : public MxList { public: MxDSActionList() { this->m_unk18 = 0; } - virtual MxS8 Compare(MxDSAction*, MxDSAction*); // +0x14 + virtual MxS8 Compare(MxDSAction*, MxDSAction*) override; // +0x14 static void Destroy(MxDSAction* p_action); diff --git a/LEGO1/mxdsbuffer.cpp b/LEGO1/mxdsbuffer.cpp index 4163e39b..a09bb101 100644 --- a/LEGO1/mxdsbuffer.cpp +++ b/LEGO1/mxdsbuffer.cpp @@ -1,5 +1,8 @@ #include "mxdsbuffer.h" +#include "mxomni.h" +#include "mxstreamer.h" + DECOMP_SIZE_ASSERT(MxDSBuffer, 0x34); // OFFSET: LEGO1 0x100c6470 @@ -14,24 +17,112 @@ MxDSBuffer::MxDSBuffer() m_unk1c = 0; m_writeOffset = 0; m_bytesRemaining = 0; - m_mode = 2; + m_mode = MxDSBufferType_Preallocated; m_unk30 = 0; } // OFFSET: LEGO1 0x100c6530 MxDSBuffer::~MxDSBuffer() { - // TODO + if (m_pBuffer != NULL) { + if (m_mode == MxDSBufferType_Chunk) { + // TODO + } + else if (m_mode == MxDSBufferType_Allocate || m_mode == MxDSBufferType_Unknown) { + delete[] m_pBuffer; + } + } + + m_unk14 = 0; + m_unk1c = 0; +} + +// OFFSET: LEGO1 0x100c6640 +MxResult MxDSBuffer::AllocateBuffer(MxU32 p_bufferSize, MxDSBufferType p_mode) +{ + MxResult result = FAILURE; + MxU32 i = 0; + if (p_mode == MxDSBufferType_Allocate) { + m_pBuffer = new MxU8[p_bufferSize]; + } + else if (p_mode == MxDSBufferType_Chunk) { + MxStreamer* streamer = Streamer(); + // I have no clue as to what this does, or even if its correct. Maybe it's related to storing chunks in + // MxRamStreamController? + if (p_bufferSize >> 10 == 0x40) { + i = 0; + while (i < 22) { + if ((*(MxU32*) ((streamer->GetSubclass1().GetUnk08() + ((i & 0xffffffe7) >> 3)) & 1 << ((MxU8) i & 0x1f) + )) == 0) { + MxU32* ptr = (MxU32*) ((streamer->GetSubclass1().GetUnk08() + ((i & 0xffffffe7) >> 3)) & + 1 << ((MxU8) i & 0x1f)); + + // mark it as used? + *ptr = *ptr ^ 1 << (i & 0x1f); + + m_pBuffer = + (MxU8*) (streamer->GetSubclass1().GetSize() * i * 0x400 + streamer->GetSubclass1().GetBuffer()); + break; + } + i++; + } + + m_pBuffer = NULL; + } + else if (p_bufferSize >> 10 == 0x80) { + i = 0; + // Same thing as above but it uses subclass2 + while (i < 22) { + if ((*(MxU32*) ((streamer->GetSubclass2().GetUnk08() + ((i & 0xffffffe7) >> 3)) & 1 << ((MxU8) i & 0x1f) + )) == 0) { + MxU32* ptr = (MxU32*) ((streamer->GetSubclass2().GetUnk08() + ((i & 0xffffffe7) >> 3)) & + 1 << ((MxU8) i & 0x1f)); + + // mark it as used? + *ptr = *ptr ^ 1 << (i & 0x1f); + + m_pBuffer = + (MxU8*) (streamer->GetSubclass2().GetSize() * i * 0x400 + streamer->GetSubclass2().GetBuffer()); + break; + } + i++; + } + + m_pBuffer = NULL; + } + else { + m_pIntoBuffer = NULL; + } + } + + m_pIntoBuffer = m_pBuffer; + m_pIntoBuffer2 = m_pBuffer; + if (m_pBuffer != NULL) { + m_mode = p_mode; + m_bytesRemaining = p_bufferSize; + m_writeOffset = p_bufferSize; + result = SUCCESS; + } + return result; } // OFFSET: LEGO1 0x100c6780 -MxResult MxDSBuffer::FUN_100c6780(void* p_buffer, MxU32 p_size) +MxResult MxDSBuffer::SetBufferPointer(MxU32* p_buffer, MxU32 p_size) { - m_pBuffer = p_buffer; - m_pIntoBuffer = p_buffer; - m_pIntoBuffer2 = p_buffer; + m_pBuffer = (MxU8*) p_buffer; + m_pIntoBuffer = (MxU8*) p_buffer; + m_pIntoBuffer2 = (MxU8*) p_buffer; m_bytesRemaining = p_size; m_writeOffset = p_size; - m_mode = 2; + m_mode = MxDSBufferType_Preallocated; return SUCCESS; } + +// OFFSET: LEGO1 0x100c6f80 +void MxDSBuffer::FUN_100c6f80(MxU32 p_unk) +{ + if (p_unk < m_writeOffset) { + m_pIntoBuffer2 = m_pBuffer + p_unk; + m_pIntoBuffer = m_pBuffer + p_unk; + } +} diff --git a/LEGO1/mxdsbuffer.h b/LEGO1/mxdsbuffer.h index e521b47f..33706899 100644 --- a/LEGO1/mxdsbuffer.h +++ b/LEGO1/mxdsbuffer.h @@ -4,6 +4,13 @@ #include "decomp.h" #include "mxcore.h" +enum MxDSBufferType { + MxDSBufferType_Chunk = 0, + MxDSBufferType_Allocate = 1, + MxDSBufferType_Preallocated = 2, + MxDSBufferType_Unknown = 3, +}; + // VTABLE 0x100dcca0 // SIZE 0x34 class MxDSBuffer : public MxCore { @@ -18,20 +25,22 @@ class MxDSBuffer : public MxCore { return "MxDSBuffer"; } - MxResult FUN_100c6780(void* p_buffer, MxU32 p_size); + MxResult AllocateBuffer(MxU32 p_bufferSize, MxDSBufferType p_mode); + MxResult SetBufferPointer(MxU32* p_buffer, MxU32 p_size); + void FUN_100c6f80(MxU32 p_unk); - inline void* GetBuffer() { return m_pBuffer; } + inline MxU8* GetBuffer() { return m_pBuffer; } inline MxU32 GetWriteOffset() { return m_writeOffset; } private: - void* m_pBuffer; - void* m_pIntoBuffer; - void* m_pIntoBuffer2; + MxU8* m_pBuffer; + MxU8* m_pIntoBuffer; + MxU8* m_pIntoBuffer2; undefined4 m_unk14; undefined4 m_unk18; undefined4 m_unk1c; undefined2 m_unk20; - undefined4 m_mode; + MxDSBufferType m_mode; MxU32 m_writeOffset; MxU32 m_bytesRemaining; undefined4 m_unk30; diff --git a/LEGO1/mxdschunk.cpp b/LEGO1/mxdschunk.cpp index 3abfb573..489a1611 100644 --- a/LEGO1/mxdschunk.cpp +++ b/LEGO1/mxdschunk.cpp @@ -1,19 +1,21 @@ #include "mxdschunk.h" +DECOMP_SIZE_ASSERT(MxDSChunk, 0x1c); + // OFFSET: LEGO1 0x100be050 MxDSChunk::MxDSChunk() { - this->m_length = 0; - this->m_unk18 = NULL; - this->m_buffer = -1; - this->m_unk10 = 0; - this->m_unk14 = 0; + m_flags = 0; + m_data = NULL; + m_unk0c = -1; + m_time = 0; + m_length = 0; } // OFFSET: LEGO1 0x100be170 MxDSChunk::~MxDSChunk() { - if ((this->m_length & 1) != 0) { - delete this->m_unk18; + if (m_flags & Flag_Bit1) { + delete[] m_data; } } diff --git a/LEGO1/mxdschunk.h b/LEGO1/mxdschunk.h index ba716de6..e626d70b 100644 --- a/LEGO1/mxdschunk.h +++ b/LEGO1/mxdschunk.h @@ -1,12 +1,20 @@ #ifndef MXDSCHUNK_H #define MXDSCHUNK_H +#include "decomp.h" #include "mxcore.h" #include "mxtypes.h" // VTABLE 0x100dc7f8 +// SIZE 0x1c class MxDSChunk : public MxCore { public: + enum { + Flag_Bit1 = 0x01, + Flag_Bit2 = 0x02, + Flag_Bit3 = 0x04, + }; + MxDSChunk(); virtual ~MxDSChunk() override; @@ -23,13 +31,27 @@ class MxDSChunk : public MxCore { return !strcmp(name, MxDSChunk::ClassName()) || MxCore::IsA(name); } + inline void SetTime(MxLong p_time) { m_time = p_time; } + inline void SetLength(MxU32 p_length) { m_length = p_length; } + inline void SetData(MxU8* p_data) { m_data = p_data; } + + inline MxU16 GetFlags() { return m_flags; } + inline MxLong GetTime() { return m_time; } + inline MxU32 GetLength() { return m_length; } + inline MxU8* GetData() { return m_data; } + + inline void Release() + { + if (m_data) + delete[] m_data; + } + private: - MxS16 m_length; // 0x8 - MxLong m_buffer; // 0xc - MxLong m_unk10; // 0x10 - MxLong m_unk14; // 0x14 - void* m_unk18; // 0x18 - void* m_unk1c; // 0x1c + MxU16 m_flags; // 0x8 + undefined4 m_unk0c; // 0xc + MxLong m_time; // 0x10 + MxU32 m_length; // 0x14 + MxU8* m_data; // 0x18 }; #endif // MXDSCHUNK_H diff --git a/LEGO1/mxdsselectaction.cpp b/LEGO1/mxdsselectaction.cpp index 291a14df..e6ff1895 100644 --- a/LEGO1/mxdsselectaction.cpp +++ b/LEGO1/mxdsselectaction.cpp @@ -30,7 +30,7 @@ void MxDSSelectAction::CopyFrom(MxDSSelectAction& p_dsSelectAction) MxStringListCursor cursor(p_dsSelectAction.m_unk0xac); MxString string; while (cursor.Next(string)) - this->m_unk0xac->OtherAppend(string); + this->m_unk0xac->Append(string); } // OFFSET: LEGO1 0x100cbd50 @@ -109,7 +109,7 @@ void MxDSSelectAction::Deserialize(char** p_source, MxS16 p_unk24) if (!strcmp(string.GetData(), *p_source)) index = i; - this->m_unk0xac->OtherAppend(*p_source); + this->m_unk0xac->Append(*p_source); *p_source += strlen(*p_source) + 1; } diff --git a/LEGO1/mxdssound.h b/LEGO1/mxdssound.h index d56a4471..63a1d5ab 100644 --- a/LEGO1/mxdssound.h +++ b/LEGO1/mxdssound.h @@ -30,6 +30,8 @@ class MxDSSound : public MxDSMediaAction { virtual void Deserialize(char** p_source, MxS16 p_unk24) override; // vtable+1c; virtual MxDSAction* Clone() override; // vtable+2c; + inline MxS32 GetVolume() const { return m_volume; } + private: MxU32 m_sizeOnDisk; MxS32 m_volume; // 0xbc diff --git a/LEGO1/mxdssource.cpp b/LEGO1/mxdssource.cpp index f94318d1..7110c9ee 100644 --- a/LEGO1/mxdssource.cpp +++ b/LEGO1/mxdssource.cpp @@ -5,7 +5,7 @@ // OFFSET: LEGO1 0x100bffd0 void MxDSSource::ReadToBuffer(MxDSBuffer* p_buffer) { - Read((unsigned char*) p_buffer->GetBuffer(), p_buffer->GetWriteOffset()); + Read(p_buffer->GetBuffer(), p_buffer->GetWriteOffset()); } // OFFSET: LEGO1 0x100bfff0 diff --git a/LEGO1/mxdssubscriber.cpp b/LEGO1/mxdssubscriber.cpp index d97b6946..151572eb 100644 --- a/LEGO1/mxdssubscriber.cpp +++ b/LEGO1/mxdssubscriber.cpp @@ -1,13 +1,42 @@ #include "mxdssubscriber.h" -// OFFSET: LEGO1 0x100b7bb0 +DECOMP_SIZE_ASSERT(MxDSSubscriber, 0x4c); + +// OFFSET: LEGO1 0x100b7bb0 STUB MxDSSubscriber::MxDSSubscriber() { // TODO } -// OFFSET: LEGO1 0x100b7e00 +// OFFSET: LEGO1 0x100b7e00 STUB MxDSSubscriber::~MxDSSubscriber() { // TODO } + +// OFFSET: LEGO1 0x100b7ed0 STUB +MxResult MxDSSubscriber::FUN_100b7ed0(MxStreamController*, MxU32, MxS16) +{ + // TODO + return SUCCESS; +} + +// OFFSET: LEGO1 0x100b8250 STUB +MxStreamChunk* MxDSSubscriber::FUN_100b8250() +{ + // TODO + return NULL; +} + +// OFFSET: LEGO1 0x100b8360 STUB +MxStreamChunk* MxDSSubscriber::FUN_100b8360() +{ + // TODO + return NULL; +} + +// OFFSET: LEGO1 0x100b8390 STUB +void MxDSSubscriber::FUN_100b8390(MxStreamChunk*) +{ + // TODO +} diff --git a/LEGO1/mxdssubscriber.h b/LEGO1/mxdssubscriber.h index c56835db..4a57c841 100644 --- a/LEGO1/mxdssubscriber.h +++ b/LEGO1/mxdssubscriber.h @@ -1,7 +1,11 @@ #ifndef MXDSSUBSCRIBER_H #define MXDSSUBSCRIBER_H +#include "decomp.h" #include "mxcore.h" +#include "mxdschunk.h" +#include "mxstreamchunk.h" +#include "mxstreamcontroller.h" // VTABLE 0x100dc698 // SIZE 0x4c @@ -22,6 +26,14 @@ class MxDSSubscriber : public MxCore { { return !strcmp(name, MxDSSubscriber::ClassName()) || MxCore::IsA(name); } + + MxResult FUN_100b7ed0(MxStreamController*, MxU32, MxS16); + MxStreamChunk* FUN_100b8250(); + MxStreamChunk* FUN_100b8360(); + void FUN_100b8390(MxStreamChunk*); + +private: + undefined m_pad[0x44]; // 0x8 }; #endif // MXDSSUBSCRIBER_H diff --git a/LEGO1/mxeventpresenter.cpp b/LEGO1/mxeventpresenter.cpp index 755b440e..48741d4f 100644 --- a/LEGO1/mxeventpresenter.cpp +++ b/LEGO1/mxeventpresenter.cpp @@ -24,11 +24,22 @@ void MxEventPresenter::Init() m_unk50 = NULL; } +// OFFSET: LEGO1 0x100c2db0 +MxResult MxEventPresenter::AddToManager() +{ + MxResult ret = FAILURE; + if (EventManager()) { + ret = SUCCESS; + EventManager()->AddPresenter(*this); + } + + return ret; +} + // OFFSET: LEGO1 0x100c2de0 void MxEventPresenter::Destroy() { - MxEventManager* eventManager = EventManager(); - if (eventManager) + if (EventManager()) EventManager()->RemovePresenter(*this); m_criticalSection.Enter(); diff --git a/LEGO1/mxeventpresenter.h b/LEGO1/mxeventpresenter.h index 35ad8ae9..91b95983 100644 --- a/LEGO1/mxeventpresenter.h +++ b/LEGO1/mxeventpresenter.h @@ -24,7 +24,8 @@ class MxEventPresenter : public MxMediaPresenter { return !strcmp(name, MxEventPresenter::ClassName()) || MxMediaPresenter::IsA(name); } - virtual void Destroy() override; // vtable+0x38 + virtual MxResult AddToManager() override; // vtable+0x34 + virtual void Destroy() override; // vtable+0x38 private: void Init(); diff --git a/LEGO1/mxhashtable.h b/LEGO1/mxhashtable.h index f9a8df73..a276cfd8 100644 --- a/LEGO1/mxhashtable.h +++ b/LEGO1/mxhashtable.h @@ -1,13 +1,11 @@ #ifndef MXHASHTABLE_H #define MXHASHTABLE_H +#include "mxcollection.h" #include "mxcore.h" #include "mxtypes.h" #define HASH_TABLE_INIT_SIZE 128 -#define HASH_TABLE_OPT_NO_EXPAND 0 -#define HASH_TABLE_OPT_EXPAND_ADD 1 -#define HASH_TABLE_OPT_EXPAND_MULTIPLY 2 template class MxHashTableCursor; @@ -15,8 +13,7 @@ class MxHashTableCursor; template class MxHashTableNode { public: - MxHashTableNode() {} - MxHashTableNode(T* p_obj, MxU32 p_hash) + MxHashTableNode(T p_obj, MxU32 p_hash) { m_obj = p_obj; m_hash = p_hash; @@ -24,55 +21,39 @@ class MxHashTableNode { m_next = NULL; } - // private: - T* m_obj; + // DECOMP: Should use getter and setter methods here per the style guide. + // However, LEGO1D (with no functions inlined) does not use them. + T m_obj; MxU32 m_hash; MxHashTableNode* m_prev; MxHashTableNode* m_next; }; -// See MxOmni::Create -// VTABLE 0x100dc1b0 template -class HashTableParent : public MxCore { +class MxHashTable : protected MxCollection { public: - HashTableParent() - { - m_numKeys = 0; - m_customDestructor = Destroy; - } + enum HashTableOpt { + HashTableOpt_NoExpand = 0, + HashTableOpt_ExpandAdd = 1, + HashTableOpt_ExpandMultiply = 2, + }; - static void Destroy(T*){}; - - virtual MxS8 Compare(T*, T*) = 0; - -protected: - MxU32 m_numKeys; // +0x8 - void (*m_customDestructor)(T*); // +0xc -}; - -// VTABLE 0x100dc1e8 -template -class MxHashTable : protected HashTableParent { -public: MxHashTable() { m_numSlots = HASH_TABLE_INIT_SIZE; m_slots = new MxHashTableNode*[HASH_TABLE_INIT_SIZE]; memset(m_slots, 0, sizeof(MxHashTableNode*) * m_numSlots); - m_resizeOption = HASH_TABLE_OPT_NO_EXPAND; + m_resizeOption = HashTableOpt_NoExpand; } - virtual ~MxHashTable(); + virtual ~MxHashTable() override; void Resize(); - void Add(T*); + void Add(T); + void DeleteAll(); - virtual MxS8 Compare(T*, T*) = 0; + virtual MxU32 Hash(T) { return 0; } - virtual MxU32 Hash(T*) = 0; - - // FIXME: use of friend here? friend class MxHashTableCursor; protected: @@ -80,91 +61,108 @@ class MxHashTable : protected HashTableParent { MxHashTableNode** m_slots; // +0x10 MxU32 m_numSlots; // +0x14 - MxU32 m_autoResizeRatio; - int m_resizeOption; // +0x1c + MxU32 m_autoResizeRatio; // +0x18 + HashTableOpt m_resizeOption; // +0x1c // FIXME: or FIXME? This qword is used as an integer or double depending // on the value of m_resizeOption. Hard to say whether this is how the devs // did it, but a simple cast in either direction doesn't match. union { - MxU32 m_increaseAmount; - double m_increaseFactor; + MxU32 m_increaseAmount; // +0x20 + double m_increaseFactor; // +0x20 }; }; template class MxHashTableCursor : public MxCore { public: - MxHashTableCursor(MxHashTable* p_hashTable) + MxHashTableCursor(MxHashTable* p_table) { - m_table = p_hashTable; + m_table = p_table; m_match = NULL; } - MxBool Find(T* p_obj) - { - MxU32 hash = m_table->Hash(p_obj); - int bucket = hash % m_table->m_numSlots; - - MxHashTableNode* t = m_table->m_slots[bucket]; - - while (t) { - if (t->m_hash == hash && !m_table->Compare(t->m_obj, p_obj)) - m_match = t; - t = t->m_next; - } - - return m_match != NULL; - } - - void GetMatch(T*& p_obj) - { - if (m_match) { - p_obj = m_match->m_obj; - } - } - - void DeleteMatch() - { - // Cut the matching node out of the linked list - // by updating pointer references. - - if (m_match->m_prev) { - m_match->m_prev->m_next = m_match->m_next; - } - else { - // No "prev" node, so move "next" to the head of the list. - int bucket = m_match->m_hash % m_table->m_numSlots; - m_table->m_slots[bucket] = m_match->m_next; - } - - if (m_match->m_next) - m_match->m_next->m_prev = m_match->m_prev; - - m_table->m_customDestructor(m_match->m_obj); - delete m_match; - m_table->m_numKeys--; - } + MxBool Find(T p_obj); + MxBool Current(T& p_obj); + void DeleteMatch(); private: MxHashTable* m_table; MxHashTableNode* m_match; }; +template +MxBool MxHashTableCursor::Find(T p_obj) +{ + MxU32 hash = m_table->Hash(p_obj); + MxS32 bucket = hash % m_table->m_numSlots; + + MxHashTableNode* t = m_table->m_slots[bucket]; + + while (t) { + if (t->m_hash == hash && !m_table->Compare(t->m_obj, p_obj)) + m_match = t; + t = t->m_next; + } + + return m_match != NULL; +} + +template +MxBool MxHashTableCursor::Current(T& p_obj) +{ + if (m_match) { + p_obj = m_match->m_obj; + } + + return m_match != NULL; +} + +template +void MxHashTableCursor::DeleteMatch() +{ + // Cut the matching node out of the linked list + // by updating pointer references. + if (m_match == NULL) + return; + + if (m_match->m_prev) { + m_match->m_prev->m_next = m_match->m_next; + } + else { + // No "prev" node, so move "next" to the head of the list. + MxS32 bucket = m_match->m_hash % m_table->m_numSlots; + m_table->m_slots[bucket] = m_match->m_next; + } + + if (m_match->m_next) + m_match->m_next->m_prev = m_match->m_prev; + + m_table->m_customDestructor(m_match->m_obj); + delete m_match; + m_table->m_count--; +} + template MxHashTable::~MxHashTable() { - for (int i = 0; i < m_numSlots; i++) { + DeleteAll(); +} + +template +void MxHashTable::DeleteAll() +{ + for (MxS32 i = 0; i < m_numSlots; i++) { MxHashTableNode* t = m_slots[i]; while (t) { MxHashTableNode* next = t->m_next; - this->m_customDestructor(t->m_obj); + m_customDestructor(t->m_obj); delete t; t = next; } } - this->m_numKeys = 0; + m_count = 0; memset(m_slots, 0, sizeof(MxHashTableNode*) * m_numSlots); delete[] m_slots; @@ -179,21 +177,20 @@ inline void MxHashTable::Resize() MxHashTableNode** old_table = m_slots; switch (m_resizeOption) { - case HASH_TABLE_OPT_EXPAND_ADD: + case HashTableOpt_ExpandAdd: m_numSlots += m_increaseAmount; break; - case HASH_TABLE_OPT_EXPAND_MULTIPLY: + case HashTableOpt_ExpandMultiply: m_numSlots *= m_increaseFactor; break; } MxHashTableNode** new_table = new MxHashTableNode*[m_numSlots]; - // FIXME: order? m_numKeys set after `rep stosd` m_slots = new_table; memset(m_slots, 0, sizeof(MxHashTableNode*) * m_numSlots); - this->m_numKeys = 0; + m_count = 0; - for (int i = 0; i != old_size; i++) { + for (MxS32 i = 0; i != old_size; i++) { MxHashTableNode* t = old_table[i]; while (t) { @@ -209,7 +206,7 @@ inline void MxHashTable::Resize() template inline void MxHashTable::_NodeInsert(MxHashTableNode* p_node) { - int bucket = p_node->m_hash % m_numSlots; + MxS32 bucket = p_node->m_hash % m_numSlots; p_node->m_next = m_slots[bucket]; @@ -217,13 +214,13 @@ inline void MxHashTable::_NodeInsert(MxHashTableNode* p_node) m_slots[bucket]->m_prev = p_node; m_slots[bucket] = p_node; - this->m_numKeys++; + m_count++; } template -inline void MxHashTable::Add(T* p_newobj) +inline void MxHashTable::Add(T p_newobj) { - if (m_resizeOption && ((this->m_numKeys + 1) / m_numSlots) > m_autoResizeRatio) + if (m_resizeOption && ((m_count + 1) / m_numSlots) > m_autoResizeRatio) MxHashTable::Resize(); MxU32 hash = Hash(p_newobj); @@ -232,4 +229,6 @@ inline void MxHashTable::Add(T* p_newobj) MxHashTable::_NodeInsert(node); } +#undef HASH_TABLE_INIT_SIZE + #endif // MXHASHTABLE_H diff --git a/LEGO1/mxlist.h b/LEGO1/mxlist.h index f6093f60..11f0e8ba 100644 --- a/LEGO1/mxlist.h +++ b/LEGO1/mxlist.h @@ -27,9 +27,12 @@ class MxListEntry { } T GetValue() { return this->m_obj; } + MxListEntry* GetNext() { return m_next; } + MxListEntry* GetPrev() { return m_prev; } - friend class MxList; - friend class MxListCursor; + void SetValue(T p_obj) { m_obj = p_obj; } + void SetNext(MxListEntry* p_next) { m_next = p_next; } + void SetPrev(MxListEntry* p_prev) { m_prev = p_prev; } private: T m_obj; @@ -67,10 +70,9 @@ class MxList : protected MxListParent { m_first = NULL; } - virtual ~MxList(); + virtual ~MxList() override; - void Append(T); - void OtherAppend(T p_obj) { _InsertEntry(p_obj, this->m_last, NULL); }; + void Append(T p_obj) { _InsertEntry(p_obj, this->m_last, NULL); }; void DeleteAll(); MxU32 GetCount() { return this->m_count; } void SetDestroy(void (*p_customDestructor)(T)) { this->m_customDestructor = p_customDestructor; } @@ -81,7 +83,6 @@ class MxList : protected MxListParent { MxListEntry* m_first; // +0x10 MxListEntry* m_last; // +0x14 -private: void _DeleteEntry(MxListEntry* match); MxListEntry* _InsertEntry(T, MxListEntry*, MxListEntry*); }; @@ -97,10 +98,15 @@ class MxListCursor : public MxCore { MxBool Find(T p_obj); void Detach(); + void Destroy(); MxBool Next(T& p_obj); + MxBool Current(T& p_obj); + MxBool Advance(); + MxBool HasMatch() { return m_match != NULL; } void SetValue(T p_obj); void Head() { m_match = m_list->m_first; } void Reset() { m_match = NULL; } + void Prepend(T p_newobj); private: MxList* m_list; @@ -134,7 +140,7 @@ inline void MxList::DeleteAll() if (!t) break; - MxListEntry* next = t->m_next; + MxListEntry* next = t->GetNext(); this->m_customDestructor(t->GetValue()); delete t; t = next; @@ -145,33 +151,18 @@ inline void MxList::DeleteAll() m_first = NULL; } -template -inline void MxList::Append(T p_newobj) -{ - MxListEntry* currentLast = this->m_last; - MxListEntry* newEntry = new MxListEntry(p_newobj, currentLast); - - if (currentLast) - currentLast->m_next = newEntry; - else - this->m_first = newEntry; - - this->m_last = newEntry; - this->m_count++; -} - template inline MxListEntry* MxList::_InsertEntry(T p_newobj, MxListEntry* p_prev, MxListEntry* p_next) { MxListEntry* newEntry = new MxListEntry(p_newobj, p_prev, p_next); if (p_prev) - p_prev->m_next = newEntry; + p_prev->SetNext(newEntry); else this->m_first = newEntry; if (p_next) - p_next->m_prev = newEntry; + p_next->SetPrev(newEntry); else this->m_last = newEntry; @@ -182,18 +173,15 @@ inline MxListEntry* MxList::_InsertEntry(T p_newobj, MxListEntry* p_pre template inline void MxList::_DeleteEntry(MxListEntry* match) { - MxListEntry** pPrev = &match->m_prev; - MxListEntry** pNext = &match->m_next; - - if (match->m_prev) - match->m_prev->m_next = *pNext; + if (match->GetPrev()) + match->GetPrev()->SetNext(match->GetNext()); else - m_first = *pNext; + m_first = match->GetNext(); - if (*pNext) - (*pNext)->m_prev = *pPrev; + if (match->GetNext()) + match->GetNext()->SetPrev(match->GetPrev()); else - m_last = *pPrev; + m_last = match->GetPrev(); delete match; this->m_count--; @@ -202,7 +190,8 @@ inline void MxList::_DeleteEntry(MxListEntry* match) template inline MxBool MxListCursor::Find(T p_obj) { - for (m_match = m_list->m_first; m_match && m_list->Compare(m_match->m_obj, p_obj); m_match = m_match->m_next) + for (m_match = m_list->m_first; m_match && m_list->Compare(m_match->GetValue(), p_obj); + m_match = m_match->GetNext()) ; return m_match != NULL; @@ -215,13 +204,22 @@ inline void MxListCursor::Detach() m_match = NULL; } +template +inline void MxListCursor::Destroy() +{ + if (m_match) { + m_list->m_customDestructor(m_match->GetValue()); + Detach(); + } +} + template inline MxBool MxListCursor::Next(T& p_obj) { if (!m_match) m_match = m_list->m_first; else - m_match = m_match->m_next; + m_match = m_match->GetNext(); if (m_match) p_obj = m_match->GetValue(); @@ -229,11 +227,38 @@ inline MxBool MxListCursor::Next(T& p_obj) return m_match != NULL; } +template +inline MxBool MxListCursor::Current(T& p_obj) +{ + if (m_match) + p_obj = m_match->GetValue(); + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Advance() +{ + if (!m_match) + m_match = m_list->m_first; + else + m_match = m_match->GetNext(); + + return m_match != NULL; +} + template inline void MxListCursor::SetValue(T p_obj) { if (m_match) - m_match->m_obj = p_obj; + m_match->SetValue(p_obj); +} + +template +inline void MxListCursor::Prepend(T p_newobj) +{ + if (m_match) + m_list->_InsertEntry(p_newobj, m_match->GetPrev(), m_match); } #endif // MXLIST_H diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index 4350c62c..919b1fa8 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -1,5 +1,12 @@ #include "mxmediapresenter.h" +#include "mxactionnotificationparam.h" +#include "mxautolocker.h" +#include "mxcompositepresenter.h" +#include "mxnotificationmanager.h" +#include "mxstreamchunk.h" +#include "mxtimer.h" + DECOMP_SIZE_ASSERT(MxMediaPresenter, 0x50); // OFFSET: LEGO1 0x1000c550 @@ -8,38 +15,151 @@ MxMediaPresenter::~MxMediaPresenter() Destroy(TRUE); } -// OFFSET: LEGO1 0x100b5d10 STUB -MxResult MxMediaPresenter::Tickle() +// OFFSET: LEGO1 0x1000c5b0 +void MxMediaPresenter::Destroy() { - // TODO - return SUCCESS; + Destroy(FALSE); } // OFFSET: LEGO1 0x100b54e0 void MxMediaPresenter::Init() { - this->m_unk40 = NULL; - this->m_unk44 = NULL; - this->m_unk48 = NULL; - this->m_unk4c = NULL; + this->m_subscriber = NULL; + this->m_chunks = NULL; + this->m_cursor = NULL; + this->m_currentChunk = NULL; } -// OFFSET: LEGO1 0x100b54f0 STUB +// OFFSET: LEGO1 0x100b54f0 void MxMediaPresenter::Destroy(MxBool p_fromDestructor) { - // TODO + { + MxAutoLocker lock(&m_criticalSection); + + if (m_currentChunk && m_subscriber) + m_subscriber->FUN_100b8390(m_currentChunk); + + if (m_subscriber) + delete m_subscriber; + + if (m_cursor) + delete m_cursor; + + if (m_chunks) { + MxStreamChunkListCursor cursor(m_chunks); + MxStreamChunk* chunk; + + while (cursor.Next(chunk)) + chunk->Release(); + + delete m_chunks; + } + + Init(); + } + + if (!p_fromDestructor) + MxPresenter::Destroy(); } -// OFFSET: LEGO1 0x100b5d90 STUB +// OFFSET: LEGO1 0x100b5650 +MxStreamChunk* MxMediaPresenter::FUN_100b5650() +{ + MxStreamChunk* result = NULL; + + if (m_subscriber) { + result = m_subscriber->FUN_100b8360(); + + if (result && result->GetFlags() & MxDSChunk::Flag_Bit3) { + m_action->SetFlags(m_action->GetFlags() | MxDSAction::Flag_Bit7); + m_subscriber->FUN_100b8250(); + m_subscriber->FUN_100b8390(result); + result = NULL; + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Done; + } + } + + return result; +} + +// OFFSET: LEGO1 0x100b56b0 +MxStreamChunk* MxMediaPresenter::NextChunk() +{ + MxStreamChunk* result = NULL; + + if (m_subscriber) { + result = m_subscriber->FUN_100b8250(); + + if (result && result->GetFlags() & MxDSChunk::Flag_Bit3) { + m_action->SetFlags(m_action->GetFlags() | MxDSAction::Flag_Bit7); + m_subscriber->FUN_100b8390(result); + result = NULL; + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Done; + } + } + + return result; +} + +// OFFSET: LEGO1 0x100b5d10 +MxResult MxMediaPresenter::Tickle() +{ + MxAutoLocker lock(&m_criticalSection); + + FUN_100b5650(); + + return MxPresenter::Tickle(); +} + +// OFFSET: LEGO1 0x100b5d90 void MxMediaPresenter::StreamingTickle() { - // TODO + if (!m_currentChunk) { + m_currentChunk = NextChunk(); + + if (m_currentChunk) { + if (m_currentChunk->GetFlags() & MxDSChunk::Flag_Bit2) { + m_subscriber->FUN_100b8390(m_currentChunk); + m_currentChunk = NULL; + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Repeating; + } + else if (m_action->GetFlags() & MxDSAction::Flag_Looping) { + AppendChunk(m_currentChunk); + + if (!MxPresenter::IsEnabled()) { + m_subscriber->FUN_100b8390(m_currentChunk); + m_currentChunk = NULL; + } + } + } + } } -// OFFSET: LEGO1 0x100b5e10 STUB +// OFFSET: LEGO1 0x100b5e10 void MxMediaPresenter::RepeatingTickle() { - // TODO + if (MxPresenter::IsEnabled() && !m_currentChunk) { + if (m_cursor) + if (!m_cursor->Next(m_currentChunk)) + m_cursor->Next(m_currentChunk); + + if (m_currentChunk) { + MxLong time = m_currentChunk->GetTime(); + if (time <= m_action->GetElapsedTime() % m_action->GetLoopCount()) { + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_unk5; + } + } + else { + if (m_action->GetElapsedTime() <= m_action->GetStartTime() + m_action->GetDuration()) { + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_unk5; + } + } + } } // OFFSET: LEGO1 0x100b5ef0 @@ -50,32 +170,99 @@ void MxMediaPresenter::DoneTickle() EndAction(); } -// OFFSET: LEGO1 0x100b6030 STUB +// OFFSET: LEGO1 0x100b6030 void MxMediaPresenter::Enable(MxBool p_enable) { - // TODO + if (MxPresenter::IsEnabled() != p_enable) { + MxPresenter::Enable(p_enable); + + if (p_enable) { + MxLong time = Timer()->GetTime(); + m_action->SetUnkTimingField(time); + SetTickleState(TickleState_Repeating); + } + else { + if (m_cursor) + m_cursor->Reset(); + m_currentChunk = NULL; + SetTickleState(TickleState_Done); + } + } } -// OFFSET: LEGO1 0x1000c5b0 -void MxMediaPresenter::Destroy() +// OFFSET: LEGO1 0x100b5700 +MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) { - Destroy(FALSE); + 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 0x100b5700 STUB -MxLong MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) -{ - return 0; -} - -// OFFSET: LEGO1 0x100b5bc0 STUB +// OFFSET: LEGO1 0x100b5bc0 void MxMediaPresenter::EndAction() { - // TODO + 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 STUB -void MxMediaPresenter::VTable0x58() +// OFFSET: LEGO1 0x100b5f10 +void MxMediaPresenter::AppendChunk(MxStreamChunk* p_chunk) { - // TODO + 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/mxmediapresenter.h b/LEGO1/mxmediapresenter.h index 59ca015b..3706b225 100644 --- a/LEGO1/mxmediapresenter.h +++ b/LEGO1/mxmediapresenter.h @@ -2,15 +2,18 @@ #define MXMEDIAPRESENTER_H #include "decomp.h" +#include "mxdssubscriber.h" #include "mxpresenter.h" +#include "mxstreamchunklist.h" // VTABLE 0x100d4cd8 +// SIZE 0x50 class MxMediaPresenter : public MxPresenter { public: inline MxMediaPresenter() { Init(); } virtual ~MxMediaPresenter() override; - virtual MxResult Tickle() override; + virtual MxResult Tickle() override; // vtable+0x8 // OFFSET: LEGO1 0x1000c5c0 inline virtual const char* ClassName() const override // vtable+0xc @@ -25,23 +28,25 @@ class MxMediaPresenter : public MxPresenter { return !strcmp(name, MxMediaPresenter::ClassName()) || MxPresenter::IsA(name); } - virtual void StreamingTickle() override; - virtual void RepeatingTickle() override; - virtual void DoneTickle() override; - virtual void Destroy() override; - virtual MxLong StartAction(MxStreamController*, MxDSAction*) override; - virtual void EndAction() override; - virtual void Enable(MxBool p_enable) override; - virtual void VTable0x58(); - - undefined4 m_unk40; - undefined4 m_unk44; - undefined4 m_unk48; - undefined4 m_unk4c; + virtual void StreamingTickle() override; // vtable+0x20 + virtual void RepeatingTickle() override; // vtable+0x24 + virtual void DoneTickle() override; // vtable+0x2c + virtual void Destroy() override; // vtable+0x38 + virtual MxResult StartAction(MxStreamController*, MxDSAction*) override; // vtable+0x3c + virtual void EndAction() override; // vtable+0x40 + virtual void Enable(MxBool p_enable) override; // vtable+0x54 + virtual void AppendChunk(MxStreamChunk* p_chunk); // vtable+0x58 protected: + MxDSSubscriber* m_subscriber; // 0x40 + MxStreamChunkList* m_chunks; // 0x44 + MxStreamChunkListCursor* m_cursor; // 0x48 + MxStreamChunk* m_currentChunk; // 0x4c + void Init(); void Destroy(MxBool p_fromDestructor); + MxStreamChunk* FUN_100b5650(); + MxStreamChunk* NextChunk(); }; #endif // MXMEDIAPRESENTER_H diff --git a/LEGO1/mxnextactiondatastart.h b/LEGO1/mxnextactiondatastart.h index 480e39b3..1ef99a70 100644 --- a/LEGO1/mxnextactiondatastart.h +++ b/LEGO1/mxnextactiondatastart.h @@ -4,6 +4,34 @@ #include "mxcore.h" // VTABLE 0x100dc9a0 -class MxNextActionDataStart : public MxCore {}; +// SIZE 0x14 +class MxNextActionDataStart : public MxCore { +public: + // inlined constructor at 0x100c1847 + inline MxNextActionDataStart(MxU32 p_objectId, MxS16 p_unk24val, MxU32 p_data) + { + m_objectId = p_objectId; + m_unk24val = p_unk24val; + m_data = p_data; + } + + // OFFSET: LEGO1 0x100c1900 + inline virtual const char* ClassName() const override // vtable+0xc + { + // 0x101025a0 + return "MxNextActionDataStart"; + } + + // OFFSET: LEGO1 0x100c1910 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, MxNextActionDataStart::ClassName()) || MxCore::IsA(name); + } + +private: + MxU32 m_objectId; + MxS16 m_unk24val; + MxU32 m_data; +}; #endif // MXNEXTACTIONDATASTART_H diff --git a/LEGO1/mxnotificationparam.h b/LEGO1/mxnotificationparam.h index e5654243..ec58fde6 100644 --- a/LEGO1/mxnotificationparam.h +++ b/LEGO1/mxnotificationparam.h @@ -7,11 +7,11 @@ class MxCore; -enum MxParamType { +enum NotificationId { PARAM_NONE = 0, - PAINT = 1, // 100dc210:100d8350 - c_notificationEndAction = 2, // 100d8358:100d8350 - TYPE4 = 4, // 100dc208:100d8350 + c_notificationStartAction = 1, // 100dc210:100d8350 + c_notificationEndAction = 2, // 100d8358:100d8350 + TYPE4 = 4, // 100dc208:100d8350 MXPRESENTER_NOTIFICATION = 5, MXSTREAMER_DELETE_NOTIFY = 6, // 100dc760 c_notificationKeyPress = 7, // 100d6aa0 @@ -36,17 +36,20 @@ enum MxParamType { // VTABLE 0x100d56e0 class MxNotificationParam : public MxParam { public: - inline MxNotificationParam(MxParamType p_type, MxCore* p_sender) : MxParam(), m_type(p_type), m_sender(p_sender) {} + inline MxNotificationParam(NotificationId p_type, MxCore* p_sender) : MxParam(), m_type(p_type), m_sender(p_sender) + { + } virtual ~MxNotificationParam() override {} // vtable+0x0 (scalar deleting destructor) virtual MxNotificationParam* Clone(); // vtable+0x4 - inline MxParamType GetNotification() const { return m_type; } + inline NotificationId GetNotification() const { return m_type; } inline MxCore* GetSender() const { return m_sender; } + inline NotificationId GetType() const { return m_type; } protected: - MxParamType m_type; // 0x4 - MxCore* m_sender; // 0x8 + NotificationId m_type; // 0x4 + MxCore* m_sender; // 0x8 }; #endif // MXNOTIFICATIONPARAM_H diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index edd71d99..469e058a 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -91,11 +91,10 @@ void MxOmni::Vtable0x2c() // TODO } -// OFFSET: LEGO1 0x100aefb0 STUB -int MxOmni::Vtable0x30(char*, int, MxCore*) +// OFFSET: LEGO1 0x100aefb0 +MxEntity* MxOmni::FindWorld(const char*, MxS32, MxPresenter*) { - // TODO - return 0; + return NULL; } // OFFSET: LEGO1 0x100aefc0 diff --git a/LEGO1/mxomni.h b/LEGO1/mxomni.h index 40fad828..bdafe9c1 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -14,12 +14,14 @@ class MxNotificationManager; class MxNotificationParam; class MxObjectFactory; class MxOmniCreateParam; +class MxPresenter; class MxSoundManager; class MxStreamer; class MxTickleManager; class MxTimer; class MxVariableTable; class MxVideoManager; +class MxEntity; // VTABLE 0x100dc168 // SIZE 0x68 @@ -45,7 +47,7 @@ class MxOmni : public MxCore { virtual MxResult DeleteObject(MxDSAction& p_dsAction); // vtable+24 virtual MxBool DoesEntityExist(MxDSAction& p_dsAction); // vtable+28 virtual void Vtable0x2c(); // vtable+2c - virtual int Vtable0x30(char*, int, MxCore*); // vtable+30 + virtual MxEntity* FindWorld(const char*, MxS32, MxPresenter*); // vtable+30 virtual void NotifyCurrentEntity(MxNotificationParam* p_param); // vtable+34 virtual void StartTimer(); // vtable+38 virtual void StopTimer(); // vtable+3c diff --git a/LEGO1/mxomnicreateflags.h b/LEGO1/mxomnicreateflags.h index 7cb8f4ba..f3490a70 100644 --- a/LEGO1/mxomnicreateflags.h +++ b/LEGO1/mxomnicreateflags.h @@ -23,17 +23,17 @@ class MxOmniCreateFlags { __declspec(dllexport) MxOmniCreateFlags(); - const inline MxBool CreateObjectFactory() const { return this->m_flags1 & Flag_CreateObjectFactory; } - const inline MxBool CreateVariableTable() const { return this->m_flags1 & Flag_CreateVariableTable; } - const inline MxBool CreateTickleManager() const { return this->m_flags1 & Flag_CreateTickleManager; } - const inline MxBool CreateNotificationManager() const { return this->m_flags1 & Flag_CreateNotificationManager; } - const inline MxBool CreateVideoManager() const { return this->m_flags1 & Flag_CreateVideoManager; } - const inline MxBool CreateSoundManager() const { return this->m_flags1 & Flag_CreateSoundManager; } - const inline MxBool CreateMusicManager() const { return this->m_flags1 & Flag_CreateMusicManager; } - const inline MxBool CreateEventManager() const { return this->m_flags1 & Flag_CreateEventManager; } + inline const MxBool CreateObjectFactory() const { return this->m_flags1 & Flag_CreateObjectFactory; } + inline const MxBool CreateVariableTable() const { return this->m_flags1 & Flag_CreateVariableTable; } + inline const MxBool CreateTickleManager() const { return this->m_flags1 & Flag_CreateTickleManager; } + inline const MxBool CreateNotificationManager() const { return this->m_flags1 & Flag_CreateNotificationManager; } + inline const MxBool CreateVideoManager() const { return this->m_flags1 & Flag_CreateVideoManager; } + inline const MxBool CreateSoundManager() const { return this->m_flags1 & Flag_CreateSoundManager; } + inline const MxBool CreateMusicManager() const { return this->m_flags1 & Flag_CreateMusicManager; } + inline const MxBool CreateEventManager() const { return this->m_flags1 & Flag_CreateEventManager; } - const inline MxBool CreateTimer() const { return this->m_flags2 & Flag_CreateTimer; } - const inline MxBool CreateStreamer() const { return this->m_flags2 & Flag_CreateStreamer; } + inline const MxBool CreateTimer() const { return this->m_flags2 & Flag_CreateTimer; } + inline const MxBool CreateStreamer() const { return this->m_flags2 & Flag_CreateStreamer; } inline void CreateObjectFactory(MxBool b) { diff --git a/LEGO1/mxomnicreateparam.h b/LEGO1/mxomnicreateparam.h index 12867186..a30d01df 100644 --- a/LEGO1/mxomnicreateparam.h +++ b/LEGO1/mxomnicreateparam.h @@ -17,7 +17,7 @@ class MxOmniCreateParam : public MxParam { MxOmniCreateFlags flags ); - const MxOmniCreateFlags& CreateFlags() const { return this->m_createFlags; } + MxOmniCreateFlags& CreateFlags() { return this->m_createFlags; } const MxString& GetMediaPath() const { return m_mediaPath; } const HWND GetWindowHandle() const { return m_windowHandle; } MxVideoParam& GetVideoParam() { return m_videoParam; } diff --git a/LEGO1/mxpresenter.cpp b/LEGO1/mxpresenter.cpp index 13df6a60..8843bef5 100644 --- a/LEGO1/mxpresenter.cpp +++ b/LEGO1/mxpresenter.cpp @@ -5,6 +5,7 @@ #include "legoomni.h" #include "mxactionnotificationparam.h" #include "mxautolocker.h" +#include "mxcompositepresenter.h" #include "mxdsanim.h" #include "mxdssound.h" #include "mxnotificationmanager.h" @@ -22,7 +23,7 @@ void MxPresenter::Init() m_action = NULL; m_location = MxPoint32(0, 0); m_displayZ = 0; - m_unkPresenter = NULL; + m_compositePresenter = NULL; m_previousTickleStates = 0; } @@ -47,26 +48,26 @@ void MxPresenter::ParseExtra() token = strtok(NULL, g_parseExtraTokens); MxS32 val = token ? atoi(token) : 0; - MxS32 result = MxOmni::GetInstance()->Vtable0x30(t_token, val, this); + MxEntity* result = MxOmni::GetInstance()->FindWorld(t_token, val, this); - m_action->SetFlags(m_action->GetFlags() | MxDSAction::Flag_Parsed); + m_action->SetFlags(m_action->GetFlags() | MxDSAction::Flag_World); if (result) - SendTo_unkPresenter(MxOmni::GetInstance()); + SendToCompositePresenter(MxOmni::GetInstance()); } } } // OFFSET: LEGO1 0x100b5120 -void MxPresenter::SendTo_unkPresenter(MxOmni* p_omni) +void MxPresenter::SendToCompositePresenter(MxOmni* p_omni) { - if (m_unkPresenter) { + if (m_compositePresenter) { MxAutoLocker lock(&m_criticalSection); - NotificationManager()->Send(m_unkPresenter, &MxNotificationParam(MXPRESENTER_NOTIFICATION, this)); + NotificationManager()->Send(m_compositePresenter, &MxNotificationParam(MXPRESENTER_NOTIFICATION, this)); - m_action->SetOmni(p_omni ? p_omni : MxOmni::GetInstance()); - m_unkPresenter = NULL; + m_action->SetUnknown8c(p_omni ? p_omni : MxOmni::GetInstance()); + m_compositePresenter = NULL; } } @@ -116,7 +117,7 @@ MxResult MxPresenter::Tickle() } // OFFSET: LEGO1 0x100b4d80 -MxLong MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action) +MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action) { MxAutoLocker lock(&this->m_criticalSection); @@ -138,8 +139,10 @@ void MxPresenter::EndAction() { if (this->m_action == FALSE) return; + MxAutoLocker lock(&this->m_criticalSection); - if (!this->m_unkPresenter) { + + if (!this->m_compositePresenter) { MxOmni::GetInstance()->NotifyCurrentEntity( &MxEndActionNotificationParam(c_notificationEndAction, NULL, this->m_action, TRUE) ); diff --git a/LEGO1/mxpresenter.h b/LEGO1/mxpresenter.h index ce61fa7e..ea552845 100644 --- a/LEGO1/mxpresenter.h +++ b/LEGO1/mxpresenter.h @@ -8,9 +8,11 @@ #include "mxomni.h" #include "mxpoint32.h" +class MxCompositePresenter; class MxStreamController; // VTABLE 0x100d4d38 +// SIZE 0x40 class MxPresenter : public MxCore { public: enum TickleState { @@ -53,15 +55,15 @@ class MxPresenter : public MxCore { __declspec(dllexport) virtual void ParseExtra(); // vtable+0x30 public: - virtual MxResult AddToManager(); // vtable+0x34 - virtual void Destroy(); // vtable+0x38 - __declspec(dllexport) virtual MxLong StartAction(MxStreamController*, MxDSAction*); // vtable+0x3c - __declspec(dllexport) virtual void EndAction(); // vtable+0x40 - virtual void SetTickleState(TickleState p_tickleState); // vtable+0x44 - virtual MxBool HasTickleStatePassed(TickleState p_tickleState); // vtable+0x48 - virtual undefined4 PutData(); // vtable+0x4c - virtual MxBool IsHit(MxS32 p_x, MxS32 p_y); // vtable+0x50 - __declspec(dllexport) virtual void Enable(MxBool p_enable); // vtable+0x54 + virtual MxResult AddToManager(); // vtable+0x34 + virtual void Destroy(); // vtable+0x38 + __declspec(dllexport) virtual MxResult StartAction(MxStreamController*, MxDSAction*); // vtable+0x3c + __declspec(dllexport) virtual void EndAction(); // vtable+0x40 + virtual void SetTickleState(TickleState p_tickleState); // vtable+0x44 + virtual MxBool HasTickleStatePassed(TickleState p_tickleState); // vtable+0x48 + virtual undefined4 PutData(); // vtable+0x4c + virtual MxBool IsHit(MxS32 p_x, MxS32 p_y); // vtable+0x50 + __declspec(dllexport) virtual void Enable(MxBool p_enable); // vtable+0x54 MxBool IsEnabled(); @@ -74,14 +76,15 @@ class MxPresenter : public MxCore { protected: __declspec(dllexport) void Init(); - void SendTo_unkPresenter(MxOmni*); - TickleState m_currentTickleState; // 0x8 - MxU32 m_previousTickleStates; // 0x0c - MxPoint32 m_location; // 0x10 - MxS32 m_displayZ; // 0x18 - MxDSAction* m_action; // 0x1c - MxCriticalSection m_criticalSection; // 0x20 - MxPresenter* m_unkPresenter; // 0x3c + void SendToCompositePresenter(MxOmni*); + + TickleState m_currentTickleState; // 0x8 + MxU32 m_previousTickleStates; // 0x0c + MxPoint32 m_location; // 0x10 + MxS32 m_displayZ; // 0x18 + MxDSAction* m_action; // 0x1c + MxCriticalSection m_criticalSection; // 0x20 + MxCompositePresenter* m_compositePresenter; // 0x3c }; const char* PresenterNameDispatch(const MxDSAction&); diff --git a/LEGO1/mxpresenterlist.cpp b/LEGO1/mxpresenterlist.cpp index fb95aa99..f6ed6594 100644 --- a/LEGO1/mxpresenterlist.cpp +++ b/LEGO1/mxpresenterlist.cpp @@ -6,11 +6,7 @@ DECOMP_SIZE_ASSERT(MxPresenterList, 0x18); DECOMP_SIZE_ASSERT(MxPresenterListCursor, 0x10); // OFFSET: LEGO1 0x1001cd00 -MxS8 MxPresenterList::Compare(MxPresenter* p_var0, MxPresenter* p_var1) +MxS8 MxPresenterList::Compare(MxPresenter* p_a, MxPresenter* p_b) { - if (p_var1 == p_var0) - return 0; - if (p_var1 <= p_var0) - return 1; - return -1; + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; } diff --git a/LEGO1/mxpresenterlist.h b/LEGO1/mxpresenterlist.h index b1a780bc..350d6c17 100644 --- a/LEGO1/mxpresenterlist.h +++ b/LEGO1/mxpresenterlist.h @@ -17,7 +17,7 @@ class MxPresenterListParent : public MxList { // SIZE 0x18 class MxPresenterList : public MxPresenterListParent { public: - virtual MxS8 Compare(MxPresenter*, MxPresenter*); // +0x14 + virtual MxS8 Compare(MxPresenter*, MxPresenter*) override; // +0x14 }; typedef MxListCursorChildChild MxPresenterListCursor; diff --git a/LEGO1/mxqueue.h b/LEGO1/mxqueue.h new file mode 100644 index 00000000..fd22cb0a --- /dev/null +++ b/LEGO1/mxqueue.h @@ -0,0 +1,26 @@ +#ifndef MXQUEUE_H +#define MXQUEUE_H + +#include "mxlist.h" + +template +class MxQueue : public MxList { +public: + void Enqueue(T& p_obj) + { + // TODO + } + + MxBool Dequeue(T& p_obj) + { + MxBool has_next = (m_first != NULL); + if (m_first) { + p_obj = m_first->GetValue(); + _DeleteEntry(m_first); + } + + return has_next; + } +}; + +#endif // MXQUEUE_H diff --git a/LEGO1/mxramstreamcontroller.cpp b/LEGO1/mxramstreamcontroller.cpp index ae3d9634..2e8efc36 100644 --- a/LEGO1/mxramstreamcontroller.cpp +++ b/LEGO1/mxramstreamcontroller.cpp @@ -29,7 +29,7 @@ MxResult MxRAMStreamController::Open(const char* p_filename) ((MxRAMStreamProvider*) m_provider)->GetBufferOfFileSize(), ((MxRAMStreamProvider*) m_provider)->GetFileSize() ); - m_buffer.FUN_100c6780( + m_buffer.SetBufferPointer( ((MxRAMStreamProvider*) m_provider)->GetBufferOfFileSize(), ((MxRAMStreamProvider*) m_provider)->GetFileSize() ); diff --git a/LEGO1/mxramstreamprovider.h b/LEGO1/mxramstreamprovider.h index ba32768a..0dfd33ef 100644 --- a/LEGO1/mxramstreamprovider.h +++ b/LEGO1/mxramstreamprovider.h @@ -9,6 +9,19 @@ class MxRAMStreamProvider : public MxStreamProvider { MxRAMStreamProvider(); virtual ~MxRAMStreamProvider() override; + // OFFSET: LEGO1 0x100d0970 + inline virtual const char* ClassName() const override // vtable+0xc + { + // 0x10102864 + return "MxRAMStreamProvider"; + } + + // OFFSET: LEGO1 0x100d0980 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, MxRAMStreamProvider::ClassName()) || MxStreamProvider::IsA(name); + } + virtual MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14 virtual MxU32 GetFileSize() override; // vtable+0x18 virtual MxU32 GetStreamBuffersNum() override; // vtable+0x1c diff --git a/LEGO1/mxrect32.h b/LEGO1/mxrect32.h index c3381d46..070c3d25 100644 --- a/LEGO1/mxrect32.h +++ b/LEGO1/mxrect32.h @@ -1,6 +1,9 @@ #ifndef MXRECT32_H #define MXRECT32_H +#include "mxpoint32.h" +#include "mxsize32.h" + class MxRect32 { public: MxRect32() {} @@ -12,14 +15,72 @@ class MxRect32 { this->m_bottom = p_bottom; } + MxRect32(const MxPoint32& p_point, const MxSize32& p_size) + { + this->m_left = p_point.m_x; + this->m_top = p_point.m_y; + this->m_right = p_size.m_width; + this->m_bottom = p_size.m_height; + } + + MxRect32(const MxRect32& p_a, const MxRect32& p_b) + { + m_left = Max(p_a.m_left, p_b.m_left); + m_top = Max(p_a.m_top, p_b.m_top); + m_right = Min(p_a.m_right, p_b.m_right); + m_bottom = Min(p_a.m_bottom, p_b.m_bottom); + } + + inline void SetPoint(const MxPoint32& p_point) + { + this->m_left = p_point.m_x; + this->m_top = p_point.m_y; + } + + inline void SetSize(const MxSize32& p_size) + { + this->m_right = p_size.m_width; + this->m_bottom = p_size.m_height; + } + + inline MxBool IsValid() { return m_left < m_right && m_top < m_bottom; } + inline MxBool IntersectsWith(const MxRect32& p_rect) + { + return m_left < p_rect.m_right && p_rect.m_left < m_right && m_top < p_rect.m_bottom && p_rect.m_top < m_bottom; + } + + inline void UpdateBounds(const MxRect32& p_rect) + { + m_left = Min(m_left, p_rect.m_left); + m_top = Min(m_top, p_rect.m_top); + m_right = Max(m_right, p_rect.m_right); + m_bottom = Max(m_bottom, p_rect.m_bottom); + } + + inline MxS32 GetWidth() { return (m_right - m_left) + 1; } + inline MxS32 GetHeight() { return (m_bottom - m_top) + 1; } + + inline MxPoint32 GetPoint() { return MxPoint32(this->m_left, this->m_top); } + inline MxSize32 GetSize() { return MxSize32(this->m_right, this->m_bottom); } + + inline MxS32 GetLeft() { return m_left; } + inline MxS32 GetTop() { return m_top; } + inline MxS32 GetRight() { return m_right; } + inline MxS32 GetBottom() { return m_bottom; } + + inline void SetLeft(MxS32 p_left) { m_left = p_left; } + inline void SetTop(MxS32 p_top) { m_top = p_top; } + inline void SetRight(MxS32 p_right) { m_right = p_right; } + inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; } + +private: + inline static MxS32 Min(MxS32 a, MxS32 b) { return a <= b ? a : b; }; + inline static MxS32 Max(MxS32 a, MxS32 b) { return a <= b ? b : a; }; + MxS32 m_left; MxS32 m_top; MxS32 m_right; MxS32 m_bottom; - - inline MxS32 GetWidth() { return (m_right - m_left) + 1; } - - inline MxS32 GetHeight() { return (m_bottom - m_top) + 1; } }; #endif // MXRECT32_H diff --git a/LEGO1/mxregion.cpp b/LEGO1/mxregion.cpp index 5b7237cb..d338f322 100644 --- a/LEGO1/mxregion.cpp +++ b/LEGO1/mxregion.cpp @@ -1,40 +1,198 @@ #include "mxregion.h" -DECOMP_SIZE_ASSERT(MxRegion, 0x1c); +#include -// OFFSET: LEGO1 0x100c31c0 STUB +DECOMP_SIZE_ASSERT(MxRegion, 0x1c); +DECOMP_SIZE_ASSERT(MxRegionTopBottom, 0x0c); +DECOMP_SIZE_ASSERT(MxRegionLeftRight, 0x08); + +// OFFSET: LEGO1 0x100c31c0 MxRegion::MxRegion() { - // TODO + m_list = new MxRegionList; + m_rect.SetPoint(MxPoint32(INT_MAX, INT_MAX)); + m_rect.SetSize(MxSize32(-1, -1)); } -// OFFSET: LEGO1 0x100c3690 STUB -MxRegion::~MxRegion() -{ - // TODO -} - -// OFFSET: LEGO1 0x100c3700 STUB -void MxRegion::Reset() -{ - // TODO -} - -// OFFSET: LEGO1 0x100c3750 STUB -void MxRegion::vtable18(MxRect32& p_rect) -{ - // TODO -} - -// OFFSET: LEGO1 0x100c3e20 STUB -void MxRegion::vtable1c() -{ - // TODO -} - -// OFFSET: LEGO1 0x100c3660 STUB +// OFFSET: LEGO1 0x100c3660 MxBool MxRegion::vtable20() { - // TODO + return m_list->GetCount() == 0; +} + +// OFFSET: LEGO1 0x100c3690 +MxRegion::~MxRegion() +{ + if (m_list) + delete m_list; +} + +// OFFSET: LEGO1 0x100c3700 +void MxRegion::Reset() +{ + m_list->DeleteAll(); + m_rect.SetPoint(MxPoint32(INT_MAX, INT_MAX)); + m_rect.SetSize(MxSize32(-1, -1)); +} + +// OFFSET: LEGO1 0x100c3750 +void MxRegion::vtable18(MxRect32& p_rect) +{ + MxRect32 rect(p_rect.GetPoint(), MxSize32(p_rect.GetRight(), p_rect.GetBottom())); + MxRegionListCursor cursor(m_list); + MxRegionTopBottom* topBottom; + + while (rect.IsValid() && cursor.Next(topBottom)) { + if (topBottom->GetTop() >= rect.GetBottom()) { + MxRegionTopBottom* newTopBottom = new MxRegionTopBottom(rect); + cursor.Prepend(newTopBottom); + rect.SetTop(rect.GetBottom()); + } + else if (rect.GetTop() < topBottom->GetBottom()) { + if (rect.GetTop() < topBottom->GetTop()) { + MxRect32 newRect(rect); + newRect.SetBottom(topBottom->GetTop()); + MxRegionTopBottom* newTopBottom = new MxRegionTopBottom(newRect); + cursor.Prepend(newTopBottom); + rect.SetTop(topBottom->GetTop()); + } + else if (topBottom->GetTop() < rect.GetTop()) { + MxRegionTopBottom* newTopBottom = topBottom->Clone(); + newTopBottom->SetBottom(rect.GetTop()); + topBottom->SetTop(rect.GetTop()); + cursor.Prepend(newTopBottom); + } + + if (rect.GetBottom() < topBottom->GetBottom()) { + MxRegionTopBottom* newTopBottom = topBottom->Clone(); + newTopBottom->SetBottom(rect.GetBottom()); + topBottom->SetTop(rect.GetBottom()); + newTopBottom->FUN_100c5280(rect.GetLeft(), rect.GetRight()); + cursor.Prepend(newTopBottom); + rect.SetTop(rect.GetBottom()); + } + else { + topBottom->FUN_100c5280(rect.GetLeft(), rect.GetRight()); + rect.SetTop(topBottom->GetBottom()); + } + } + } + + if (rect.IsValid()) { + MxRegionTopBottom* newTopBottom = new MxRegionTopBottom(rect); + m_list->Append(newTopBottom); + } + + m_rect.UpdateBounds(p_rect); +} + +// OFFSET: LEGO1 0x100c3e20 +MxBool MxRegion::vtable1c(MxRect32& p_rect) +{ + if (!m_rect.IntersectsWith(p_rect)) + return FALSE; + + MxRegionListCursor cursor(m_list); + MxRegionTopBottom* topBottom; + + while (cursor.Next(topBottom)) { + if (topBottom->GetTop() >= p_rect.GetBottom()) + return FALSE; + if (topBottom->GetBottom() > p_rect.GetTop() && topBottom->FUN_100c57b0(p_rect)) + return TRUE; + } + + return FALSE; +} + +// OFFSET: LEGO1 0x100c4c90 +MxRegionTopBottom::MxRegionTopBottom(MxS32 p_top, MxS32 p_bottom) +{ + m_top = p_top; + m_bottom = p_bottom; + m_leftRightList = new MxRegionLeftRightList; +} + +// OFFSET: LEGO1 0x100c50e0 +MxRegionTopBottom::MxRegionTopBottom(MxRect32& p_rect) +{ + m_top = p_rect.GetTop(); + m_bottom = p_rect.GetBottom(); + m_leftRightList = new MxRegionLeftRightList; + + MxRegionLeftRight* leftRight = new MxRegionLeftRight(p_rect.GetLeft(), p_rect.GetRight()); + m_leftRightList->Append(leftRight); +} + +// OFFSET: LEGO1 0x100c5280 +void MxRegionTopBottom::FUN_100c5280(MxS32 p_left, MxS32 p_right) +{ + MxRegionLeftRightListCursor a(m_leftRightList); + MxRegionLeftRightListCursor b(m_leftRightList); + + MxRegionLeftRight* leftRight; + while (a.Next(leftRight) && leftRight->GetRight() < p_left) + ; + + if (!a.HasMatch()) { + MxRegionLeftRight* copy = new MxRegionLeftRight(p_left, p_right); + m_leftRightList->Append(copy); + } + else { + if (p_left > leftRight->GetLeft()) + p_left = leftRight->GetLeft(); + + while (leftRight->GetLeft() < p_right) { + if (p_right < leftRight->GetRight()) + p_right = leftRight->GetRight(); + + b = a; + b.Advance(); + a.Destroy(); + + if (!b.Current(leftRight)) + break; + + a = b; + } + + if (a.HasMatch()) { + MxRegionLeftRight* copy = new MxRegionLeftRight(p_left, p_right); + a.Prepend(copy); + } + else { + MxRegionLeftRight* copy = new MxRegionLeftRight(p_left, p_right); + m_leftRightList->Append(copy); + } + } +} + +// OFFSET: LEGO1 0x100c55d0 +MxRegionTopBottom* MxRegionTopBottom::Clone() +{ + MxRegionTopBottom* clone = new MxRegionTopBottom(m_top, m_bottom); + + MxRegionLeftRightListCursor cursor(m_leftRightList); + MxRegionLeftRight* leftRight; + + while (cursor.Next(leftRight)) + clone->m_leftRightList->Append(leftRight->Clone()); + + return clone; +} + +// OFFSET: LEGO1 0x100c57b0 +MxBool MxRegionTopBottom::FUN_100c57b0(MxRect32& p_rect) +{ + MxRegionLeftRightListCursor cursor(m_leftRightList); + MxRegionLeftRight* leftRight; + + while (cursor.Next(leftRight)) { + if (p_rect.GetRight() <= leftRight->GetLeft()) + return FALSE; + if (leftRight->GetRight() > p_rect.GetLeft()) + return TRUE; + } + return FALSE; } diff --git a/LEGO1/mxregion.h b/LEGO1/mxregion.h index 25482207..ac6acd5e 100644 --- a/LEGO1/mxregion.h +++ b/LEGO1/mxregion.h @@ -4,6 +4,51 @@ #include "decomp.h" #include "mxcore.h" #include "mxrect32.h" +#include "mxregionlist.h" + +// SIZE 0x0c +struct MxRegionTopBottom { + MxRegionTopBottom(MxRect32& p_rect); + MxRegionTopBottom(MxS32 m_top, MxS32 m_bottom); + + MxRegionTopBottom* Clone(); + void FUN_100c5280(MxS32 p_left, MxS32 p_right); + MxBool FUN_100c57b0(MxRect32& p_rect); + + inline MxS32 GetTop() { return m_top; } + inline MxS32 GetBottom() { return m_bottom; } + + inline void SetTop(MxS32 p_top) { m_top = p_top; } + inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; } + + friend class MxRegionListParent; + +private: + MxS32 m_top; + MxS32 m_bottom; + MxRegionLeftRightList* m_leftRightList; +}; + +// SIZE 0x08 +struct MxRegionLeftRight { + MxRegionLeftRight(MxS32 p_left, MxS32 p_right) + { + m_left = p_left; + m_right = p_right; + } + + MxRegionLeftRight* Clone() { return new MxRegionLeftRight(m_left, m_right); } + + inline MxS32 GetLeft() { return m_left; } + inline MxS32 GetRight() { return m_right; } + + inline void SetLeft(MxS32 p_left) { m_left = p_left; } + inline void SetRight(MxS32 p_right) { m_right = p_right; } + +private: + MxS32 m_left; + MxS32 m_right; +}; // VTABLE 0x100dcae8 // SIZE 0x1c @@ -14,15 +59,13 @@ class MxRegion : public MxCore { virtual void Reset(); virtual void vtable18(MxRect32& p_rect); - virtual void vtable1c(); + virtual MxBool vtable1c(MxRect32& p_rect); virtual MxBool vtable20(); inline MxRect32& GetRect() { return this->m_rect; } private: - // A container (probably MxList) holding MxRect32 - // MxList *m_rects; - undefined4 m_unk08; + MxRegionList* m_list; MxRect32 m_rect; }; diff --git a/LEGO1/mxregionlist.cpp b/LEGO1/mxregionlist.cpp new file mode 100644 index 00000000..a33d78b7 --- /dev/null +++ b/LEGO1/mxregionlist.cpp @@ -0,0 +1,19 @@ +#include "mxregionlist.h" + +#include "mxregion.h" + +// OFFSET: LEGO1 0x100c33e0 +void MxRegionListParent::Destroy(MxRegionTopBottom* p_topBottom) +{ + if (p_topBottom) { + if (p_topBottom->m_leftRightList) + delete p_topBottom->m_leftRightList; + delete p_topBottom; + } +} + +// OFFSET: LEGO1 0x100c4e80 +void MxRegionLeftRightListParent::Destroy(MxRegionLeftRight* p_leftRight) +{ + delete p_leftRight; +} diff --git a/LEGO1/mxregionlist.h b/LEGO1/mxregionlist.h new file mode 100644 index 00000000..52336d38 --- /dev/null +++ b/LEGO1/mxregionlist.h @@ -0,0 +1,56 @@ +#ifndef MXREGIONLIST_H +#define MXREGIONLIST_H + +#include "mxlist.h" + +struct MxRegionTopBottom; +struct MxRegionLeftRight; + +// VTABLE 0x100dcb40 +// SIZE 0x18 +class MxRegionListParent : public MxList { +public: + static void Destroy(MxRegionTopBottom* p_topBottom); + + MxRegionListParent() { m_customDestructor = Destroy; } +}; + +// VTABLE 0x100dcb58 +// SIZE 0x18 +class MxRegionList : public MxRegionListParent {}; + +// VTABLE 0x100dcb88 +typedef MxListCursorChildChild MxRegionListCursor; + +// OFFSET: LEGO1 0x100c5970 TEMPLATE +// MxList::_InsertEntry + +// OFFSET: LEGO1 0x100c5a20 TEMPLATE +// MxListEntry::MxListEntry + +// VTABLE 0x100dcc70 +// SIZE 0x18 +class MxRegionLeftRightListParent : public MxList { +public: + static void Destroy(MxRegionLeftRight* p_leftRight); + + MxRegionLeftRightListParent() { m_customDestructor = Destroy; } +}; + +// VTABLE 0x100dcc88 +// SIZE 0x18 +class MxRegionLeftRightList : public MxRegionLeftRightListParent {}; + +// VTABLE 0x100dcc10 +typedef MxListCursorChildChild MxRegionLeftRightListCursor; + +// OFFSET: LEGO1 0x100c54f0 TEMPLATE +// MxListCursor::MxListCursor + +// OFFSET: LEGO1 0x100c58c0 TEMPLATE +// MxList::_InsertEntry + +// OFFSET: LEGO1 0x100c5a40 TEMPLATE +// MxList::_DeleteEntry + +#endif // MXREGIONLIST_H diff --git a/LEGO1/mxsize32.h b/LEGO1/mxsize32.h new file mode 100644 index 00000000..a55326cc --- /dev/null +++ b/LEGO1/mxsize32.h @@ -0,0 +1,19 @@ +#ifndef MXSIZE32_H +#define MXSIZE32_H + +#include "mxtypes.h" + +class MxSize32 { +public: + MxSize32() {} + MxSize32(MxS32 p_width, MxS32 p_height) + { + this->m_width = p_width; + this->m_height = p_height; + } + + MxS32 m_width; + MxS32 m_height; +}; + +#endif // MXSIZE32_H diff --git a/LEGO1/mxsmkpresenter.cpp b/LEGO1/mxsmkpresenter.cpp index 126c9a7a..c4c2224e 100644 --- a/LEGO1/mxsmkpresenter.cpp +++ b/LEGO1/mxsmkpresenter.cpp @@ -1,6 +1,7 @@ #include "mxsmkpresenter.h" #include "decomp.h" +#include "mxvideomanager.h" DECOMP_SIZE_ASSERT(MxSmkPresenter, 0x720); @@ -65,3 +66,48 @@ void MxSmkPresenter::FUN_100c5d40(MxSmack* p_mxSmack) 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() +{ + MxU32 result = m_unk0x71c; + if ((m_mxSmack.m_smack.m_smkType & 1) != 0) { + result = m_unk0x71c / m_mxSmack.m_smack.m_frames; + if (1 < m_unk0x71c && (m_unk0x71c % m_mxSmack.m_smack.m_frames) == 1) { + m_unk0x71c = 1; + } + return result; + } + else { + if (m_mxSmack.m_smack.m_frames == result) { + m_unk0x71c = 0; + result = 0; + memset(m_mxSmack.m_smack.m_palette, 0, sizeof(m_mxSmack.m_smack.m_palette)); + } + return result; + } +} diff --git a/LEGO1/mxsmkpresenter.h b/LEGO1/mxsmkpresenter.h index 29b23afc..549c65b7 100644 --- a/LEGO1/mxsmkpresenter.h +++ b/LEGO1/mxsmkpresenter.h @@ -13,7 +13,25 @@ class MxSmkPresenter : public MxVideoPresenter { MxSmkPresenter(); virtual ~MxSmkPresenter() override; + // OFFSET: LEGO1 0x100b3730 + inline virtual const char* ClassName() const override // vtable+0xc + { + // 0x10101e38 + return "MxSmkPresenter"; + } + + // OFFSET: LEGO1 0x100b3740 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, MxSmkPresenter::ClassName()) || MxVideoPresenter::IsA(name); + } + + virtual void Destroy() override; + virtual void VTable0x5c(undefined4 p_unknown1) override; virtual void VTable0x60() override; + virtual void VTable0x68(undefined4 p_unknown1) override; // vtable+0x68 + virtual void VTable0x70() override; + virtual MxU32 VTable0x88(); struct MxSmack { Smack m_smack; diff --git a/LEGO1/mxsoundmanager.cpp b/LEGO1/mxsoundmanager.cpp index 937cad63..a57672d3 100644 --- a/LEGO1/mxsoundmanager.cpp +++ b/LEGO1/mxsoundmanager.cpp @@ -1,5 +1,6 @@ #include "mxsoundmanager.h" +#include "define.h" #include "mxautolocker.h" #include "mxomni.h" #include "mxpresenter.h" @@ -127,6 +128,53 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) return status; } +// OFFSET: LEGO1 0x100aeab0 +void MxSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100aeac0 +void MxSoundManager::SetVolume(MxS32 p_volume) +{ + MxAudioManager::SetVolume(p_volume); + + m_criticalSection.Enter(); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) + ((MxAudioPresenter*) presenter)->vtable60(((MxAudioPresenter*) presenter)->vtable5c()); + + m_criticalSection.Leave(); +} + +// OFFSET: LEGO1 0x100aebd0 +MxPresenter* MxSoundManager::FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId) +{ + MxAutoLocker lock(&m_criticalSection); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) { + if (presenter->GetAction()->GetAtomId().GetInternal() == p_atomId.GetInternal() && + presenter->GetAction()->GetObjectId() == p_objectId) + return presenter; + } + + return NULL; +} + +// OFFSET: LEGO1 0x100aecf0 +MxS32 MxSoundManager::FUN_100aecf0(MxU32 p_unk) +{ + if (!p_unk) + return -10000; + return g_mxcoreCount[p_unk]; +} + // OFFSET: LEGO1 0x100aed10 void MxSoundManager::vtable0x34() { @@ -152,25 +200,3 @@ void MxSoundManager::vtable0x38() if (presenter->IsA("MxWavePresenter")) ((MxWavePresenter*) presenter)->VTable0x68(); } - -// OFFSET: LEGO1 0x100aeab0 -void MxSoundManager::Destroy() -{ - Destroy(FALSE); -} - -// OFFSET: LEGO1 0x100aeac0 -void MxSoundManager::SetVolume(MxS32 p_volume) -{ - MxAudioManager::SetVolume(p_volume); - - m_criticalSection.Enter(); - - MxPresenter* presenter; - MxPresenterListCursor cursor(m_presenters); - - while (cursor.Next(presenter)) - ((MxAudioPresenter*) presenter)->vtable60(((MxAudioPresenter*) presenter)->vtable5c()); - - m_criticalSection.Leave(); -} diff --git a/LEGO1/mxsoundmanager.h b/LEGO1/mxsoundmanager.h index ef42e8df..5fc5dfb3 100644 --- a/LEGO1/mxsoundmanager.h +++ b/LEGO1/mxsoundmanager.h @@ -2,6 +2,7 @@ #define MXSOUNDMANAGER_H #include "decomp.h" +#include "mxatomid.h" #include "mxaudiomanager.h" #include @@ -11,6 +12,9 @@ class MxSoundManager : public MxAudioManager { public: MxSoundManager(); + + // OFFSET: LEGO1 0x100ae7b0 TEMPLATE + // MxSoundManager::`scalar deleting destructor' virtual ~MxSoundManager() override; // vtable+0x0 virtual void Destroy() override; // vtable+18 @@ -22,6 +26,8 @@ class MxSoundManager : public MxAudioManager { private: void Init(); void Destroy(MxBool p_fromDestructor); + MxPresenter* FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId); + MxS32 FUN_100aecf0(MxU32 p_unk); LPDIRECTSOUND m_directSound; // 0x30 LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x34 diff --git a/LEGO1/mxstillpresenter.h b/LEGO1/mxstillpresenter.h index f812b545..d2e89f59 100644 --- a/LEGO1/mxstillpresenter.h +++ b/LEGO1/mxstillpresenter.h @@ -8,6 +8,19 @@ // SIZE 0x6c class MxStillPresenter : public MxVideoPresenter { public: + // OFFSET: LEGO1 0x100435c0 + inline virtual const char* ClassName() const override // vtable+0xc + { + // 0x100f0184 + return "MxStillPresenter"; + } + + // OFFSET: LEGO1 0x100435d0 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, MxStillPresenter::ClassName()) || MxVideoPresenter::IsA(name); + } + virtual void ParseExtra() override; // vtable+0x30 MxStillPresenter() { m_unk68 = 0; } diff --git a/LEGO1/mxstreamchunk.h b/LEGO1/mxstreamchunk.h index 5043b722..f31f891a 100644 --- a/LEGO1/mxstreamchunk.h +++ b/LEGO1/mxstreamchunk.h @@ -4,6 +4,26 @@ #include "mxdschunk.h" // VTABLE 0x100dc2a8 -class MxStreamChunk : public MxDSChunk {}; +// SIZE 0x20 +class MxStreamChunk : public MxDSChunk { +public: + inline MxStreamChunk() : m_unk1c(NULL) {} + + // OFFSET: LEGO1 0x100b1fe0 + inline virtual const char* ClassName() const override // vtable+0xc + { + // 0x10101e5c + return "MxStreamChunk"; + } + + // OFFSET: LEGO1 0x100b1ff0 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, MxStreamChunk::ClassName()) || MxDSChunk::IsA(name); + } + +private: + void* m_unk1c; // 0x1c +}; #endif // MXSTREAMCHUNK_H diff --git a/LEGO1/mxstreamchunklist.cpp b/LEGO1/mxstreamchunklist.cpp new file mode 100644 index 00000000..8c76452e --- /dev/null +++ b/LEGO1/mxstreamchunklist.cpp @@ -0,0 +1,19 @@ +#include "mxstreamchunklist.h" + +#include "mxstreamchunk.h" + +DECOMP_SIZE_ASSERT(MxStreamChunkList, 0x18); +DECOMP_SIZE_ASSERT(MxStreamChunkListCursor, 0x10); + +// OFFSET: LEGO1 0x100b5900 +MxS8 MxStreamChunkList::Compare(MxStreamChunk* p_a, MxStreamChunk* p_b) +{ + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; +} + +// OFFSET: LEGO1 0x100b5920 +void MxStreamChunkList::Destroy(MxStreamChunk* p_chunk) +{ + if (p_chunk) + delete p_chunk; +} diff --git a/LEGO1/mxstreamchunklist.h b/LEGO1/mxstreamchunklist.h new file mode 100644 index 00000000..3a19950b --- /dev/null +++ b/LEGO1/mxstreamchunklist.h @@ -0,0 +1,34 @@ +#ifndef MXSTREAMCHUNKLIST_H +#define MXSTREAMCHUNKLIST_H + +#include "decomp.h" +#include "mxlist.h" + +class MxStreamChunk; + +// VTABLE 0x100dc600 +// SIZE 0x18 +class MxStreamChunkList : public MxList { +public: + MxStreamChunkList() { m_customDestructor = Destroy; } + + virtual MxS8 Compare(MxStreamChunk*, MxStreamChunk*) override; // +0x14 + + static void Destroy(MxStreamChunk* p_chunk); +}; + +typedef MxListCursorChild MxStreamChunkListCursor; + +// OFFSET: LEGO1 0x100b5930 TEMPLATE +// MxListParent::Compare + +// OFFSET: LEGO1 0x100b5990 TEMPLATE +// MxListParent::Destroy + +// OFFSET: LEGO1 0x100b59a0 TEMPLATE +// MxList::~MxList + +// OFFSET: LEGO1 0x100b5b10 TEMPLATE +// MxList::`scalar deleting destructor' + +#endif // MXSTREAMCHUNKLIST_H diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp index 72f77b33..1fb3ae03 100644 --- a/LEGO1/mxstreamcontroller.cpp +++ b/LEGO1/mxstreamcontroller.cpp @@ -2,6 +2,9 @@ #include "legoomni.h" #include "mxautolocker.h" +#include "mxnextactiondatastart.h" + +DECOMP_SIZE_ASSERT(MxNextActionDataStart, 0x14) // OFFSET: LEGO1 0x100c0b90 STUB MxStreamController::MxStreamController() @@ -74,16 +77,32 @@ MxResult MxStreamController::vtable0x24(undefined4 p_unknown) return FAILURE; } +// OFFSET: LEGO1 0x100c1800 STUB +MxResult MxStreamController::FUN_100c1800(MxDSAction* p_action, MxU32 p_val) +{ + MxNextActionDataStart* dataActionStart = + new MxNextActionDataStart(p_action->GetObjectId(), p_action->GetUnknown24(), p_val); + if (dataActionStart == NULL) { + return FAILURE; + } + // TODO: insert dataActionStart to a list + return FAILURE; +} + // OFFSET: LEGO1 0x100b9420 MxResult MxStreamController::vtable0x28() { return SUCCESS; } -// OFFSET: LEGO1 0x100c1c10 STUB +// OFFSET: LEGO1 0x100c1c10 MxResult MxStreamController::vtable0x2c(MxDSAction* p_action, MxU32 p_bufferval) { - return FAILURE; + MxAutoLocker locker(&m_criticalSection); + if (FUN_100c1a00(p_action, p_bufferval) != SUCCESS) { + return FAILURE; + } + return FUN_100c1800(p_action, (p_bufferval / m_provider->GetFileSize()) * m_provider->GetFileSize()); } // OFFSET: LEGO1 0x100c1ce0 STUB @@ -91,3 +110,9 @@ MxResult MxStreamController::vtable0x30(undefined4 p_unknown) { return FAILURE; } + +// OFFSET: LEGO1 0x100c1a00 STUB +MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval) +{ + return FAILURE; +} diff --git a/LEGO1/mxstreamcontroller.h b/LEGO1/mxstreamcontroller.h index 4bee2f4c..6422d12d 100644 --- a/LEGO1/mxstreamcontroller.h +++ b/LEGO1/mxstreamcontroller.h @@ -35,11 +35,13 @@ class MxStreamController : public MxCore { virtual MxResult vtable0x1C(undefined4 p_unknown, undefined4 p_unknown2); // vtable+0x1c virtual MxResult vtable0x20(MxDSAction* p_action); // vtable+0x20 virtual MxResult vtable0x24(undefined4 p_unknown); // vtable+0x24 - virtual MxResult vtable0x28(); // vtable+0x28 - virtual MxResult vtable0x2c(MxDSAction* p_action, MxU32 p_bufferval); // vtable+0x2c - virtual MxResult vtable0x30(undefined4 p_unknown); // vtable+0x30 + MxResult FUN_100c1800(MxDSAction* p_action, MxU32 p_val); + virtual MxResult vtable0x28(); // vtable+0x28 + virtual MxResult vtable0x2c(MxDSAction* p_action, MxU32 p_bufferval); // vtable+0x2c + virtual MxResult vtable0x30(undefined4 p_unknown); // vtable+0x30 MxBool FUN_100c20d0(MxDSObject& p_obj); + MxResult FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval); inline MxAtomId& GetAtom() { return atom; }; diff --git a/LEGO1/mxstreamer.h b/LEGO1/mxstreamer.h index 6a62146a..6e0500cb 100644 --- a/LEGO1/mxstreamer.h +++ b/LEGO1/mxstreamer.h @@ -18,9 +18,11 @@ class MxStreamerSubClass1 { ~MxStreamerSubClass1() { delete[] m_buffer; } - undefined4 GetSize() { return m_size; } + undefined4 GetSize() const { return m_size; } void SetBuffer(undefined* p_buf) { m_buffer = p_buf; } + inline undefined* GetBuffer() const { return m_buffer; } + inline undefined4 GetUnk08() const { return m_unk08; } private: undefined* m_buffer; @@ -40,7 +42,7 @@ class MxStreamerSubClass3 : public MxStreamerSubClass1 { class MxStreamerNotification : public MxNotificationParam { public: - inline MxStreamerNotification(MxParamType p_type, MxCore* p_sender, MxStreamController* p_ctrlr) + inline MxStreamerNotification(NotificationId p_type, MxCore* p_sender, MxStreamController* p_ctrlr) : MxNotificationParam(p_type, p_sender) { m_controller = p_ctrlr; @@ -93,6 +95,9 @@ class MxStreamer : public MxCore { MxResult AddStreamControllerToOpenList(MxStreamController* p_stream); MxResult FUN_100b99b0(MxDSAction* p_action); + inline const MxStreamerSubClass2& GetSubclass1() { return m_subclass1; } + inline const MxStreamerSubClass3& GetSubclass2() { return m_subclass2; } + private: list m_openStreams; // 0x8 MxStreamerSubClass2 m_subclass1; // 0x14 diff --git a/LEGO1/mxstring.h b/LEGO1/mxstring.h index df5863b7..3984f428 100644 --- a/LEGO1/mxstring.h +++ b/LEGO1/mxstring.h @@ -18,6 +18,7 @@ class MxString : public MxCore { MxString operator+(const char*); MxString& operator+=(const char*); + inline MxS8 Compare(const MxString& p_str) const { return strcmp(m_data, p_str.m_data); } inline const char* GetData() const { return m_data; } private: diff --git a/LEGO1/mxstringlist.h b/LEGO1/mxstringlist.h index f92d2b7d..d80c4777 100644 --- a/LEGO1/mxstringlist.h +++ b/LEGO1/mxstringlist.h @@ -21,7 +21,7 @@ typedef MxListCursorChild MxStringListCursor; // MxList::~MxList // OFFSET: LEGO1 0x100cbb40 TEMPLATE -// MxList::OtherAppend +// MxList::Append // OFFSET: LEGO1 0x100cc2d0 TEMPLATE // MxList::_InsertEntry diff --git a/LEGO1/mxtransitionmanager.cpp b/LEGO1/mxtransitionmanager.cpp index 0e60855e..0df51929 100644 --- a/LEGO1/mxtransitionmanager.cpp +++ b/LEGO1/mxtransitionmanager.cpp @@ -468,7 +468,7 @@ void MxTransitionManager::SetWaitIndicator(MxVideoPresenter* p_waitIndicator) { // End current wait indicator if (m_waitIndicator != NULL) { - m_waitIndicator->GetAction()->SetFlags(m_waitIndicator->GetAction()->GetFlags() & ~MxDSAction::Flag_Parsed); + m_waitIndicator->GetAction()->SetFlags(m_waitIndicator->GetAction()->GetFlags() & ~MxDSAction::Flag_World); m_waitIndicator->EndAction(); m_waitIndicator = NULL; } diff --git a/LEGO1/mxvariabletable.cpp b/LEGO1/mxvariabletable.cpp index 96500167..0faa2b7b 100644 --- a/LEGO1/mxvariabletable.cpp +++ b/LEGO1/mxvariabletable.cpp @@ -3,7 +3,7 @@ // OFFSET: LEGO1 0x100b7330 MxS8 MxVariableTable::Compare(MxVariable* p_var0, MxVariable* p_var1) { - return strcmp(p_var0->GetKey()->GetData(), p_var1->GetKey()->GetData()); + return p_var0->GetKey()->Compare(*p_var1->GetKey()); } // OFFSET: LEGO1 0x100b7370 @@ -22,43 +22,43 @@ MxU32 MxVariableTable::Hash(MxVariable* p_var) // OFFSET: LEGO1 0x100b73a0 void MxVariableTable::SetVariable(const char* p_key, const char* p_value) { - MxHashTableCursor cursor(this); + MxHashTableCursor cursor(this); MxVariable* var = new MxVariable(p_key, p_value); if (cursor.Find(var)) { delete var; - cursor.GetMatch(var); + cursor.Current(var); var->SetValue(p_value); } else { - MxHashTable::Add(var); + MxHashTable::Add(var); } } // OFFSET: LEGO1 0x100b7740 -void MxVariableTable::SetVariable(MxVariable* var) +void MxVariableTable::SetVariable(MxVariable* p_var) { - MxHashTableCursor cursor(this); - MxBool found = cursor.Find(var); + MxHashTableCursor cursor(this); + MxBool found = cursor.Find(p_var); if (found) cursor.DeleteMatch(); - MxHashTable::Add(var); + MxHashTable::Add(p_var); } // OFFSET: LEGO1 0x100b78f0 const char* MxVariableTable::GetVariable(const char* p_key) { const char* value = ""; - MxHashTableCursor cursor(this); + MxHashTableCursor cursor(this); MxVariable* var = new MxVariable(p_key); MxBool found = cursor.Find(var); delete var; if (found) { - cursor.GetMatch(var); + cursor.Current(var); value = var->GetValue()->GetData(); } diff --git a/LEGO1/mxvariabletable.h b/LEGO1/mxvariabletable.h index 8bffab81..872aa49f 100644 --- a/LEGO1/mxvariabletable.h +++ b/LEGO1/mxvariabletable.h @@ -7,27 +7,51 @@ // VTABLE 0x100dc1c8 // SIZE 0x28 -class MxVariableTable : public MxHashTable { +class MxVariableTable : public MxHashTable { public: MxVariableTable() { m_customDestructor = Destroy; } - __declspec(dllexport) void SetVariable(const char* key, const char* value); - __declspec(dllexport) void SetVariable(MxVariable* var); - __declspec(dllexport) const char* GetVariable(const char* key); + __declspec(dllexport) void SetVariable(const char* p_key, const char* p_value); + __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*); // +0x14 - virtual MxU32 Hash(MxVariable*); // +0x18 + virtual MxS8 Compare(MxVariable*, MxVariable*) override; // +0x14 + virtual MxU32 Hash(MxVariable*) override; // +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 +// MxHashTable::~MxHashTable + +// OFFSET: LEGO1 0x100b0ca0 TEMPLATE +// MxHashTable::`scalar deleting destructor' // OFFSET: LEGO1 0x100b7ab0 TEMPLATE -// MxHashTable::Resize +// MxHashTable::Resize // OFFSET: LEGO1 0x100b7b80 TEMPLATE -// MxHashTable::_NodeInsert +// MxHashTable::_NodeInsert + +// VTABLE 0x100dc1b0 TEMPLATE +// class MxCollection + +// VTABLE 0x100dc1e8 TEMPLATE +// class MxHashTable #endif // MXVARIABLETABLE_H diff --git a/LEGO1/mxvideomanager.cpp b/LEGO1/mxvideomanager.cpp index 70f49424..754a1aee 100644 --- a/LEGO1/mxvideomanager.cpp +++ b/LEGO1/mxvideomanager.cpp @@ -75,26 +75,9 @@ void MxVideoManager::Destroy(MxBool p_fromDestructor) void MxVideoManager::UpdateRegion() { if (m_region->vtable20() == FALSE) { - MxS32 left, top, right, bottom; - MxRect32& regionRect = m_region->GetRect(); - - left = m_videoParam.GetRect().m_left; - if (left <= regionRect.m_left) - left = regionRect.m_left; - - top = regionRect.m_top; - if (top <= m_videoParam.GetRect().m_top) - top = m_videoParam.GetRect().m_top; - - right = regionRect.m_right; - if (right >= m_videoParam.GetRect().m_right) - right = m_videoParam.GetRect().m_right; - - bottom = m_videoParam.GetRect().m_bottom; - if (bottom >= regionRect.m_bottom) - bottom = regionRect.m_bottom; - - m_displaySurface->Display(left, top, left, top, right - left + 1, bottom - top + 1); + MxRect32 rect(m_region->GetRect(), m_videoParam.GetRect()); + m_displaySurface + ->Display(rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); } } diff --git a/LEGO1/mxvideoparam.cpp b/LEGO1/mxvideoparam.cpp index 750ce30c..d631e5be 100644 --- a/LEGO1/mxvideoparam.cpp +++ b/LEGO1/mxvideoparam.cpp @@ -6,14 +6,14 @@ // OFFSET: LEGO1 0x100bec70 MxVideoParam::MxVideoParam() { - this->m_rect.m_right = 640; - this->m_rect.m_bottom = 480; - this->m_rect.m_left = 0; - this->m_rect.m_top = 0; - this->m_palette = 0; + this->m_rect.SetRight(640); + this->m_rect.SetBottom(480); + this->m_rect.SetLeft(0); + this->m_rect.SetTop(0); + this->m_palette = NULL; this->m_backBuffers = 0; this->m_unk1c = 0; - this->m_deviceId = 0; + this->m_deviceId = NULL; } // OFFSET: LEGO1 0x100beca0 @@ -24,10 +24,7 @@ MxVideoParam::MxVideoParam( COMPAT_CONST MxVideoParamFlags& p_flags ) { - this->m_rect.m_left = p_rect.m_left; - this->m_rect.m_top = p_rect.m_top; - this->m_rect.m_right = p_rect.m_right; - this->m_rect.m_bottom = p_rect.m_bottom; + this->m_rect = p_rect; this->m_palette = p_pal; this->m_backBuffers = p_backBuffers; this->m_flags = p_flags; @@ -38,10 +35,7 @@ MxVideoParam::MxVideoParam( // OFFSET: LEGO1 0x100becf0 MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) { - this->m_rect.m_left = p_videoParam.m_rect.m_left; - this->m_rect.m_top = p_videoParam.m_rect.m_top; - this->m_rect.m_right = p_videoParam.m_rect.m_right; - this->m_rect.m_bottom = p_videoParam.m_rect.m_bottom; + 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; @@ -53,10 +47,7 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) // OFFSET: LEGO1 0x100bede0 MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) { - this->m_rect.m_left = p_videoParam.m_rect.m_left; - this->m_rect.m_top = p_videoParam.m_rect.m_top; - this->m_rect.m_right = p_videoParam.m_rect.m_right; - this->m_rect.m_bottom = p_videoParam.m_rect.m_bottom; + 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; @@ -69,24 +60,24 @@ MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) // OFFSET: LEGO1 0x100bed70 void MxVideoParam::SetDeviceName(char* id) { - if (this->m_deviceId != 0) + if (this->m_deviceId != NULL) delete[] this->m_deviceId; if (id != 0) { this->m_deviceId = new char[strlen(id) + 1]; - if (this->m_deviceId != 0) { + if (this->m_deviceId != NULL) { strcpy(this->m_deviceId, id); } } else { - this->m_deviceId = 0; + this->m_deviceId = NULL; } } // OFFSET: LEGO1 0x100bed50 MxVideoParam::~MxVideoParam() { - if (this->m_deviceId != 0) + if (this->m_deviceId != NULL) delete[] this->m_deviceId; } diff --git a/LEGO1/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index 7378b703..e39a92bf 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -220,7 +220,7 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) MxRect32 rect(x, y, x + width, y + height); MVideoManager()->InvalidateRect(rect); - MVideoManager()->vtable0x34(rect.m_left, rect.m_top, rect.GetWidth(), rect.GetHeight()); + MVideoManager()->vtable0x34(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); } delete m_bitmap; diff --git a/LEGO1/pizza.cpp b/LEGO1/pizza.cpp index e7eb0261..13df0739 100644 --- a/LEGO1/pizza.cpp +++ b/LEGO1/pizza.cpp @@ -20,7 +20,7 @@ Pizza::~Pizza() TickleManager()->UnregisterClient(this); } -// OFFSET: LEGO1 0x100388a0 +// OFFSET: LEGO1 0x100388a0 STUB MxResult Pizza::Tickle() { // TODO diff --git a/LEGO1/pizzeria.h b/LEGO1/pizzeria.h index b7e1a4e6..a06aa9e5 100644 --- a/LEGO1/pizzeria.h +++ b/LEGO1/pizzeria.h @@ -7,6 +7,18 @@ // SIZE 0x84 class Pizzeria : public IsleActor { public: + // OFFSET: LEGO1 0x1000e780 + inline virtual const char* ClassName() const override // vtable+0x0c + { + // 0x100f0380 + return "Pizzeria"; + } + + // OFFSET: LEGO1 0x1000e790 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, Pizzeria::ClassName()) || IsleActor::IsA(name); + } }; #endif // PIZZERIASTATE_H diff --git a/LEGO1/pizzeriastate.h b/LEGO1/pizzeriastate.h index 0c7143bf..76cb1728 100644 --- a/LEGO1/pizzeriastate.h +++ b/LEGO1/pizzeriastate.h @@ -8,6 +8,19 @@ class PizzeriaState : public LegoState { public: PizzeriaState(); + + // OFFSET: LEGO1 0x10017c20 + inline virtual const char* ClassName() const override // vtable+0x0c + { + // 0x100f0370 + return "PizzeriaState"; + } + + // OFFSET: LEGO1 0x10017c30 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, PizzeriaState::ClassName()) || LegoState::IsA(name); + } }; #endif // PIZZERIASTATE_H diff --git a/LEGO1/radio.h b/LEGO1/radio.h index b0f785c6..e2a4325c 100644 --- a/LEGO1/radio.h +++ b/LEGO1/radio.h @@ -7,6 +7,19 @@ class Radio : public MxCore { public: virtual ~Radio() override; + + // OFFSET: LEGO1 0x1002c8e0 + inline virtual const char* ClassName() const override // vtable+0x0c + { + // 0x100f328c + return "Radio"; + } + + // OFFSET: LEGO1 0x1002c8f0 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, Radio::ClassName()) || MxCore::IsA(name); + } }; #endif // RADIO_H diff --git a/LEGO1/registrationbook.h b/LEGO1/registrationbook.h index 17009204..28dd7de3 100644 --- a/LEGO1/registrationbook.h +++ b/LEGO1/registrationbook.h @@ -11,6 +11,19 @@ class RegistrationBook : public LegoWorld { virtual ~RegistrationBook() override; // vtable+0x0 virtual MxLong Notify(MxParam& p) override; // vtable+0x4 + + // OFFSET: LEGO1 0x10076e10 + inline virtual const char* ClassName() const override // vtable+0x0c + { + // 0x100f04c8 + return "RegistrationBook"; + } + + // OFFSET: LEGO1 0x10076e20 + inline virtual MxBool IsA(const char* name) const override // vtable+0x10 + { + return !strcmp(name, RegistrationBook::ClassName()) || LegoWorld::IsA(name); + } }; #endif // REGISTRATIONBOOK_H diff --git a/LEGO1/score.cpp b/LEGO1/score.cpp index c071f404..1c122482 100644 --- a/LEGO1/score.cpp +++ b/LEGO1/score.cpp @@ -15,8 +15,6 @@ DECOMP_SIZE_ASSERT(Score, 0x104) -MxAtomId* g_infoscorScript; - // OFFSET: LEGO1 0x10001000 Score::Score() { @@ -41,7 +39,7 @@ MxLong Score::Notify(MxParam& p) LegoWorld::Notify(p); if (m_unkf6) { switch (((MxNotificationParam&) p).GetNotification()) { - case PAINT: + case c_notificationStartAction: ret = 1; Paint(); break; diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index d32b5ad0..565fddef 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -50,19 +50,19 @@ original = args.original if not os.path.isfile(original): - parser.error('Original binary does not exist') + parser.error(f'Original binary {original} does not exist') recomp = args.recompiled if not os.path.isfile(recomp): - parser.error('Recompiled binary does not exist') + parser.error(f'Recompiled binary {recomp} does not exist') syms = args.pdb if not os.path.isfile(syms): - parser.error('Symbols PDB does not exist') + parser.error(f'Symbols PDB {syms} does not exist') source = args.decomp_dir if not os.path.isdir(source): - parser.error('Source directory does not exist') + parser.error(f'Source directory {source} does not exist') svg = args.svg @@ -70,7 +70,7 @@ # to file addresses class Bin: def __init__(self, filename): - logger.debug('Parsing headers of "%s"... ', filename) + logger.debug(f'Parsing headers of "{filename}"... ') self.file = open(filename, 'rb') #HACK: Strictly, we should be parsing the header, but we know where @@ -153,8 +153,8 @@ def __init__(self, pdb, file, wine_path_converter): else: call.append(pdb) - logger.info('Parsing %s ...', pdb) - logger.debug('Command = %r', call) + logger.info(f'Parsing {pdb} ...') + logger.debug(f'Command = {call}') line_dump = subprocess.check_output(call).decode('utf-8').split('\r\n') current_section = None @@ -219,13 +219,15 @@ def get_recompiled_address(self, filename, line): addr = None found = False - logger.debug('Looking for %s:%d', filename, line) + logger.debug(f'Looking for {filename}:{line}') + filename_basename = os.path.basename(filename).lower() for fn in self.lines: # Sometimes a PDB is compiled with a relative path while we always have # an absolute path. Therefore we must try: - if os.path.samefile(fn, filename): + if (os.path.basename(fn).lower() == filename_basename and + os.path.samefile(fn, filename)): filename = fn break except FileNotFoundError as e: @@ -237,9 +239,9 @@ def get_recompiled_address(self, filename, line): if addr in self.funcs: return self.funcs[addr] else: - logger.error('Failed to find function symbol with address: 0x%x', addr) + logger.error(f'Failed to find function symbol with address: 0x{addr:x}') else: - logger.error('Failed to find function symbol with filename and line: %s:%d', filename, line) + logger.error(f'Failed to find function symbol with filename and line: {filename}:{line}') def get_recompiled_address_from_name(self, name): logger.debug('Looking for %s', name) @@ -247,7 +249,7 @@ def get_recompiled_address_from_name(self, name): if name in self.names: return self.names[name] else: - logger.error('Failed to find function symbol with name: %s', name) + logger.error(f'Failed to find function symbol with name: {name}') wine_path_converter = None if os.name != 'nt': @@ -270,7 +272,7 @@ def get(self, addr): return self.replacements[addr] else: self.counter += 1 - replacement = '' % self.counter + replacement = f'' self.replacements[addr] = replacement return replacement @@ -330,12 +332,26 @@ def parse_asm(file, addr, size): if op_str is None: asm.append(mnemonic) else: - asm.append("%s %s" % (mnemonic, op_str)) + asm.append(f'{mnemonic} {op_str}') return asm REGISTER_LIST = set([ - 'eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', - 'ax', 'bx', 'cx', 'dx', 'di', 'si', 'bp', 'sp', + 'ax', + 'bp', + 'bx', + 'cx', + 'di', + 'dx', + 'eax', + 'ebp', + 'ebx', + 'ecx', + 'edi', + 'edx', + 'esi', + 'esp', + 'si', + 'sp', ]) WORDS = re.compile(r'\w+') @@ -348,9 +364,8 @@ def get_registers(line: str): to_replace.append((reg, match.start())) return to_replace -def replace_register(lines: list[str], start_line: int, reg: str, replacement: str): - for i in range(start_line, len(lines)): - lines[i] = lines[i].replace(reg, replacement) +def replace_register(lines: list[str], start_line: int, reg: str, replacement: str) -> list[str]: + return [line.replace(reg, replacement) if i >= start_line else line for i, line in enumerate(lines)] # Is it possible to make new_asm the same as original_asm by swapping registers? def can_resolve_register_differences(original_asm, new_asm): @@ -377,10 +392,10 @@ def can_resolve_register_differences(original_asm, new_asm): if replacing_reg in REGISTER_LIST: if replacing_reg != reg: # Do a three-way swap replacing in all the subsequent lines - temp_reg = "&" * len(reg) - replace_register(new_asm, i, replacing_reg, temp_reg) - replace_register(new_asm, i, reg, replacing_reg) - replace_register(new_asm, i, temp_reg, reg) + temp_reg = '&' * len(reg) + new_asm = replace_register(new_asm, i, replacing_reg, temp_reg) + new_asm = replace_register(new_asm, i, reg, replacing_reg) + new_asm = replace_register(new_asm, i, temp_reg, reg) else: # No replacement to do, different code, bail out return False @@ -402,185 +417,171 @@ def can_resolve_register_differences(original_asm, new_asm): for subdir, dirs, files in os.walk(source): for file in files: srcfilename = os.path.join(os.path.abspath(subdir), file) - srcfile = open(srcfilename, 'r') - line_no = 0 + with open(srcfilename, 'r') as srcfile: + line_no = 0 - while True: - try: - line = srcfile.readline() - line_no += 1 + while True: + try: + line = srcfile.readline() + line_no += 1 - if not line: - break + if not line: + break - line = line.strip() + line = line.strip() - if line.startswith(pattern) and not line.endswith("STUB"): - par = line[len(pattern):].strip().split() - module = par[0] - if module != basename: - continue - - addr = int(par[1], 16) - - # Verbose flag handling - if verbose: - if addr == verbose: - found_verbose_target = True - else: + if line.startswith(pattern) and not line.endswith('STUB'): + par = line[len(pattern):].strip().split() + module = par[0] + if module != basename: continue - if line.endswith("TEMPLATE"): - line = srcfile.readline() - line_no += 1 - # Name comes after // comment - name = line.strip()[2:].strip() + addr = int(par[1], 16) - 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 - - recinfo = syminfo.get_recompiled_address(srcfilename, line_no) - if not recinfo: - continue - - # 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) - - diff = difflib.SequenceMatcher(None, origasm, recompasm) - ratio = diff.ratio() - effective_ratio = ratio - - 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 - - percenttext = "%.2f%%" % (effective_ratio * 100) - 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 effective_ratio == 1.0 and ratio != 1.0: - if plain: - percenttext += "*" - else: - percenttext += colorama.Fore.RED + "*" + colorama.Style.RESET_ALL - - if args.print_rec_addr: - addrs = '%s / %s' % (hex(addr), hex(recinfo.addr)) - else: - addrs = hex(addr) - - if not verbose: - print(' %s (%s) is %s similar to the original' % (recinfo.name, addrs, percenttext)) - - function_count += 1 - total_accuracy += ratio - total_effective_accuracy += effective_ratio - - if recinfo.size: - udiff = difflib.unified_diff(origasm, recompasm, n=10) - - # If verbose, print the diff for that function to the output + # Verbose flag handling 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("%s: %s 100%% match.\n\n%s\n\n" % - (addrs, recinfo.name, ok_text)) - else: - print("%s: %s Effective 100%% match. (Differs in register allocation only)\n\n%s (still differs in register allocation)\n\n" % - (addrs, recinfo.name, ok_text)) + if addr == verbose: + found_verbose_target = True 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) + continue + + if line.endswith('TEMPLATE'): + line = srcfile.readline() + line_no += 1 + # Name comes after // comment + name = line.strip()[2:].strip() + + 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 + + recinfo = syminfo.get_recompiled_address(srcfilename, line_no) + if not recinfo: + continue + + # 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) + + diff = difflib.SequenceMatcher(None, origasm, recompasm) + ratio = diff.ratio() + effective_ratio = ratio + + 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 + + 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 effective_ratio == 1.0 and ratio != 1.0: + if plain: + percenttext += '*' + else: + percenttext += colorama.Fore.RED + '*' + colorama.Style.RESET_ALL + + if args.print_rec_addr: + addrs = f'0x{addr:x} / 0x{recinfo.addr:x}' + else: + addrs = hex(addr) + + if not verbose: + print(f' {recinfo.name} ({addrs}) is {percenttext} similar to the original') + + function_count += 1 + total_accuracy += ratio + total_effective_accuracy += effective_ratio + + 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(line) - if not plain: - print(colorama.Style.RESET_ALL, end='') + 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("\n%s is only %s similar to the original, diff above" % (recinfo.name, percenttext)) + 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 = '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n').replace('<', '<').replace('>', '>') - htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), html.escape(recinfo.name), str(effective_ratio), escaped)) + # 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 + except UnicodeDecodeError: + break def gen_html(html_path, data): - templatefile = open(get_file_in_script_dir('template.html'), 'r') - if not templatefile: - print('Failed to find HTML template file, can\'t generate HTML summary') - return - - templatedata = templatefile.read() - templatefile.close() + templatedata = None + with open(get_file_in_script_dir('template.html')) as templatefile: + templatedata = templatefile.read() templatedata = templatedata.replace('/* INSERT DATA HERE */', ','.join(data), 1) - htmlfile = open(html_path, 'w') - if not htmlfile: - print('Failed to write to HTML file %s' % html_path) - return + with open(html_path, 'w') as htmlfile: + htmlfile.write(templatedata) - htmlfile.write(templatedata) - htmlfile.close() def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy): - templatefile = open(get_file_in_script_dir('template.svg'), 'r') - if not templatefile: - print('Failed to find SVG template file, can\'t generate SVG summary') - return - - templatedata = templatefile.read() - templatefile.close() + templatedata = None + with open(get_file_in_script_dir('template.svg')) as templatefile: + templatedata = templatefile.read() + # TODO: Use templating engine (e.g. pystache) # Replace icon if args.svg_icon: - iconfile = open(args.svg_icon, 'rb') - templatedata = templatedata.replace('{icon}', base64.b64encode(iconfile.read()).decode('utf-8'), 1) - iconfile.close() + with open(args.svg_icon, 'rb') as iconfile: + templatedata = templatedata.replace('{icon}', base64.b64encode(iconfile.read()).decode('utf-8'), 1) # Replace name templatedata = templatedata.replace('{name}', name, 1) # Replace implemented statistic - templatedata = templatedata.replace('{implemented}', '%.2f%% (%i/%i)' % (implemented_funcs / total_funcs * 100, implemented_funcs, total_funcs), 1) + templatedata = templatedata.replace('{implemented}', f'{(implemented_funcs / total_funcs * 100):.2f}% ({implemented_funcs}/{total_funcs})', 1) # Replace accuracy statistic - templatedata = templatedata.replace('{accuracy}', '%.2f%%' % (raw_accuracy / implemented_funcs * 100), 1) + templatedata = templatedata.replace('{accuracy}', f'{(raw_accuracy / implemented_funcs * 100):.2f}%', 1) # Generate progress bar width total_statistic = raw_accuracy / total_funcs @@ -591,22 +592,17 @@ def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy): templatedata = templatedata[0:percentstart] + str(progwidth) + templatedata[percentend + 1:] # Replace percentage statistic - templatedata = templatedata.replace('{percent}', '%.2f%%' % (total_statistic * 100), 2) + templatedata = templatedata.replace('{percent}', f'{(total_statistic * 100):.2f}%', 2) - svgfile = open(svg, 'w') - if not svgfile: - print('Failed to write to SVG file %s' % svg) - return - - svgfile.write(templatedata) - svgfile.close() + with open(svg, 'w') as svgfile: + svgfile.write(templatedata) if html_path: gen_html(html_path, htmlinsert) if verbose: if not found_verbose_target: - print('Failed to find the function with address %s' % hex(verbose)) + print(f'Failed to find the function with address 0x{verbose:x}') else: implemented_funcs = function_count @@ -614,8 +610,9 @@ def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy): function_count = int(args.total) if function_count > 0: - print('\nTotal effective accuracy %.2f%% across %i functions (%.2f%% actual accuracy)' % - (total_effective_accuracy / function_count * 100, function_count, total_accuracy / function_count * 100)) + effective_accuracy = total_effective_accuracy / function_count * 100 + actual_accuracy = total_accuracy / function_count * 100 + print(f'\nTotal effective accuracy {effective_accuracy:.2f}% across {function_count} functions ({actual_accuracy:.2f}% actual accuracy)') if svg: gen_svg(svg, os.path.basename(original), args.svg_icon, implemented_funcs, function_count, total_effective_accuracy) diff --git a/tools/verexp/verexp.py b/tools/verexp/verexp.py index 6927622d..3a469fb6 100755 --- a/tools/verexp/verexp.py +++ b/tools/verexp/verexp.py @@ -16,10 +16,10 @@ args = parser.parse_args() if not os.path.isfile(args.original): - parser.error('Original binary does not exist') + parser.error(f'Original binary file {args.original} does not exist') if not os.path.isfile(args.recompiled): - parser.error('Recompiled binary does not exist') + parser.error(f'Recompiled binary {args.recompiled} does not exist') def get_file_in_script_dir(fn): return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn) @@ -58,25 +58,19 @@ def get_exports(file): for line in udiff: has_diff = True - if line.startswith("++") or line.startswith("@@") or line.startswith("--"): + color = '' + if line.startswith('++') or line.startswith('@@') or line.startswith('--'): # Skip unneeded parts of the diff for the brief view - pass - elif line.startswith("+"): - if args.no_color: - print(line) - else: - print(colorama.Fore.GREEN + line) - elif line.startswith("-"): - if args.no_color: - print(line) - else: - print(colorama.Fore.RED + line) - else: - print(line) + continue + # Work out color if we are printing color + if not args.no_color: + if line.startswith('+'): + color = colorama.Fore.GREEN + elif line.startswith('-'): + color = colorama.Fore.RED + print(color + line) + # Reset color if we're printing in color if not args.no_color: print(colorama.Style.RESET_ALL, end='') -if has_diff: - sys.exit(1) -else: - sys.exit(0) +sys.exit(1 if has_diff else 0)