From d145f914c464a3b1892e6c4a70ceb12dadd3c91a Mon Sep 17 00:00:00 2001
From: Christian Semmler <mail@csemmler.com>
Date: Tue, 19 Sep 2023 23:00:34 -0400
Subject: [PATCH] Implement/match MxVideoManager::Tickle (#128)

* Implement/match MxPresenter::StartAction

* Update mxpoint32.h

* Implement/match MxVideoManager::Tickle

* Update mxlist.h

* Update mxpresenter.cpp
---
 LEGO1/mxlist.h           | 12 +++++-
 LEGO1/mxmediamanager.cpp |  4 +-
 LEGO1/mxmediamanager.h   |  6 +--
 LEGO1/mxpresenter.cpp    | 10 ++---
 LEGO1/mxpresenter.h      |  8 ++--
 LEGO1/mxpresenterlist.h  |  2 +
 LEGO1/mxregion.h         | 26 +++++++++++
 LEGO1/mxvideomanager.cpp | 93 ++++++++++++++++++++++++++++++++--------
 LEGO1/mxvideomanager.h   |  9 ++--
 9 files changed, 133 insertions(+), 37 deletions(-)
 create mode 100644 LEGO1/mxregion.h

diff --git a/LEGO1/mxlist.h b/LEGO1/mxlist.h
index da2c3e4e..013ef852 100644
--- a/LEGO1/mxlist.h
+++ b/LEGO1/mxlist.h
@@ -59,6 +59,7 @@ public:
   virtual ~MxList();
 
   void Append(T*);
+  MxU32 GetCount() { return m_count; }
 
   friend class MxListCursor<T>;
 
@@ -83,6 +84,8 @@ public:
   MxBool Find(T *p_obj);
   void Detach();
   MxBool Next(T*& p_obj);
+  void SetValue(T *p_obj);
+  void Head() { m_match = m_list->m_first; }
   void Reset() { m_match = NULL; }
 
 private:
@@ -193,4 +196,11 @@ inline MxBool MxListCursor<T>::Next(T*& p_obj)
   return m_match != NULL;
 }
 
-#endif // MXLIST_H
\ No newline at end of file
+template <class T>
+inline void MxListCursor<T>::SetValue(T *p_obj)
+{
+  if (m_match)
+    m_match->m_obj = p_obj;
+}
+
+#endif // MXLIST_H
diff --git a/LEGO1/mxmediamanager.cpp b/LEGO1/mxmediamanager.cpp
index b890eec4..3fb28d37 100644
--- a/LEGO1/mxmediamanager.cpp
+++ b/LEGO1/mxmediamanager.cpp
@@ -5,8 +5,6 @@
 
 DECOMP_SIZE_ASSERT(MxMediaManager, 0x2c);
 
-typedef MxListCursorChildChild<MxPresenter> MxPresenterListCursor;
-
 // OFFSET: LEGO1 0x100b84c0
 MxMediaManager::MxMediaManager()
 {
@@ -40,7 +38,7 @@ MxResult MxMediaManager::Tickle()
   cursor.Reset();
 
   while (cursor.Next(presenter))
-    presenter->VTable0x4c();
+    presenter->PutData();
 
   return SUCCESS;
 }
diff --git a/LEGO1/mxmediamanager.h b/LEGO1/mxmediamanager.h
index 9df073bc..ccc3ec42 100644
--- a/LEGO1/mxmediamanager.h
+++ b/LEGO1/mxmediamanager.h
@@ -23,12 +23,10 @@ public:
   virtual void StopPresenters(); // vtable+24
 
   MxResult Init();
-  
-private:
-  MxPresenterList *m_presenters;
-  MxThread *m_thread; // 0xc
 
 protected:
+  MxPresenterList *m_presenters;
+  MxThread *m_thread; // 0xc
   MxCriticalSection m_criticalSection; // 0x10
 };
 
diff --git a/LEGO1/mxpresenter.cpp b/LEGO1/mxpresenter.cpp
index cf934fe7..e82aa3a4 100644
--- a/LEGO1/mxpresenter.cpp
+++ b/LEGO1/mxpresenter.cpp
@@ -20,7 +20,7 @@ void MxPresenter::Init()
   m_currentTickleState = TickleState_Idle;
   m_action = NULL;
   m_location = MxPoint32(0, 0);
