From d82d062e926e2a726d951afda2810090b6f8f262 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Thu, 28 Dec 2023 23:37:21 -0500 Subject: [PATCH] Implement/match MxRegionCursor class (#385) * Implement/match MxRegionCursor class * Rename function --- CMakeLists.txt | 1 + LEGO1/mxlist.h | 30 +++- LEGO1/mxrect32.h | 8 +- LEGO1/mxregion.cpp | 6 +- LEGO1/mxregion.h | 9 +- LEGO1/mxregioncursor.cpp | 284 +++++++++++++++++++++++++++++++++++++ LEGO1/mxregioncursor.h | 45 ++++++ LEGO1/mxregionlist.h | 31 ++-- LEGO1/mxvideopresenter.cpp | 4 +- LEGO1/mxvideopresenter.h | 2 +- 10 files changed, 391 insertions(+), 29 deletions(-) create mode 100644 LEGO1/mxregioncursor.cpp create mode 100644 LEGO1/mxregioncursor.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b4676767..3b31a548 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ add_library(lego1 SHARED LEGO1/mxramstreamcontroller.cpp LEGO1/mxramstreamprovider.cpp LEGO1/mxregion.cpp + LEGO1/mxregioncursor.cpp LEGO1/mxrendersettings.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp diff --git a/LEGO1/mxlist.h b/LEGO1/mxlist.h index 8a5f3e0e..80fa0e00 100644 --- a/LEGO1/mxlist.h +++ b/LEGO1/mxlist.h @@ -92,13 +92,23 @@ public: void Detach(); void Destroy(); MxBool Next(T& p_obj); + MxBool Prev(T& p_obj); MxBool Current(T& p_obj); MxBool First(T& p_obj); MxBool Last(T& p_obj); MxBool Advance(); MxBool HasMatch() { return m_match != NULL; } void SetValue(T p_obj); - void Head() { m_match = m_list->m_first; } + MxBool Head() + { + m_match = m_list->m_first; + return m_match != NULL; + } + MxBool Tail() + { + m_match = m_list->m_last; + return m_match != NULL; + } void Reset() { m_match = NULL; } void Prepend(T p_newobj); @@ -110,8 +120,8 @@ public: } private: - MxList* m_list; - MxListEntry* m_match; + MxList* m_list; // 0x08 + MxListEntry* m_match; // 0x0c }; template @@ -226,6 +236,20 @@ inline MxBool MxListCursor::Next(T& p_obj) return m_match != NULL; } +template +inline MxBool MxListCursor::Prev(T& p_obj) +{ + if (!m_match) + m_match = m_list->m_last; + else + m_match = m_match->GetPrev(); + + if (m_match) + p_obj = m_match->GetValue(); + + return m_match != NULL; +} + template inline MxBool MxListCursor::Current(T& p_obj) { diff --git a/LEGO1/mxrect32.h b/LEGO1/mxrect32.h index b54a9d92..7566a9ea 100644 --- a/LEGO1/mxrect32.h +++ b/LEGO1/mxrect32.h @@ -110,10 +110,10 @@ private: inline static MxS32 Min(MxS32 p_a, MxS32 p_b) { return p_a <= p_b ? p_a : p_b; }; inline static MxS32 Max(MxS32 p_a, MxS32 p_b) { return p_a <= p_b ? p_b : p_a; }; - MxS32 m_left; - MxS32 m_top; - MxS32 m_right; - MxS32 m_bottom; + MxS32 m_left; // 0x00 + MxS32 m_top; // 0x04 + MxS32 m_right; // 0x08 + MxS32 m_bottom; // 0x0c }; #endif // MXRECT32_H diff --git a/LEGO1/mxregion.cpp b/LEGO1/mxregion.cpp index f003aceb..d21b9fdb 100644 --- a/LEGO1/mxregion.cpp +++ b/LEGO1/mxregion.cpp @@ -9,7 +9,7 @@ DECOMP_SIZE_ASSERT(MxRegionLeftRight, 0x08); // FUNCTION: LEGO1 0x100c31c0 MxRegion::MxRegion() { - m_list = new MxRegionList; + m_list = new MxRegionTopBottomList; m_rect = MxRect32(INT_MAX, INT_MAX, -1, -1); } @@ -38,7 +38,7 @@ void MxRegion::VTable0x18(MxRect32& p_rect) { MxRect32 rect(p_rect); MxRect32 newRect; - MxRegionListCursor cursor(m_list); + MxRegionTopBottomListCursor cursor(m_list); MxRegionTopBottom* topBottom; while (rect.IsValid() && cursor.Next(topBottom)) { @@ -91,7 +91,7 @@ MxBool MxRegion::VTable0x1c(MxRect32& p_rect) if (!m_rect.IntersectsWith(p_rect)) return FALSE; - MxRegionListCursor cursor(m_list); + MxRegionTopBottomListCursor cursor(m_list); MxRegionTopBottom* topBottom; while (cursor.Next(topBottom)) { diff --git a/LEGO1/mxregion.h b/LEGO1/mxregion.h index c7d7dd90..646866a6 100644 --- a/LEGO1/mxregion.h +++ b/LEGO1/mxregion.h @@ -18,11 +18,14 @@ public: virtual MxBool VTable0x1c(MxRect32& p_rect); // vtable+0x1c virtual MxBool VTable0x20(); // vtable+0x20 - inline MxRect32& GetRect() { return this->m_rect; } + inline MxRegionTopBottomList* GetTopBottomList() const { return m_list; } + inline const MxRect32& GetRect() const { return m_rect; } + + friend class MxRegionCursor; private: - MxRegionList* m_list; // 0x08 - MxRect32 m_rect; // 0x0c + MxRegionTopBottomList* m_list; // 0x08 + MxRect32 m_rect; // 0x0c }; #endif // MXREGION_H diff --git a/LEGO1/mxregioncursor.cpp b/LEGO1/mxregioncursor.cpp new file mode 100644 index 00000000..89c90403 --- /dev/null +++ b/LEGO1/mxregioncursor.cpp @@ -0,0 +1,284 @@ +#include "mxregioncursor.h" + +DECOMP_SIZE_ASSERT(MxRegionCursor, 0x18); + +// FUNCTION: LEGO1 0x100c3f70 +MxRegionCursor::MxRegionCursor(MxRegion* p_region) +{ + m_region = p_region; + m_rect = NULL; + m_topBottomCursor = new MxRegionTopBottomListCursor(m_region->m_list); + m_leftRightCursor = NULL; +} + +// FUNCTION: LEGO1 0x100c40b0 +MxRegionCursor::~MxRegionCursor() +{ + if (m_rect) + delete m_rect; + + if (m_topBottomCursor) + delete m_topBottomCursor; + + if (m_leftRightCursor) + delete m_leftRightCursor; +} + +// FUNCTION: LEGO1 0x100c4140 +MxRect32* MxRegionCursor::VTable0x18() +{ + m_topBottomCursor->Head(); + + MxRegionTopBottom* topBottom; + if (m_topBottomCursor->Current(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + m_leftRightCursor->First(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + } + else + Reset(); + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c41d0 +MxRect32* MxRegionCursor::VTable0x20() +{ + m_topBottomCursor->Tail(); + + MxRegionTopBottom* topBottom; + if (m_topBottomCursor->Current(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + m_leftRightCursor->Last(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + } + else + Reset(); + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4260 +MxRect32* MxRegionCursor::VTable0x28() +{ + MxRegionLeftRight* leftRight; + MxRegionTopBottom* topBottom; + + if (m_leftRightCursor && m_leftRightCursor->Next(leftRight)) { + m_topBottomCursor->Current(topBottom); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + if (m_topBottomCursor->Next(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + m_leftRightCursor->First(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + Reset(); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4360 +MxRect32* MxRegionCursor::VTable0x30() +{ + MxRegionLeftRight* leftRight; + MxRegionTopBottom* topBottom; + + if (m_leftRightCursor && m_leftRightCursor->Prev(leftRight)) { + m_topBottomCursor->Current(topBottom); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + if (m_topBottomCursor->Prev(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + m_leftRightCursor->Last(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + Reset(); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4460 +MxRect32* MxRegionCursor::VTable0x14(MxRect32& p_rect) +{ + m_topBottomCursor->Reset(); + FUN_100c4a20(p_rect); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4480 +MxRect32* MxRegionCursor::VTable0x1c(MxRect32& p_rect) +{ + m_topBottomCursor->Reset(); + FUN_100c4b50(p_rect); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c44a0 +MxRect32* MxRegionCursor::VTable0x24(MxRect32& p_rect) +{ + MxRegionLeftRight* leftRight; + + if (m_leftRightCursor && m_leftRightCursor->Next(leftRight)) { + MxRegionTopBottom* topBottom; + + m_topBottomCursor->Current(topBottom); + + if (topBottom->IntersectsWith(p_rect) && leftRight->IntersectsWith(p_rect)) { + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + m_rect->Intersect(p_rect); + } + else + FUN_100c4a20(p_rect); + } + else + FUN_100c4a20(p_rect); + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4590 +MxRect32* MxRegionCursor::VTable0x2c(MxRect32& p_rect) +{ + MxRegionLeftRight* leftRight; + + if (m_leftRightCursor && m_leftRightCursor->Prev(leftRight)) { + MxRegionTopBottom* topBottom; + + m_topBottomCursor->Current(topBottom); + + if (topBottom->IntersectsWith(p_rect) && leftRight->IntersectsWith(p_rect)) { + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + m_rect->Intersect(p_rect); + } + else + FUN_100c4b50(p_rect); + } + else + FUN_100c4b50(p_rect); + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4680 +void MxRegionCursor::Reset() +{ + if (m_rect) { + delete m_rect; + m_rect = NULL; + } + + m_topBottomCursor->Reset(); + + if (m_leftRightCursor) { + delete m_leftRightCursor; + m_leftRightCursor = NULL; + } +} + +// FUNCTION: LEGO1 0x100c46c0 +void MxRegionCursor::FUN_100c46c0(MxRegionLeftRightList& p_leftRightList) +{ + if (m_leftRightCursor) + delete m_leftRightCursor; + + m_leftRightCursor = new MxRegionLeftRightListCursor(&p_leftRightList); +} + +// FUNCTION: LEGO1 0x100c4980 +void MxRegionCursor::UpdateRect(MxS32 p_left, MxS32 p_top, MxS32 p_right, MxS32 p_bottom) +{ + if (!m_rect) + m_rect = new MxRect32; + + m_rect->SetLeft(p_left); + m_rect->SetTop(p_top); + m_rect->SetRight(p_right); + m_rect->SetBottom(p_bottom); +} + +// FUNCTION: LEGO1 0x100c4a20 +void MxRegionCursor::FUN_100c4a20(MxRect32& p_rect) +{ + MxRegionTopBottom* topBottom; + while (m_topBottomCursor->Next(topBottom)) { + if (p_rect.GetBottom() <= topBottom->GetTop()) { + Reset(); + return; + } + + if (p_rect.GetTop() < topBottom->GetBottom()) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + while (m_leftRightCursor->Next(leftRight)) { + if (p_rect.GetRight() <= leftRight->GetLeft()) + break; + + if (p_rect.GetLeft() < leftRight->GetRight()) { + UpdateRect( + leftRight->GetLeft(), + topBottom->GetTop(), + leftRight->GetRight(), + topBottom->GetBottom() + ); + m_rect->Intersect(p_rect); + return; + } + } + } + } + + Reset(); +} + +// FUNCTION: LEGO1 0x100c4b50 +void MxRegionCursor::FUN_100c4b50(MxRect32& p_rect) +{ + MxRegionTopBottom* topBottom; + while (m_topBottomCursor->Prev(topBottom)) { + if (topBottom->GetBottom() <= p_rect.GetTop()) { + Reset(); + return; + } + + if (topBottom->GetTop() < p_rect.GetBottom()) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + while (m_leftRightCursor->Prev(leftRight)) { + if (leftRight->GetRight() <= p_rect.GetLeft()) + break; + + if (leftRight->GetLeft() < p_rect.GetRight()) { + UpdateRect( + leftRight->GetLeft(), + topBottom->GetTop(), + leftRight->GetRight(), + topBottom->GetBottom() + ); + m_rect->Intersect(p_rect); + return; + } + } + } + } + + Reset(); +} diff --git a/LEGO1/mxregioncursor.h b/LEGO1/mxregioncursor.h new file mode 100644 index 00000000..5f4a24b8 --- /dev/null +++ b/LEGO1/mxregioncursor.h @@ -0,0 +1,45 @@ +#ifndef MXREGIONCURSOR_H +#define MXREGIONCURSOR_H + +#include "mxregion.h" + +// VTABLE: LEGO1 0x100dcbb8 +// SIZE 0x18 +class MxRegionCursor : public MxCore { +public: + MxRegionCursor(MxRegion* p_region); + virtual ~MxRegionCursor() override; + + virtual MxRect32* VTable0x14(MxRect32& p_rect); // vtable+0x14 + virtual MxRect32* VTable0x18(); // vtable+0x18 + virtual MxRect32* VTable0x1c(MxRect32& p_rect); // vtable+0x1c + virtual MxRect32* VTable0x20(); // vtable+0x20 + virtual MxRect32* VTable0x24(MxRect32& p_rect); // vtable+0x24 + virtual MxRect32* VTable0x28(); // vtable+0x28 + virtual MxRect32* VTable0x2c(MxRect32& p_rect); // vtable+0x2c + virtual MxRect32* VTable0x30(); // vtable+0x30 + + // FUNCTION: LEGO1 0x100c4070 + virtual MxRect32* GetRect() { return m_rect; } // vtable+0x34 + + // FUNCTION: LEGO1 0x100c4080 + virtual MxBool HasRect() { return m_rect != NULL; } // vtable+0x38 + + virtual void Reset(); // vtable+0x3c + +private: + void FUN_100c46c0(MxRegionLeftRightList& p_leftRightList); + void UpdateRect(MxS32 p_left, MxS32 p_top, MxS32 p_right, MxS32 p_bottom); + void FUN_100c4a20(MxRect32& p_rect); + void FUN_100c4b50(MxRect32& p_rect); + + MxRegion* m_region; // 0x08 + MxRect32* m_rect; // 0x0c + MxRegionTopBottomListCursor* m_topBottomCursor; // 0x10 + MxRegionLeftRightListCursor* m_leftRightCursor; // 0x14 +}; + +// SYNTHETIC: LEGO1 0x100c4090 +// MxRegionCursor::`scalar deleting destructor' + +#endif // MXREGIONCURSOR_H diff --git a/LEGO1/mxregionlist.h b/LEGO1/mxregionlist.h index ef3712cb..7c6da5c2 100644 --- a/LEGO1/mxregionlist.h +++ b/LEGO1/mxregionlist.h @@ -19,9 +19,11 @@ struct MxRegionLeftRight { inline void SetLeft(MxS32 p_left) { m_left = p_left; } inline void SetRight(MxS32 p_right) { m_right = p_right; } + inline MxBool IntersectsWith(MxRect32& p_rect) { return m_left < p_rect.GetRight() && p_rect.GetTop() < m_right; } + private: - MxS32 m_left; - MxS32 m_right; + MxS32 m_left; // 0x00 + MxS32 m_right; // 0x04 }; // VTABLE: LEGO1 0x100dcc40 @@ -68,12 +70,15 @@ struct MxRegionTopBottom { inline void SetTop(MxS32 p_top) { m_top = p_top; } inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; } - friend class MxRegionList; + inline MxBool IntersectsWith(MxRect32& p_rect) { return m_top < p_rect.GetBottom() && p_rect.GetTop() < m_bottom; } + + friend class MxRegionTopBottomList; + friend class MxRegionCursor; private: - MxS32 m_top; - MxS32 m_bottom; - MxRegionLeftRightList* m_leftRightList; + MxS32 m_top; // 0x00 + MxS32 m_bottom; // 0x04 + MxRegionLeftRightList* m_leftRightList; // 0x08 }; // VTABLE: LEGO1 0x100dcb10 @@ -87,9 +92,9 @@ private: // VTABLE: LEGO1 0x100dcb58 // SIZE 0x18 -class MxRegionList : public MxPtrList { +class MxRegionTopBottomList : public MxPtrList { public: - MxRegionList() : MxPtrList(TRUE) {} + MxRegionTopBottomList() : MxPtrList(TRUE) {} }; // VTABLE: LEGO1 0x100dcb70 @@ -98,14 +103,14 @@ public: // VTABLE: LEGO1 0x100dcba0 // class MxListCursor -// TODO: The initialize list param type should be MxRegionList, but doing that +// TODO: The initialize list param type should be MxRegionTopBottomList, but doing that // drastically reduced the match percentage for MxRegion::VTable0x18. // It also works with MxPtrList, so we'll do that until we figure this out. // VTABLE: LEGO1 0x100dcb88 -class MxRegionListCursor : public MxPtrListCursor { +class MxRegionTopBottomListCursor : public MxPtrListCursor { public: - MxRegionListCursor(MxPtrList* p_list) : MxPtrListCursor(p_list){}; + MxRegionTopBottomListCursor(MxPtrList* p_list) : MxPtrListCursor(p_list){}; }; // TEMPLATE: LEGO1 0x100c32e0 @@ -127,7 +132,7 @@ public: // MxPtrList::`scalar deleting destructor' // SYNTHETIC: LEGO1 0x100c3be0 -// MxRegionListCursor::`scalar deleting destructor' +// MxRegionTopBottomListCursor::`scalar deleting destructor' // TEMPLATE: LEGO1 0x100c3c50 // MxPtrListCursor::~MxPtrListCursor @@ -142,7 +147,7 @@ public: // MxListCursor::~MxListCursor // FUNCTION: LEGO1 0x100c3dd0 -// MxRegionListCursor::~MxRegionListCursor +// MxRegionTopBottomListCursor::~MxRegionTopBottomListCursor // SYNTHETIC: LEGO1 0x100c4790 // MxRegionLeftRightListCursor::`scalar deleting destructor' diff --git a/LEGO1/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index b1beb08e..4162be43 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -313,7 +313,7 @@ MxBool MxVideoPresenter::IsHit(MxS32 p_x, MxS32 p_y) } // STUB: LEGO1 0x100b2a70 -void MxVideoPresenter::VTable0x6c() +void MxVideoPresenter::PutFrame() { // TODO } @@ -482,7 +482,7 @@ MxResult MxVideoPresenter::PutData() MxAutoLocker lock(&m_criticalSection); if (IsEnabled() && m_currentTickleState >= TickleState_Streaming && m_currentTickleState <= TickleState_unk5) - VTable0x6c(); + PutFrame(); return SUCCESS; } diff --git a/LEGO1/mxvideopresenter.h b/LEGO1/mxvideopresenter.h index 4c1bab5e..72ea33d8 100644 --- a/LEGO1/mxvideopresenter.h +++ b/LEGO1/mxvideopresenter.h @@ -47,7 +47,7 @@ public: virtual void CreateBitmap(); // vtable+0x60 virtual void NextFrame(); // vtable+0x64 virtual void LoadFrame(MxStreamChunk* p_chunk); // vtable+0x68 - virtual void VTable0x6c(); // vtable+0x6c + virtual void PutFrame(); // vtable+0x6c virtual void RealizePalette(); // vtable+0x70 virtual undefined VTable0x74(); // vtable+0x74 virtual LPDIRECTDRAWSURFACE VTable0x78(); // vtable+0x78