From 0623e6a766a7c3bcf7aa807c9f3e224649c4a468 Mon Sep 17 00:00:00 2001
From: Christian Semmler <mail@csemmler.com>
Date: Wed, 13 Mar 2024 13:46:20 -0400
Subject: [PATCH] Implement/match LegoPointOfViewController::Tickle (#667)

---
 .../lego/legoomni/include/legonavcontroller.h |  9 +++
 .../include/legopointofviewcontroller.h       |  4 ++
 .../lego/legoomni/include/legosoundmanager.h  |  6 +-
 .../legoomni/src/audio/legosoundmanager.cpp   |  6 ++
 .../legoomni/src/entity/legonavcontroller.cpp | 13 ++++
 .../legoomni/src/entity/legopovcontroller.cpp | 59 +++++++++++++++++--
 LEGO1/lego/sources/roi/legoroi.cpp            |  6 ++
 LEGO1/lego/sources/roi/legoroi.h              |  2 +
 8 files changed, 99 insertions(+), 6 deletions(-)

diff --git a/LEGO1/lego/legoomni/include/legonavcontroller.h b/LEGO1/lego/legoomni/include/legonavcontroller.h
index e5c74f35..091ce5cd 100644
--- a/LEGO1/lego/legoomni/include/legonavcontroller.h
+++ b/LEGO1/lego/legoomni/include/legonavcontroller.h
@@ -1,9 +1,11 @@
 #ifndef LEGONAVCONTROLLER_H
 #define LEGONAVCONTROLLER_H
 
+#include "decomp.h"
 #include "mxcore.h"
 #include "mxtimer.h"
 #include "mxtypes.h"
+#include "realtime/vector.h"
 
 // VTABLE: LEGO1 0x100d85b8
 // SIZE 0x70
@@ -60,6 +62,13 @@ public:
 	float CalculateNewTargetSpeed(int p_pos, int p_center, float p_maxSpeed);
 	float CalculateNewAccel(int p_pos, int p_center, float p_maxAccel, int p_minAccel);
 	float CalculateNewVel(float p_targetVel, float p_currentVel, float p_accel, float p_time);
+	MxBool CalculateNewPosDir(
+		const Vector3& p_curPos,
+		const Vector3& p_curDir,
+		Vector3& p_newPos,
+		Vector3& p_newDir,
+		undefined* p_und
+	);
 
 	inline void SetTrackDefaultParams(MxBool p_trackDefault) { m_trackDefault = p_trackDefault; }
 
diff --git a/LEGO1/lego/legoomni/include/legopointofviewcontroller.h b/LEGO1/lego/legoomni/include/legopointofviewcontroller.h
index b6db3014..89a9e5e5 100644
--- a/LEGO1/lego/legoomni/include/legopointofviewcontroller.h
+++ b/LEGO1/lego/legoomni/include/legopointofviewcontroller.h
@@ -29,6 +29,10 @@ public:
 	virtual void RightDrag(int, int); // vtable+0x24
 	virtual void RightUp(int, int);   // vtable+0x28
 
+	BOOL GetIsButtonDown() { return m_isButtonDown; }
+	MxDouble GetButtonX() { return m_buttonX; }
+	MxDouble GetButtonY() { return m_buttonY; }
+
 private:
 	BOOL m_isButtonDown;  // 0x08
 	undefined4 m_unk0x0c; // 0x0c
diff --git a/LEGO1/lego/legoomni/include/legosoundmanager.h b/LEGO1/lego/legoomni/include/legosoundmanager.h
index 89e51165..93e2b7f9 100644
--- a/LEGO1/lego/legoomni/include/legosoundmanager.h
+++ b/LEGO1/lego/legoomni/include/legosoundmanager.h
@@ -11,13 +11,15 @@ public:
 	LegoSoundManager();
 	~LegoSoundManager() override;
 
-	MxResult Tickle() override;                                           // vtable+08
-	void Destroy() override;                                              // vtable+18
+	MxResult Tickle() override;                                           // vtable+0x08
+	void Destroy() override;                                              // vtable+0x18
 	MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread) override; // vtable+0x30
 
 	// SYNTHETIC: LEGO1 0x10029920
 	// LegoSoundManager::`scalar deleting destructor'
 
+	void FUN_1002a410(const float* p_pos, const float* p_dir, const float* p_up, const float* p_vel);
+
 	inline LegoUnknown100d6b4c* GetUnknown0x40() { return m_unk0x40; }
 
 private:
diff --git a/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp b/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp
index f3476e8e..27baac13 100644
--- a/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp
+++ b/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp
@@ -93,3 +93,9 @@ MxResult LegoSoundManager::Tickle()
 	AUTOLOCK(m_criticalSection);
 	return m_unk0x40->Tickle();
 }
+
+// STUB: LEGO1 0x1002a410
+void LegoSoundManager::FUN_1002a410(const float* p_pos, const float* p_dir, const float* p_up, const float* p_vel)
+{
+	// TODO
+}
diff --git a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp
index 93d513db..a093e53a 100644
--- a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp
+++ b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp
@@ -242,6 +242,19 @@ float LegoNavController::CalculateNewVel(float p_targetVel, float p_currentVel,
 	return newVel;
 }
 