-  m_locationZ = 0;
+  m_displayZ = 0;
   m_unkPresenter = NULL;
   m_previousTickleStates = 0;
 }
@@ -129,7 +129,7 @@ MxLong MxPresenter::StartAction(MxStreamController *, MxDSAction *p_action)
   MxS32 previousTickleState = this->m_currentTickleState;
 
   this->m_location = MxPoint32(location[0], location[1]);
-  this->m_locationZ = location[2];
+  this->m_displayZ = location[2];
   this->m_previousTickleStates |= 1 << (unsigned char)previousTickleState;
   this->m_currentTickleState = TickleState_Ready;
 
@@ -236,13 +236,13 @@ MxBool MxPresenter::HasTickleStatePassed(TickleState p_tickleState)
 }
 
 // OFFSET: LEGO1 0x1000bfc0
-undefined4 MxPresenter::VTable0x4c()
+undefined4 MxPresenter::PutData()
 {
   return 0;
 }
 
 // OFFSET: LEGO1 0x1000bfd0
-undefined MxPresenter::VTable0x50(undefined4, undefined4)
+MxBool MxPresenter::IsHit(MxS32 p_x, MxS32 p_y)
 {
-  return 0;
+  return FALSE;
 }
diff --git a/LEGO1/mxpresenter.h b/LEGO1/mxpresenter.h
index f20ac647..b7e99edf 100644
--- a/LEGO1/mxpresenter.h
+++ b/LEGO1/mxpresenter.h
@@ -62,12 +62,14 @@ public:
   __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 VTable0x4c(); // vtable+0x4c
-  virtual undefined VTable0x50(undefined4, undefined4); // vtable+0x50
+  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();
 
+  inline MxS32 GetDisplayZ() { return this->m_displayZ; }
+
 protected:
   __declspec(dllexport) void Init();
   void SendTo_unkPresenter(MxOmni *);
@@ -76,7 +78,7 @@ private:
   MxS32 m_currentTickleState; // 0x8
   MxU32 m_previousTickleStates;
   MxPoint32 m_location;
-  MxS32 m_locationZ;
+  MxS32 m_displayZ;
   MxDSAction *m_action; // 0
   MxCriticalSection m_criticalSection;
   MxPresenter *m_unkPresenter; // 0x3c
diff --git a/LEGO1/mxpresenterlist.h b/LEGO1/mxpresenterlist.h
index 9373040d..5b36e2d8 100644
--- a/LEGO1/mxpresenterlist.h
+++ b/LEGO1/mxpresenterlist.h
@@ -24,4 +24,6 @@ public:
   virtual MxS8 Compare(MxPresenter *, MxPresenter *); // +0x14
 };
 
+typedef MxListCursorChildChild<MxPresenter> MxPresenterListCursor;
+
 #endif // MXPRESENTERLIST_H
diff --git a/LEGO1/mxregion.h b/LEGO1/mxregion.h
new file mode 100644
index 00000000..717be924
--- /dev/null
+++ b/LEGO1/mxregion.h
@@ -0,0 +1,26 @@
+#ifndef MXREGION_H
+#define MXREGION_H
+
+#include "mxcore.h"
+
+// VTABLE 0x100dcae8
+// SIZE 0x1c
+class MxRegion : public MxCore
+{
+public:
+  MxRegion();
+  virtual ~MxRegion() override;
+
+  virtual void Reset();
+  virtual void vtable18();
+  virtual void vtable1c();
+  virtual void vtable20();
+
+private:
+  // A container (probably MxList) holding MxRect32
+  // MxList<MxRect32> *m_rects;
+  // 4 coordinates (could be MxRect32)
+  // MxS32 left, top, right, bottom;
+};
+
+#endif // MXREGION_H
diff --git a/LEGO1/mxvideomanager.cpp b/LEGO1/mxvideomanager.cpp
index 7663743d..81d431a9 100644
--- a/LEGO1/mxvideomanager.cpp
+++ b/LEGO1/mxvideomanager.cpp
@@ -1,18 +1,6 @@
 #include "mxvideomanager.h"
