diff --git a/LEGO1/act2brick.cpp b/LEGO1/act2brick.cpp index dde79d0b..1ec4f139 100644 --- a/LEGO1/act2brick.cpp +++ b/LEGO1/act2brick.cpp @@ -25,5 +25,5 @@ MxResult Act2Brick::Tickle() { // TODO - return 0; + return SUCCESS; } diff --git a/LEGO1/jukeboxstate.cpp b/LEGO1/jukeboxstate.cpp index 25b6dc90..d4a2511f 100644 --- a/LEGO1/jukeboxstate.cpp +++ b/LEGO1/jukeboxstate.cpp @@ -1 +1,6 @@ #include "jukeboxstate.h" + +// OFFSET: LEGO1 0x1000f300 +MxBool JukeBoxState::VTable0x14() { + return FALSE; +} diff --git a/LEGO1/jukeboxstate.h b/LEGO1/jukeboxstate.h index 75640fe3..d2b37e38 100644 --- a/LEGO1/jukeboxstate.h +++ b/LEGO1/jukeboxstate.h @@ -21,6 +21,8 @@ class JukeBoxState : public LegoState return !strcmp(name, JukeBoxState::ClassName()) || LegoState::IsA(name); } + virtual MxBool VTable0x14() override; // vtable+0x14 + }; #endif // JUKEBOXSTATE_H diff --git a/LEGO1/legoanimationmanager.cpp b/LEGO1/legoanimationmanager.cpp index 20e0a0e3..bf182ef5 100644 --- a/LEGO1/legoanimationmanager.cpp +++ b/LEGO1/legoanimationmanager.cpp @@ -27,7 +27,7 @@ MxResult LegoAnimationManager::Tickle() { // TODO - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x1005f130 STUB diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index d4ab47ea..8786145e 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -6,10 +6,14 @@ #include "legoutil.h" #include "legoobjectfactory.h" #include "legoinputmanager.h" +#include "legoworld.h" // 0x100f4588 MxAtomId *g_nocdSourceName = NULL; +// 0x100f456c +MxAtomId *g_jukeboxScript = NULL; + // 0x101020e8 void (*g_omniUserMessage)(const char *,int); @@ -25,10 +29,11 @@ LegoOmni::~LegoOmni() Destroy(); } -// OFFSET: LEGO1 0x1005b560 STUB +// OFFSET: LEGO1 0x1005b560 void LegoOmni::CreateBackgroundAudio() { - // TODO + if (m_bkgAudioManager) + m_bkgAudioManager->Create(*g_jukeboxScript, 100); } // OFFSET: LEGO1 0x1005af10 STUB @@ -307,9 +312,10 @@ MxResult LegoOmni::Start(MxDSAction* action) return result; } -void LegoOmni::DeleteObject(MxDSAction &ds) +MxResult LegoOmni::DeleteObject(MxDSAction &ds) { // FIXME: Stub + return FAILURE; } MxBool LegoOmni::DoesEntityExist(MxDSAction &ds) @@ -329,9 +335,11 @@ int LegoOmni::vtable0x30(char*, int, MxCore*) return 0; } -void LegoOmni::NotifyCurrentEntity() +// OFFSET: LEGO1 0x1005b3a0 +void LegoOmni::NotifyCurrentEntity(MxNotificationParam *p_param) { - // FIXME: Stub + if (m_currentWorld) + NotificationManager()->Send(m_currentWorld, p_param); } // OFFSET: LEGO1 0x1005b640 diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index 37d3ef4b..8a61c2df 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -57,11 +57,11 @@ class LegoOmni : public MxOmni virtual MxResult Create(COMPAT_CONST MxOmniCreateParam &p) override; // vtable+18 virtual void Destroy() override; // vtable+1c virtual MxResult Start(MxDSAction* action) override; - virtual void DeleteObject(MxDSAction &ds) override; + virtual MxResult DeleteObject(MxDSAction &ds) override; virtual MxBool DoesEntityExist(MxDSAction &ds) override; virtual void vtable0x2c() override; virtual int vtable0x30(char*, int, MxCore*) override; - virtual void NotifyCurrentEntity() override; + virtual void NotifyCurrentEntity(MxNotificationParam *p_param) override; virtual void StartTimer() override; virtual void StopTimer() override; diff --git a/LEGO1/legopathcontroller.cpp b/LEGO1/legopathcontroller.cpp index f8b64109..94a6aa1d 100644 --- a/LEGO1/legopathcontroller.cpp +++ b/LEGO1/legopathcontroller.cpp @@ -16,5 +16,5 @@ LegoPathController::~LegoPathController() MxResult LegoPathController::Tickle() { // TODO - return 0; + return SUCCESS; } diff --git a/LEGO1/legosoundmanager.cpp b/LEGO1/legosoundmanager.cpp index 01f8fee5..cec30564 100644 --- a/LEGO1/legosoundmanager.cpp +++ b/LEGO1/legosoundmanager.cpp @@ -1,20 +1,48 @@ #include "legosoundmanager.h" +#include "mxautolocker.h" -// OFFSET: LEGO1 0x100298a0 STUB +// OFFSET: LEGO1 0x100298a0 LegoSoundManager::LegoSoundManager() { - // TODO + Init(); } -// OFFSET: LEGO1 0x10029940 STUB +// OFFSET: LEGO1 0x10029940 LegoSoundManager::~LegoSoundManager() { - // TODO + Destroy(TRUE); +} + +// OFFSET: LEGO1 0x1002a390 +void LegoSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100299b0 STUB +void LegoSoundManager::Destroy(MxBool p_fromDestructor) +{ + +} + +// OFFSET: LEGO1 0x100299f0 STUB +MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + return FAILURE; +} + +// OFFSET: LEGO1 0x100299a0 +void LegoSoundManager::Init() +{ + unk0x40 = 0; + unk0x3c = 0; } // OFFSET: LEGO1 0x1002a3a0 STUB MxResult LegoSoundManager::Tickle() { - // TODO - return 0; + MxMediaManager::Tickle(); + MxAutoLocker lock(&this->m_criticalSection); + + return 0; // TODO: call something in unk0x40 } diff --git a/LEGO1/legosoundmanager.h b/LEGO1/legosoundmanager.h index 90e23fba..1f16f497 100644 --- a/LEGO1/legosoundmanager.h +++ b/LEGO1/legosoundmanager.h @@ -10,11 +10,17 @@ class LegoSoundManager : public MxSoundManager public: LegoSoundManager(); virtual ~LegoSoundManager() override; + virtual MxResult Tickle() override; // vtable+08 + virtual void Destroy() override; // vtable+18 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread) override; //vtable+0x30 private: void Init(); + void Destroy(MxBool p_fromDestructor); + undefined4 unk0x3c; + undefined4 unk0x40; }; #endif // LEGOSOUNDMANAGER_H diff --git a/LEGO1/mxbackgroundaudiomanager.cpp b/LEGO1/mxbackgroundaudiomanager.cpp index 40891bef..cbf480fc 100644 --- a/LEGO1/mxbackgroundaudiomanager.cpp +++ b/LEGO1/mxbackgroundaudiomanager.cpp @@ -1,6 +1,8 @@ #include "mxbackgroundaudiomanager.h" #include "mxomni.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" DECOMP_SIZE_ASSERT(MxBackgroundAudioManager, 0x150) @@ -20,14 +22,29 @@ MxBackgroundAudioManager::MxBackgroundAudioManager() // OFFSET: LEGO1 0x1007ec20 MxBackgroundAudioManager::~MxBackgroundAudioManager() { - // TODO + TickleManager()->UnregisterClient(this); NotificationManager()->Unregister(this); + DestroyMusic(); } // OFFSET: LEGO1 0x1007f470 void MxBackgroundAudioManager::Stop() { - // TODO + if (m_action2.GetObjectId() != -1) + DeleteObject(m_action2); + + m_unk138 = 0; + m_action2.SetAtomId(MxAtomId()); + m_action2.SetObjectId(-1); + + if (m_action1.GetObjectId() != -1) + DeleteObject(m_action1); + + m_unka0 = 0; + m_action1.SetAtomId(MxAtomId()); + m_unk148 = 0; + m_action1.SetObjectId(-1); + m_unk13c = 0; } // OFFSET: LEGO1 0x1007f5f0 @@ -47,3 +64,45 @@ void MxBackgroundAudioManager::Init() this->m_unka0 = 0; this->m_unk13c = 0; } + +// OFFSET: LEGO1 0x1007ece0 +MxResult MxBackgroundAudioManager::Create(MxAtomId &p_script, MxU32 p_frequencyMS) +{ + MxResult result = OpenMusic(p_script); + + if (result == SUCCESS) { + TickleManager()->RegisterClient(this, p_frequencyMS); + m_musicEnabled = TRUE; + } + + return result; +} + +// OFFSET: LEGO1 0x1007ed20 +MxResult MxBackgroundAudioManager::OpenMusic(MxAtomId &p_script) +{ + if (m_script.GetInternal()) + DestroyMusic(); + + MxResult result = FAILURE; + + if (Streamer()->Open(p_script.GetInternal(), 0)) { + m_script = p_script; + result = SUCCESS; + } + + return result; +} + +// OFFSET: LEGO1 0x1007ed70 +void MxBackgroundAudioManager::DestroyMusic() +{ + if (m_script.GetInternal()) { + MxDSAction ds; + ds.SetAtomId(m_script); + ds.SetUnknown24(-2); + DeleteObject(ds); + Streamer()->Close(m_script.GetInternal()); + m_musicEnabled = FALSE; + } +} \ No newline at end of file diff --git a/LEGO1/mxbackgroundaudiomanager.h b/LEGO1/mxbackgroundaudiomanager.h index a2c4cae3..f81fe854 100644 --- a/LEGO1/mxbackgroundaudiomanager.h +++ b/LEGO1/mxbackgroundaudiomanager.h @@ -28,10 +28,13 @@ class MxBackgroundAudioManager : public MxCore } __declspec(dllexport) void Enable(unsigned char p); + virtual MxResult Create(MxAtomId &p_script, MxU32 p_frequencyMS); void Stop(); private: void Init(); + MxResult OpenMusic(MxAtomId &p_script); + void DestroyMusic(); MxBool m_musicEnabled; // 0x8 MxDSAction m_action1; // 0xc @@ -42,7 +45,7 @@ class MxBackgroundAudioManager : public MxCore MxS32 m_unk140; MxS32 m_unk144; MxS16 m_unk148; - MxAtomId m_unk14c; + MxAtomId m_script; }; #endif // MXBACKGROUNDAUDIOMANAGER_H diff --git a/LEGO1/mxbitmap.cpp b/LEGO1/mxbitmap.cpp index 8f33fc22..1128fded 100644 --- a/LEGO1/mxbitmap.cpp +++ b/LEGO1/mxbitmap.cpp @@ -369,7 +369,7 @@ MxResult MxBitmap::SetBitDepth(MxBool p_isHighColor) MxResult MxBitmap::StretchBits(HDC p_hdc, MxS32 p_xSrc, MxS32 p_ySrc, MxS32 p_xDest, MxS32 p_yDest, MxS32 p_destWidth, MxS32 p_destHeight) { // Compression fix? - if ((this->m_bmiHeader->biCompression != 16) && (0 < this->m_bmiHeader->biHeight)) { + if ((this->m_bmiHeader->biCompression != BI_RGB_TOPDOWN) && (0 < this->m_bmiHeader->biHeight)) { p_ySrc = (this->m_bmiHeader->biHeight - p_destHeight) - p_ySrc; } diff --git a/LEGO1/mxbitmap.h b/LEGO1/mxbitmap.h index 53b01e16..6bb1c5fd 100644 --- a/LEGO1/mxbitmap.h +++ b/LEGO1/mxbitmap.h @@ -21,6 +21,13 @@ struct MxBITMAPINFO { RGBQUAD bmiColors[256]; }; +// Non-standard value for biCompression in the BITMAPINFOHEADER struct. +// By default, uncompressed bitmaps (BI_RGB) are stored in bottom-up order. +// You can specify that the bitmap has top-down order instead by providing +// a negative number for biHeight. It could be that Mindscape decided on a +// belt & suspenders approach here. +#define BI_RGB_TOPDOWN 0x10 + // SIZE 0x20 // VTABLE 0x100dc7b0 class MxBitmap : public MxCore @@ -43,6 +50,10 @@ class MxBitmap : public MxCore virtual MxResult StretchBits(HDC p_hdc, MxS32 p_xSrc, MxS32 p_ySrc, MxS32 p_xDest, MxS32 p_yDest, MxS32 p_destWidth, MxS32 p_destHeight); // vtable+40 inline BITMAPINFOHEADER *GetBmiHeader() const { return m_bmiHeader; } + inline MxLong GetBmiWidth() const { return m_bmiHeader->biWidth; } + inline MxLong GetBmiHeight() const { return m_bmiHeader->biHeight; } + inline MxLong GetBmiHeightAbs() const { return m_bmiHeader->biHeight > 0 ? m_bmiHeader->biHeight : -m_bmiHeader->biHeight; } + inline MxU8 *GetBitmapData() const { return m_data; } private: MxResult ImportColorsToPalette(RGBQUAD*, MxPalette*); diff --git a/LEGO1/mxdiskstreamcontroller.cpp b/LEGO1/mxdiskstreamcontroller.cpp index 0c74c3a7..0c1afedf 100644 --- a/LEGO1/mxdiskstreamcontroller.cpp +++ b/LEGO1/mxdiskstreamcontroller.cpp @@ -16,7 +16,7 @@ MxDiskStreamController::~MxDiskStreamController() MxResult MxDiskStreamController::Tickle() { // TODO - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x100c7790 STUB diff --git a/LEGO1/mxdsbuffer.cpp b/LEGO1/mxdsbuffer.cpp index 686627a4..b01be21a 100644 --- a/LEGO1/mxdsbuffer.cpp +++ b/LEGO1/mxdsbuffer.cpp @@ -1,9 +1,21 @@ #include "mxdsbuffer.h" +DECOMP_SIZE_ASSERT(MxDSBuffer, 0x34); + // OFFSET: LEGO1 0x100c6470 MxDSBuffer::MxDSBuffer() { - // TODO + m_unk20 = 0; + m_pBuffer = NULL; + m_pIntoBuffer = NULL; + m_pIntoBuffer2 = NULL; + m_unk14 = 0; + m_unk18 = 0; + m_unk1c = 0; + m_writeOffset = 0; + m_bytesRemaining = 0; + m_mode = 2; + m_unk30 = 0; } // OFFSET: LEGO1 0x100c6530 @@ -11,3 +23,15 @@ MxDSBuffer::~MxDSBuffer() { // TODO } + +// OFFSET: LEGO1 0x100c6780 +MxResult MxDSBuffer::FUN_100c6780(void* p_buffer, MxU32 p_size) +{ + m_pBuffer = p_buffer; + m_pIntoBuffer = p_buffer; + m_pIntoBuffer2 = p_buffer; + m_bytesRemaining = p_size; + m_writeOffset = p_size; + m_mode = 2; + return SUCCESS; +} diff --git a/LEGO1/mxdsbuffer.h b/LEGO1/mxdsbuffer.h index cb962cea..a48c4727 100644 --- a/LEGO1/mxdsbuffer.h +++ b/LEGO1/mxdsbuffer.h @@ -12,9 +12,30 @@ class MxDSBuffer : public MxCore MxDSBuffer(); virtual ~MxDSBuffer() override; -private: - undefined m_unk08[0x2C]; + // OFFSET: LEGO1 0x100c6500 + inline virtual const char *ClassName() const override // vtable+0x0c + { + // 0x100f0568 + return "MxDSBuffer"; + } + MxResult FUN_100c6780(void* p_buffer, MxU32 p_size); + + inline void* GetBuffer() { return m_pBuffer;} + inline MxU32 GetWriteOffset() { return m_writeOffset;} + +private: + void* m_pBuffer; + void* m_pIntoBuffer; + void* m_pIntoBuffer2; + undefined4 m_unk14; + undefined4 m_unk18; + undefined4 m_unk1c; + undefined2 m_unk20; + undefined4 m_mode; + MxU32 m_writeOffset; + MxU32 m_bytesRemaining; + undefined4 m_unk30; }; #endif // MXDSBUFFER_H diff --git a/LEGO1/mxdssource.cpp b/LEGO1/mxdssource.cpp index 0ede6402..3c725a81 100644 --- a/LEGO1/mxdssource.cpp +++ b/LEGO1/mxdssource.cpp @@ -1,10 +1,10 @@ #include "mxdssource.h" +#include "mxdsbuffer.h" // OFFSET: LEGO1 0x100bffd0 -void MxDSSource::FUN_100bffd0(void* p_unk) +void MxDSSource::ReadToBuffer(MxDSBuffer* p_buffer) { - // TODO: Calls read, reading into a buffer somewhere in p_unk. - Read(NULL, 0); + Read((unsigned char*)p_buffer->GetBuffer(), p_buffer->GetWriteOffset()); } // OFFSET: LEGO1 0x100bfff0 @@ -17,4 +17,4 @@ MxLong MxDSSource::GetLengthInDWords() MxU32 *MxDSSource::GetBuffer() { return m_pBuffer; -} \ No newline at end of file +} diff --git a/LEGO1/mxdssource.h b/LEGO1/mxdssource.h index 2891f426..9c404ad0 100644 --- a/LEGO1/mxdssource.h +++ b/LEGO1/mxdssource.h @@ -3,13 +3,15 @@ #include "mxcore.h" +class MxDSBuffer; + // VTABLE 0x100dc8c8 class MxDSSource : public MxCore { public: MxDSSource() : m_lengthInDWords(0) - , m_pBuffer(0) + , m_pBuffer(NULL) , m_position(-1) {} @@ -28,7 +30,7 @@ class MxDSSource : public MxCore virtual MxLong Open(MxULong) = 0; virtual MxLong Close() = 0; - virtual void FUN_100bffd0(void* p_unk); + virtual void ReadToBuffer(MxDSBuffer* p_buffer); virtual MxResult Read(unsigned char *, MxULong) = 0; virtual MxLong Seek(MxLong, int) = 0; virtual MxULong GetBufferSize() = 0; diff --git a/LEGO1/mxeventpresenter.cpp b/LEGO1/mxeventpresenter.cpp index 88c20ce3..3a4ff7f4 100644 --- a/LEGO1/mxeventpresenter.cpp +++ b/LEGO1/mxeventpresenter.cpp @@ -1,4 +1,6 @@ #include "mxeventpresenter.h" +#include "mxeventmanager.h" +#include "mxomni.h" #include "decomp.h" @@ -10,14 +12,31 @@ MxEventPresenter::MxEventPresenter() Init(); } -// OFFSET: LEGO1 0x100c2d40 STUB +// OFFSET: LEGO1 0x100c2d40 MxEventPresenter::~MxEventPresenter() { - // TODO + Destroy(); } // OFFSET: LEGO1 0x100c2da0 void MxEventPresenter::Init() { - m_unk50 = 0; + m_unk50 = NULL; +} + +// OFFSET: LEGO1 0x100c2de0 +void MxEventPresenter::Destroy() +{ + MxEventManager *eventManager = EventManager(); + if (eventManager) + EventManager()->RemovePresenter(*this); + + m_criticalSection.Enter(); + + if (m_unk50) + delete m_unk50; + + Init(); + + m_criticalSection.Leave(); } diff --git a/LEGO1/mxeventpresenter.h b/LEGO1/mxeventpresenter.h index 256d0c7f..358a54af 100644 --- a/LEGO1/mxeventpresenter.h +++ b/LEGO1/mxeventpresenter.h @@ -26,10 +26,12 @@ class MxEventPresenter : public MxMediaPresenter return !strcmp(name, MxEventPresenter::ClassName()) || MxMediaPresenter::IsA(name); } + virtual void Destroy() override; // vtable+0x38 + private: void Init(); - undefined4 m_unk50; + undefined4 *m_unk50; }; #endif // MXEVENTPRESENTER_H diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index 2fb6b57c..3f31bf96 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -12,7 +12,7 @@ MxMediaPresenter::~MxMediaPresenter() MxResult MxMediaPresenter::Tickle() { // TODO - return 0; + return SUCCESS; } // OFFSET: LEGO1 0x100b54e0 diff --git a/LEGO1/mxmediapresenter.h b/LEGO1/mxmediapresenter.h index d0a5efe4..7ef31a98 100644 --- a/LEGO1/mxmediapresenter.h +++ b/LEGO1/mxmediapresenter.h @@ -43,9 +43,8 @@ class MxMediaPresenter : public MxPresenter undefined4 m_unk44; undefined4 m_unk48; undefined4 m_unk4c; -private: - void Init(); protected: + void Init(); void Destroy(MxBool p_fromDestructor); }; diff --git a/LEGO1/mxnotificationmanager.h b/LEGO1/mxnotificationmanager.h index adcd6876..5bc7b3a4 100644 --- a/LEGO1/mxnotificationmanager.h +++ b/LEGO1/mxnotificationmanager.h @@ -50,6 +50,8 @@ class MxNotificationManager : public MxCore void Unregister(MxCore *p_listener); MxResult Send(MxCore *p_listener, MxNotificationParam *p_param); + inline MxNotificationPtrList *GetQueue() { return m_queue; } + private: void FlushPending(MxCore *p_listener); }; diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 88e4bf02..0265cc74 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -61,22 +61,28 @@ MxResult MxOmni::Start(MxDSAction* p_dsAction) MxResult result = FAILURE; if(p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) { - result = m_streamer->Unknown100b99b0(p_dsAction); + result = m_streamer->FUN_100b99b0(p_dsAction); } return result; } // OFFSET: LEGO1 0x100b00c0 STUB -void MxOmni::DeleteObject(MxDSAction &ds) +MxResult MxOmni::DeleteObject(MxDSAction &p_dsAction) { // TODO + return FAILURE; } -// OFFSET: LEGO1 0x100b09a0 STUB -MxBool MxOmni::DoesEntityExist(MxDSAction &ds) +// OFFSET: LEGO1 0x100b09a0 +MxBool MxOmni::DoesEntityExist(MxDSAction &p_dsAction) { - // TODO + if (m_streamer->FUN_100b9b30(p_dsAction)) { + MxNotificationPtrList *queue = m_notificationManager->GetQueue(); + + if (!queue || queue->size() == 0) + return TRUE; + } return FALSE; } @@ -94,7 +100,7 @@ int MxOmni::vtable0x30(char*, int, MxCore*) } // OFFSET: LEGO1 0x100aefc0 -void MxOmni::NotifyCurrentEntity(MxParam *p_param) +void MxOmni::NotifyCurrentEntity(MxNotificationParam *p_param) { } @@ -226,7 +232,7 @@ MxResult MxOmni::Create(MxOmniCreateParam &p) } if (p.CreateFlags().CreateStreamer()) { - if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS) + if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS) goto done; } @@ -397,3 +403,9 @@ MxEventManager* EventManager() { return MxOmni::GetInstance()->GetEventManager(); } + +// OFFSET: LEGO1 0x100acf70 +MxResult DeleteObject(MxDSAction &p_dsAction) +{ + return MxOmni::GetInstance()->DeleteObject(p_dsAction); +} \ No newline at end of file diff --git a/LEGO1/mxomni.h b/LEGO1/mxomni.h index ab07d2bd..430c0fe6 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -10,6 +10,7 @@ class MxDSAction; class MxEventManager; class MxMusicManager; class MxNotificationManager; +class MxNotificationParam; class MxObjectFactory; class MxOmniCreateParam; class MxSoundManager; @@ -41,11 +42,11 @@ class MxOmni : public MxCore virtual MxResult Create(COMPAT_CONST MxOmniCreateParam &p); // vtable+18 virtual void Destroy(); // vtable+1c virtual MxResult Start(MxDSAction* p_dsAction); // vtable+20 - virtual void DeleteObject(MxDSAction &ds); // vtable+24 - virtual MxBool DoesEntityExist(MxDSAction &ds); // vtable+28 + 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 void NotifyCurrentEntity(MxParam *p_param); // vtable+34 + virtual void NotifyCurrentEntity(MxNotificationParam *p_param); // vtable+34 virtual void StartTimer(); // vtable+38 virtual void StopTimer(); // vtable+3c virtual MxBool IsTimerRunning(); //vtable+40 @@ -94,6 +95,7 @@ __declspec(dllexport) MxMusicManager * MusicManager(); __declspec(dllexport) MxEventManager * EventManager(); __declspec(dllexport) MxNotificationManager * NotificationManager(); +MxResult DeleteObject(MxDSAction &p_dsAction); MxVideoManager *MVideoManager(); MxAtomIdCounterSet *AtomIdCounterSet(); MxObjectFactory *ObjectFactory(); diff --git a/LEGO1/mxpalette.cpp b/LEGO1/mxpalette.cpp index cdd1597f..b11a1209 100644 --- a/LEGO1/mxpalette.cpp +++ b/LEGO1/mxpalette.cpp @@ -379,7 +379,7 @@ void MxPalette::Detach() MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) { MxS32 i; - MxResult status = 0; + MxResult status = SUCCESS; if ( this->m_palette ) { @@ -423,7 +423,7 @@ MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) this->m_entries[i].peFlags = 0x80; if ( this->m_palette->SetEntries(0, 0, 256, this->m_entries) ) - status = -1; + status = FAILURE; } return status; diff --git a/LEGO1/mxsoundmanager.cpp b/LEGO1/mxsoundmanager.cpp index 51336843..ca04580f 100644 --- a/LEGO1/mxsoundmanager.cpp +++ b/LEGO1/mxsoundmanager.cpp @@ -58,11 +58,23 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) // OFFSET: LEGO1 0x100aed10 STUB void MxSoundManager::vtable0x34() { - // TODO STUB + // TODO } // OFFSET: LEGO1 0x100aee10 STUB void MxSoundManager::vtable0x38() { - // TODO STUB + // TODO +} + +// OFFSET: LEGO1 0x100aeab0 +void MxSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100aeac0 STUB +void MxSoundManager::SetVolume(MxS32 p_volume) +{ + // TODO } diff --git a/LEGO1/mxsoundmanager.h b/LEGO1/mxsoundmanager.h index 3bd41085..9e0656f8 100644 --- a/LEGO1/mxsoundmanager.h +++ b/LEGO1/mxsoundmanager.h @@ -14,6 +14,8 @@ class MxSoundManager : public MxAudioManager MxSoundManager(); virtual ~MxSoundManager() override; // vtable+0x0 + virtual void Destroy() override; // vtable+18 + virtual void SetVolume(MxS32 p_volume) override; // vtable+2c virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); //vtable+0x30 virtual void vtable0x34(); // vtable+0x34 virtual void vtable0x38(); // vtable+0x38 diff --git a/LEGO1/mxsoundpresenter.cpp b/LEGO1/mxsoundpresenter.cpp index 50e04ce4..8204c01c 100644 --- a/LEGO1/mxsoundpresenter.cpp +++ b/LEGO1/mxsoundpresenter.cpp @@ -1 +1,45 @@ #include "mxsoundpresenter.h" + +#include "decomp.h" +#include "mxsoundmanager.h" + +DECOMP_SIZE_ASSERT(MxSoundPresenter, 0x54) + +// OFFSET: LEGO1 0x1000d430 +MxSoundPresenter::~MxSoundPresenter() +{ + Destroy(TRUE); +} + +// OFFSET: LEGO1 0x100b1a50 +void MxSoundPresenter::Destroy(MxBool p_fromDestructor) +{ + if (MSoundManager()) + MSoundManager()->RemovePresenter(*this); + + this->m_criticalSection.Enter(); + MxMediaPresenter::Init(); + this->m_criticalSection.Leave(); + + if (!p_fromDestructor) + MxMediaPresenter::Destroy(FALSE); +} + +// OFFSET: LEGO1 0x100b1aa0 +MxResult MxSoundPresenter::AddToManager() +{ + MxResult ret = FAILURE; + + if (MSoundManager()) { + ret = SUCCESS; + MSoundManager()->AddPresenter(*this); + } + + return ret; +} + +// OFFSET: LEGO1 0x1000d490 +void MxSoundPresenter::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/mxsoundpresenter.h b/LEGO1/mxsoundpresenter.h index 53d7000d..a63083af 100644 --- a/LEGO1/mxsoundpresenter.h +++ b/LEGO1/mxsoundpresenter.h @@ -2,11 +2,14 @@ #define MXSOUNDPRESENTER_H #include "mxaudiopresenter.h" +#include "mxomni.h" // VTABLE 0x100d4b08 class MxSoundPresenter : public MxAudioPresenter { public: + virtual ~MxSoundPresenter() override; + // OFFSET: LEGO1 0x1000d4a0 inline virtual const char *ClassName() const // vtable+0x0c { @@ -20,6 +23,11 @@ class MxSoundPresenter : public MxAudioPresenter return !strcmp(name, MxSoundPresenter::ClassName()) || MxAudioPresenter::IsA(name); }; + virtual MxResult AddToManager() override; // vtable+0x34 + virtual void Destroy() override; // vtable+0x38 + +private: + void Destroy(MxBool); }; #endif // MXSOUNDPRESENTER_H diff --git a/LEGO1/mxstreamer.cpp b/LEGO1/mxstreamer.cpp index 84d1b7b9..3bb13b73 100644 --- a/LEGO1/mxstreamer.cpp +++ b/LEGO1/mxstreamer.cpp @@ -132,7 +132,7 @@ MxResult MxStreamer::AddStreamControllerToOpenList(MxStreamController *stream) } // OFFSET: LEGO1 0x100b99b0 -MxResult MxStreamer::Unknown100b99b0(MxDSAction* p_action) +MxResult MxStreamer::FUN_100b99b0(MxDSAction* p_action) { MxStreamController* controller; if (p_action != NULL && p_action->GetAtomId().GetInternal() != NULL && p_action->GetObjectId() != -1) @@ -147,6 +147,15 @@ MxResult MxStreamer::Unknown100b99b0(MxDSAction* p_action) return FAILURE; } +// OFFSET: LEGO1 0x100b9b30 +MxBool MxStreamer::FUN_100b9b30(MxDSObject &p_dsObject) +{ + MxStreamController *controller = GetOpenStream(p_dsObject.GetAtomId().GetInternal()); + if (controller) + return controller->FUN_100c20d0(p_dsObject); + return TRUE; +} + // OFFSET: LEGO1 0x100b9b60 MxLong MxStreamer::Notify(MxParam &p) { diff --git a/LEGO1/mxstreamer.h b/LEGO1/mxstreamer.h index b5d86e4d..3931b1fb 100644 --- a/LEGO1/mxstreamer.h +++ b/LEGO1/mxstreamer.h @@ -7,6 +7,7 @@ #include "mxcore.h" #include "mxnotificationparam.h" #include "mxstreamcontroller.h" +#include "mxdsobject.h" #include "mxtypes.h" // NOTE: This feels like some kind of templated class, maybe something from the @@ -92,11 +93,10 @@ class MxStreamer : public MxCore virtual MxResult Create(); // vtable+0x14 + MxBool FUN_100b9b30(MxDSObject &p_dsObject); MxStreamController *GetOpenStream(const char *p_name); - MxResult AddStreamControllerToOpenList(MxStreamController *p_stream); - - MxResult MxStreamer::Unknown100b99b0(MxDSAction* p_action); + MxResult FUN_100b99b0(MxDSAction* p_action); private: list m_openStreams; // 0x8 diff --git a/LEGO1/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index a22adcd4..f48a0f8b 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -2,7 +2,7 @@ #include "MxVideoManager.h" DECOMP_SIZE_ASSERT(MxVideoPresenter, 0x64); -DECOMP_SIZE_ASSERT(MxVideoPresenter::UnkStruct, 0xc); +DECOMP_SIZE_ASSERT(MxVideoPresenter::AlphaMask, 0xc); // OFFSET: LEGO1 0x1000c700 void MxVideoPresenter::VTable0x5c(undefined4 p_unknown1) @@ -49,28 +49,128 @@ LPDIRECTDRAWSURFACE MxVideoPresenter::VTable0x78() // OFFSET: LEGO1 0x1000c7c0 MxBool MxVideoPresenter::VTable0x7c() { - return (m_bitmap != NULL) || (m_unk54 != NULL); + return (m_bitmap != NULL) || (m_alpha != NULL); } // OFFSET: LEGO1 0x1000c7e0 MxS32 MxVideoPresenter::GetWidth() { - return m_unk54 ? m_unk54->width + return m_alpha ? m_alpha->m_width : m_bitmap->GetBmiHeader()->biWidth; } // OFFSET: LEGO1 0x1000c800 MxS32 MxVideoPresenter::GetHeight() { - return m_unk54 ? m_unk54->height + return m_alpha ? m_alpha->m_height : m_bitmap->GetBmiHeader()->biHeight; } +// OFFSET: LEGO1 0x100b24f0 +MxVideoPresenter::AlphaMask::AlphaMask(const MxBitmap &p_bitmap) +{ + m_width = p_bitmap.GetBmiWidth(); + // DECOMP: ECX becomes word-sized if these are not two separate actions. + MxLong _height = p_bitmap.GetBmiHeightAbs(); + m_height = _height; + + MxS32 size = ((m_width * m_height) / 8) + 1; + m_bitmask = new MxU8[size]; + memset(m_bitmask, 0, size); + + MxU32 biCompression = p_bitmap.GetBmiHeader()->biCompression; + MxU32 rows_before_top; + MxU8 *bitmap_src_ptr; + + // The goal here is to enable us to walk through the bitmap's rows + // in order, regardless of the orientation. We want to end up at the + // start of the first row, which is either at position 0, or at + // (image_stride * biHeight) - 1. + + // Reminder: Negative biHeight means this is a top-down DIB. + // Otherwise it is bottom-up. + + if (biCompression == BI_RGB) { + // DECOMP: I think this must be an OR. If not, the check for + // biCompression == 16 gets optimized away. + if (biCompression == BI_RGB_TOPDOWN || p_bitmap.GetBmiHeight() < 0) { + rows_before_top = 0; + } else { + rows_before_top = p_bitmap.GetBmiHeightAbs(); + rows_before_top--; + } + + goto seek_to_last_row; + } else if (biCompression == BI_RGB_TOPDOWN) { + // DECOMP: This is the only condition where we skip the + // calculation below. + bitmap_src_ptr = p_bitmap.GetBitmapData(); + } else { + if (p_bitmap.GetBmiHeight() < 0) { + rows_before_top = 0; + } else { + rows_before_top = p_bitmap.GetBmiHeightAbs(); + rows_before_top--; + } + +// TODO: would prefer not to use goto if we can figure this structure out +seek_to_last_row: + bitmap_src_ptr = ((p_bitmap.GetBmiWidth()+3)&-4) * rows_before_top + p_bitmap.GetBitmapData(); + } + + // How many bytes are there for each row of the bitmap? + // (i.e. the image stride) + // If this is a bottom-up DIB, we will walk it in reverse. + // TODO: Same rounding trick as in MxBitmap + MxS32 row_seek = ((m_height+3)&-4); + if (p_bitmap.GetBmiHeight() < 0) + row_seek = -row_seek; + + // The actual offset into the m_bitmask array. The two for-loops + // are just for counting the pixels. + MxS32 offset = 0; + + MxU8 *t_ptr = bitmap_src_ptr; + for (MxS32 j = 0; j < m_height; j++) { + for (MxS32 i = 0; i < m_width; i++) { + if (*t_ptr) { + // TODO: Second CDQ instruction for abs() should not be there. + MxU32 shift = abs(offset) & 7; + m_bitmask[offset / 8] |= (1 << abs(shift)); + } + t_ptr++; + offset++; + } + // Seek to the start of the next row + bitmap_src_ptr += row_seek; + t_ptr = bitmap_src_ptr; + } +} + +// OFFSET: LEGO1 0x100b2670 +MxVideoPresenter::AlphaMask::AlphaMask(const MxVideoPresenter::AlphaMask &p_alpha) +{ + m_width = p_alpha.m_width; + m_height = p_alpha.m_height; + + MxS32 size = ((m_width * m_height) / 8) + 1; + m_bitmask = new MxU8[size]; + memcpy(m_bitmask, p_alpha.m_bitmask, size); +} + + +// OFFSET: LEGO1 0x100b26d0 +MxVideoPresenter::AlphaMask::~AlphaMask() +{ + if (m_bitmask) + delete[] m_bitmask; +} + // OFFSET: LEGO1 0x100b2760 void MxVideoPresenter::Init() { m_bitmap = NULL; - m_unk54 = NULL; + m_alpha = NULL; m_unk5c = 1; m_unk58 = NULL; m_unk60 = -1; @@ -99,7 +199,7 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) m_flags = m_flags & 0xfb; } - if (MVideoManager() && (m_unk54 || m_bitmap)) { + if (MVideoManager() && (m_alpha || m_bitmap)) { MxS32 height = GetHeight(); MxS32 width = GetWidth(); @@ -112,7 +212,7 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) } delete m_bitmap; - delete m_unk54; + delete m_alpha; Init(); diff --git a/LEGO1/mxvideopresenter.h b/LEGO1/mxvideopresenter.h index 30a6ada7..61a1027c 100644 --- a/LEGO1/mxvideopresenter.h +++ b/LEGO1/mxvideopresenter.h @@ -49,16 +49,19 @@ class MxVideoPresenter : public MxMediaPresenter // TODO: Not sure what this is. Seems to have size of 12 bytes // based on 0x100b9e9a. Values are copied from the bitmap header. - struct UnkStruct { - undefined unk0[4]; - MxU16 width; - MxU16 height; + // SIZE 0xc + struct AlphaMask { + MxU8 *m_bitmask; + MxU16 m_width; + MxU16 m_height; - virtual ~UnkStruct() {} + AlphaMask(const MxBitmap &); + AlphaMask(const AlphaMask &); + virtual ~AlphaMask(); }; MxBitmap *m_bitmap; - UnkStruct *m_unk54; + AlphaMask *m_alpha; LPDIRECTDRAWSURFACE m_unk58; undefined2 m_unk5c; unsigned char m_flags; // 0x5e