+// STUB: LEGO1 0x10055080
+MxBool LegoNavController::CalculateNewPosDir(
+	const Vector3& p_curPos,
+	const Vector3& p_curDir,
+	Vector3& p_newPos,
+	Vector3& p_newDir,
+	undefined* p_und
+)
+{
+	// TODO
+	return TRUE;
+}
+
 // STUB: LEGO1 0x10055620
 void LegoNavController::SetLocation(MxU32 p_location)
 {
diff --git a/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp
index 0f218c43..e155df3a 100644
--- a/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp
+++ b/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp
@@ -1,12 +1,20 @@
+#include "3dmanager/lego3dview.h"
 #include "legonavcontroller.h"
 #include "legoomni.h"
 #include "legopointofviewcontroller.h"
+#include "legosoundmanager.h"
+#include "misc.h"
 #include "mxmisc.h"
 #include "mxticklemanager.h"
+#include "realtime/realtime.h"
+#include "roi/legoroi.h"
 
 DECOMP_SIZE_ASSERT(LegoMouseController, 0x20);
 DECOMP_SIZE_ASSERT(LegoPointOfViewController, 0x38);
 
+// GLOBAL: LEGO1 0x100f75ac
+MxBool g_unk0x100f75ac = FALSE;
+
 //////////////////////////////////////////////////////////////////////
 
 // FUNCTION: LEGO1 0x10065550
@@ -121,16 +129,59 @@ void LegoPointOfViewController::LeftDrag(int p_x, int p_y)
 	AffectPointOfView();
 }
 
-// STUB: LEGO1 0x10065900
+// FUNCTION: LEGO1 0x10065900
 void LegoPointOfViewController::AffectPointOfView()
 {
-	// TODO
+	m_nav->SetTargets(GetButtonX(), GetButtonY(), GetIsButtonDown());
 }
 
-// STUB: LEGO1 0x10065930
+// FUNCTION: LEGO1 0x10065930
 MxResult LegoPointOfViewController::Tickle()
 {
-	// TODO
+	ViewROI* pov = m_lego3DView->GetPointOfView();
+
+	if (pov != NULL && m_nav != NULL && m_entity == NULL) {
+		Mx3DPointFloat newDir, newPos;
+
+		Vector3 pos(pov->GetWorldPosition());
+		Vector3 dir(pov->GetWorldDirection());
+
+		if (m_nav->CalculateNewPosDir(pos, dir, newDir, newPos, NULL)) {
+			MxMatrix mat;
+
+			CalcLocalTransform(newPos, newDir, pov->GetWorldUp(), mat);
+			((TimeROI*) pov)->FUN_100a9b40(mat, Timer()->GetTime());
+			pov->WrappedSetLocalTransform(mat);
+			m_lego3DView->Moved(*pov);
+
+			SoundManager()->FUN_1002a410(
+				pov->GetWorldPosition(),
+				pov->GetWorldDirection(),
+				pov->GetWorldUp(),
+				pov->GetWorldVelocity()
+			);
+
+			g_unk0x100f75ac = FALSE;
+		}
+		else {
+			if (g_unk0x100f75ac == FALSE) {
+				Mx3DPointFloat vel;
+
+				vel.Clear();
+				pov->FUN_100a5a30(vel);
+
+				SoundManager()->FUN_1002a410(
+					pov->GetWorldPosition(),
+					pov->GetWorldDirection(),
+					pov->GetWorldUp(),
+					pov->GetWorldVelocity()
+				);
+
+				g_unk0x100f75ac = TRUE;
+			}
+		}
+	}
+
 	return SUCCESS;
 }
 
diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp
index ed604ead..8635408b 100644
--- a/LEGO1/lego/sources/roi/legoroi.cpp
+++ b/LEGO1/lego/sources/roi/legoroi.cpp
@@ -477,6 +477,12 @@ TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_t
 	m_time = p_time;
 }
 
+// STUB: LEGO1 0x100a9b40
+void TimeROI::FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time)
+{
+	// TODO
+}
+
 // FUNCTION: LEGO1 0x100a9bf0
 LegoBool LegoROI::FUN_100a9bf0(const LegoChar* p_param, float& p_red, float& p_green, float& p_blue, float& p_alpha)
 {
diff --git a/LEGO1/lego/sources/roi/legoroi.h b/LEGO1/lego/sources/roi/legoroi.h
index b5f6c7af..4f74f14f 100644
--- a/LEGO1/lego/sources/roi/legoroi.h
+++ b/LEGO1/lego/sources/roi/legoroi.h
@@ -78,6 +78,8 @@ public:
 	// SYNTHETIC: LEGO1 0x100a9ad0
 	// TimeROI::`scalar deleting destructor'
 
+	void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time);
+
 private:
 	LegoTime m_time; // 0x108
 };