-
-// OFFSET: LEGO1 0x100be2a0 STUB
-MxVideoManager::~MxVideoManager()
-{
-  // TODO
-}
-
-// OFFSET: LEGO1 0x100bea90 STUB
-MxLong MxVideoManager::Tickle()
-{
-  // TODO
-  
-  return 0;
-}
+#include "mxautolocker.h"
+#include "mxpresenter.h"
 
 // OFFSET: LEGO1 0x100be1f0
 MxVideoManager::MxVideoManager()
@@ -20,16 +8,85 @@ MxVideoManager::MxVideoManager()
   Init();
 }
 
+// OFFSET: LEGO1 0x100be2a0 STUB
+MxVideoManager::~MxVideoManager()
+{
+  // TODO
+}
+
+// OFFSET: LEGO1 0x100bea90
+MxLong MxVideoManager::Tickle()
+{
+  MxAutoLocker lock(&this->m_criticalSection);
+
+  SortPresenterList();
+
+  MxPresenter *presenter;
+  MxPresenterListCursor cursor(this->m_presenters);
+
+  while (cursor.Next(presenter))
+    presenter->Tickle();
+
+  cursor.Reset();
+
+  while (cursor.Next(presenter))
+    presenter->PutData();
+
+  UpdateRegion();
+  m_region->Reset();
+  
+  return SUCCESS;
+}
+
 // OFFSET: LEGO1 0x100be320
-int MxVideoManager::Init()
+MxResult MxVideoManager::Init()
 {
   this->m_pDirectDraw = NULL;
-  this->m_unk54 = NULL;
+  this->m_pDDSurface = NULL;
   this->m_displaySurface = NULL;
-  this->m_unk5c = 0;
+  this->m_region = NULL;
   this->m_videoParam.SetPalette(NULL);
   this->m_unk60 = FALSE;
-  return 0;
+  return SUCCESS;
+}
+
+// OFFSET: LEGO1 0x100be440
+void MxVideoManager::SortPresenterList()
+{
+  if (this->m_presenters->GetCount() <= 1)
+    return; 
+
+  MxPresenterListCursor a(this->m_presenters);
+  MxPresenterListCursor b(this->m_presenters);
+  MxU32 count = this->m_presenters->GetCount() - 1;
+  MxBool finished;
+    
+  if (count != 0) {
+    do {
+      a.Reset();
+      b.Head();
+
+      finished = TRUE;
+      for (MxU32 i = count; i != 0; i--) {
+        MxPresenter *p_a, *p_b;
+
+        a.Next(p_a);
+        b.Next(p_b);
+
+        if (p_a->GetDisplayZ() < p_b->GetDisplayZ()) {
+          a.SetValue(p_b);
+          b.SetValue(p_a);
+          finished = FALSE;
+        }
+      }
+    } while (!finished && --count != 0);
+  }
+}
+
+// OFFSET: LEGO1 0x100be3e0 STUB
+void MxVideoManager::UpdateRegion()
+{
+  // TODO
 }
 
 // OFFSET: LEGO1 0x100bea60 STUB
diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h
index 03eac8aa..a7cde92f 100644
--- a/LEGO1/mxvideomanager.h
+++ b/LEGO1/mxvideomanager.h
@@ -2,6 +2,7 @@
 #define MXVIDEOMANAGER_H
 
 #include "mxdisplaysurface.h"
+#include "mxregion.h"
 #include "mxmediamanager.h"
 #include "mxvideoparam.h"
 
@@ -19,16 +20,18 @@ public:
 
   MxVideoManager();
 
-  int Init();
+  MxResult Init();
+  void SortPresenterList();
+  void UpdateRegion();
 
   inline MxVideoParam& GetVideoParam() { return this->m_videoParam; }
   inline LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; }
 private:
   MxVideoParam m_videoParam;
   LPDIRECTDRAW m_pDirectDraw;
-  LPDIRECTDRAWSURFACE m_unk54;
+  LPDIRECTDRAWSURFACE m_pDDSurface;
   MxDisplaySurface *m_displaySurface;
-  int m_unk5c;
+  MxRegion *m_region;
   MxBool m_unk60;
 };