From d77b1dfd67eefe3fcfb780d99bdd0f0e7ea07187 Mon Sep 17 00:00:00 2001 From: Tristan Cormier Date: Sat, 14 Feb 2026 20:27:36 -0500 Subject: [PATCH 01/31] chore(net): rename character creation NETMESSAGE enum members --- src/net/Types.hpp | 4 ++-- src/net/connection/RealmConnection.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/net/Types.hpp b/src/net/Types.hpp index 3515db6..7db2ddb 100644 --- a/src/net/Types.hpp +++ b/src/net/Types.hpp @@ -60,11 +60,11 @@ enum NETMESSAGE { CMSG_AUTH_SRP6_BEGIN = 0x0033, CMSG_AUTH_SRP6_PROOF = 0x0034, CMSG_AUTH_SRP6_RECODE = 0x0035, - CMSG_CREATE_CHARACTER = 0x0036, + CMSG_CHAR_CREATE = 0x0036, CMSG_ENUM_CHARACTERS = 0x0037, CMSG_CHAR_DELETE = 0x0038, SMSG_AUTH_SRP6_RESPONSE = 0x0039, - SMSG_CREATE_CHAR = 0x003A, + SMSG_CHAR_CREATE = 0x003A, SMSG_ENUM_CHARACTERS_RESULT = 0x003B, SMSG_DELETE_CHAR = 0x003C, CMSG_PLAYER_LOGIN = 0x003D, diff --git a/src/net/connection/RealmConnection.cpp b/src/net/connection/RealmConnection.cpp index a60549e..9bc0a6a 100644 --- a/src/net/connection/RealmConnection.cpp +++ b/src/net/connection/RealmConnection.cpp @@ -19,7 +19,7 @@ int32_t RealmConnection::MessageHandler(void* param, NETMESSAGE msgId, uint32_t break; } - case SMSG_CREATE_CHAR: { + case SMSG_CHAR_CREATE: { // TODO break; } @@ -91,7 +91,7 @@ RealmConnection::RealmConnection(RealmResponse* realmResponse) { this->SetMessageHandler(SMSG_AUTH_RESPONSE, &RealmConnection::MessageHandler, this); this->SetMessageHandler(SMSG_ADDON_INFO, &RealmConnection::MessageHandler, this); this->SetMessageHandler(SMSG_ENUM_CHARACTERS_RESULT, &RealmConnection::MessageHandler, this); - this->SetMessageHandler(SMSG_CREATE_CHAR, &RealmConnection::MessageHandler, this); + this->SetMessageHandler(SMSG_CHAR_CREATE, &RealmConnection::MessageHandler, this); this->SetMessageHandler(SMSG_CHARACTER_LOGIN_FAILED, &RealmConnection::MessageHandler, this); this->SetMessageHandler(SMSG_LOGOUT_COMPLETE, &RealmConnection::MessageHandler, this); this->SetMessageHandler(SMSG_LOGOUT_CANCEL_ACK, &RealmConnection::MessageHandler, this); From 71a31e19bd355021e416d9d882f6117841930fe9 Mon Sep 17 00:00:00 2001 From: Tristan Cormier Date: Sat, 14 Feb 2026 20:36:19 -0500 Subject: [PATCH 02/31] chore(glue): rename IDLE_5 to IDLE_CREATE_CHARACTER --- src/glue/CGlueMgr.cpp | 2 +- src/glue/CGlueMgr.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/glue/CGlueMgr.cpp b/src/glue/CGlueMgr.cpp index 6a21ac4..6528583 100644 --- a/src/glue/CGlueMgr.cpp +++ b/src/glue/CGlueMgr.cpp @@ -1129,7 +1129,7 @@ void CGlueMgr::StatusDialogClick() { } case IDLE_REALM_LIST: - case IDLE_5: + case IDLE_CREATE_CHARACTER: case IDLE_DELETE_CHARACTER: case IDLE_ENTER_WORLD: { ClientServices::Connection()->Cancel(2); diff --git a/src/glue/CGlueMgr.hpp b/src/glue/CGlueMgr.hpp index 258fbee..38e369b 100644 --- a/src/glue/CGlueMgr.hpp +++ b/src/glue/CGlueMgr.hpp @@ -20,7 +20,7 @@ class CGlueMgr { IDLE_ACCOUNT_LOGIN = 2, IDLE_CHARACTER_LIST = 3, IDLE_REALM_LIST = 4, - IDLE_5 = 5, + IDLE_CREATE_CHARACTER = 5, IDLE_DELETE_CHARACTER = 6, IDLE_7 = 7, IDLE_8 = 8, From 86084516cdf47b46f2b5a3a048e66ea25ebce485 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 15 Feb 2026 12:42:14 -0600 Subject: [PATCH 03/31] feat(ui): add CSimpleCamera --- lib/typhoon | 2 +- src/ui/simple/CSimpleCamera.cpp | 52 +++++++++++++++++++++++++++++++++ src/ui/simple/CSimpleCamera.hpp | 35 ++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/ui/simple/CSimpleCamera.cpp create mode 100644 src/ui/simple/CSimpleCamera.hpp diff --git a/lib/typhoon b/lib/typhoon index 1c9e783..a7733b6 160000 --- a/lib/typhoon +++ b/lib/typhoon @@ -1 +1 @@ -Subproject commit 1c9e7831c874068e7c939a7dea8790eef6513d78 +Subproject commit a7733b6a8c2d52f081fbd74ca40d7ca8f94e1209 diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp new file mode 100644 index 0000000..db439c1 --- /dev/null +++ b/src/ui/simple/CSimpleCamera.cpp @@ -0,0 +1,52 @@ +#include "ui/simple/CSimpleCamera.hpp" + +CSimpleCamera::CSimpleCamera(float nearZ, float farZ, float fov) { + this->float10 = 0.0f; + + this->m_nearZ = nearZ; + this->m_farZ = farZ; + this->m_fov = fov; + this->m_aspect = 1.0f; + + this->SetFacing(0.0f, 0.0f, 0.0f); +} + +float CSimpleCamera::FOV() { + return this->m_fov; +} + +C3Vector CSimpleCamera::Forward() const { + return { this->m_facing.a0, this->m_facing.a1, this->m_facing.a2 }; +} + +C3Vector CSimpleCamera::Right() const { + return { this->m_facing.b0, this->m_facing.b1, this->m_facing.b2 }; +} + +void CSimpleCamera::SetFacing(const C3Vector& forward) { + // TODO +} + +void CSimpleCamera::SetFacing(const C3Vector& forward, const C3Vector& up) { + // TODO +} + +void CSimpleCamera::SetFacing(float yaw, float pitch, float roll) { + this->m_facing.FromEulerAnglesZYX(yaw, pitch, roll); +} + +void CSimpleCamera::SetFarZ(float farZ) { + this->m_farZ = farZ; +} + +void CSimpleCamera::SetFieldOfView(float fov) { + this->m_fov = fov; +} + +void CSimpleCamera::SetNearZ(float nearZ) { + this->m_nearZ = nearZ; +} + +C3Vector CSimpleCamera::Up() const { + return { this->m_facing.c0, this->m_facing.c1, this->m_facing.c2 }; +} diff --git a/src/ui/simple/CSimpleCamera.hpp b/src/ui/simple/CSimpleCamera.hpp new file mode 100644 index 0000000..5f8c943 --- /dev/null +++ b/src/ui/simple/CSimpleCamera.hpp @@ -0,0 +1,35 @@ +#ifndef UI_SIMPLE_C_SIMPLE_CAMERA_HPP +#define UI_SIMPLE_C_SIMPLE_CAMERA_HPP + +#include +#include + +class CSimpleCamera { + public: + // Virtual public member functions + virtual float FOV(); + virtual C3Vector Forward() const; + virtual C3Vector Right() const; + virtual C3Vector Up() const; + + // Public member functions + CSimpleCamera(float nearZ, float farZ, float fov); + void SetFacing(const C3Vector& forward); + void SetFacing(const C3Vector& forward, const C3Vector& up); + void SetFacing(float yaw, float pitch, float roll); + void SetFarZ(float farZ); + void SetFieldOfView(float fov); + void SetNearZ(float nearZ); + + protected: + // Protected member variables + C3Vector m_position; + float float10; + C33Matrix m_facing; + float m_nearZ; + float m_farZ; + float m_fov; + float m_aspect; +}; + +#endif From 0e6f65f32e98cc98b65b29fee430db0f7f40161c Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 15 Feb 2026 20:12:01 -0600 Subject: [PATCH 04/31] feat(ui): implement CSimpleCamera::SetFacing with forward vector --- src/ui/simple/CSimpleCamera.cpp | 53 ++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index db439c1..11f2ff5 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -1,4 +1,55 @@ #include "ui/simple/CSimpleCamera.hpp" +#include + +namespace { + +void FaceDirection(const C3Vector& direction, C3Vector& xPrime, C3Vector& yPrime, C3Vector& zPrime) { + STORM_ASSERT(CMath::fnotequal(direction.SquaredMag(), 0.0f)); + + // Forward + xPrime = direction; + + // Right + if (CMath::fequal(xPrime.SquaredMag(), 0.0f)) { + yPrime.x = 1.0f; + yPrime.y = 0.0f; + yPrime.z = 0.0f; + } else { + yPrime.x = -xPrime.y; + yPrime.y = xPrime.x; + yPrime.z = 0.0f; + + CMath::normalize(yPrime.x, yPrime.y); + } + + // Up (Forward cross Right) + zPrime = C3Vector::Cross(xPrime, yPrime); +} + +void BuildBillboardMatrix(const C3Vector& direction, C33Matrix& rotation) { + C3Vector xPrime = {}; + C3Vector yPrime = {}; + C3Vector zPrime = {}; + + FaceDirection(direction, xPrime, yPrime, zPrime); + + // Forward + rotation.a0 = xPrime.x; + rotation.a1 = xPrime.y; + rotation.a2 = xPrime.z; + + // Right + rotation.b0 = yPrime.x; + rotation.b1 = yPrime.y; + rotation.b2 = yPrime.z; + + // Up + rotation.c0 = zPrime.x; + rotation.c1 = zPrime.y; + rotation.c2 = zPrime.z; +} + +} CSimpleCamera::CSimpleCamera(float nearZ, float farZ, float fov) { this->float10 = 0.0f; @@ -24,7 +75,7 @@ C3Vector CSimpleCamera::Right() const { } void CSimpleCamera::SetFacing(const C3Vector& forward) { - // TODO + BuildBillboardMatrix(forward, this->m_facing); } void CSimpleCamera::SetFacing(const C3Vector& forward, const C3Vector& up) { From 2711c752ba3897f50c9b00e9365c561b7b9fc537 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 15 Feb 2026 20:28:56 -0600 Subject: [PATCH 05/31] chore(build): update typhoon --- lib/typhoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/typhoon b/lib/typhoon index a7733b6..dc8f10e 160000 --- a/lib/typhoon +++ b/lib/typhoon @@ -1 +1 @@ -Subproject commit a7733b6a8c2d52f081fbd74ca40d7ca8f94e1209 +Subproject commit dc8f10e407daa8bdf7e90d9438b55d5883780825 From 7d491570e486900cb8fbf752f4e4b58ca3fea74e Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 15 Feb 2026 21:02:06 -0600 Subject: [PATCH 06/31] feat(ui): add CSimpleCamera::GetScene --- src/ui/simple/CSimpleCamera.cpp | 11 ++++++++++- src/ui/simple/CSimpleCamera.hpp | 5 ++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index 11f2ff5..0164145 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -1,4 +1,5 @@ #include "ui/simple/CSimpleCamera.hpp" +#include "model/Model2.hpp" #include namespace { @@ -52,7 +53,7 @@ void BuildBillboardMatrix(const C3Vector& direction, C33Matrix& rotation) { } CSimpleCamera::CSimpleCamera(float nearZ, float farZ, float fov) { - this->float10 = 0.0f; + this->m_scene = nullptr; this->m_nearZ = nearZ; this->m_farZ = farZ; @@ -70,6 +71,14 @@ C3Vector CSimpleCamera::Forward() const { return { this->m_facing.a0, this->m_facing.a1, this->m_facing.a2 }; } +CM2Scene* CSimpleCamera::GetScene() { + if (!this->m_scene) { + this->m_scene = M2CreateScene(); + } + + return this->m_scene; +} + C3Vector CSimpleCamera::Right() const { return { this->m_facing.b0, this->m_facing.b1, this->m_facing.b2 }; } diff --git a/src/ui/simple/CSimpleCamera.hpp b/src/ui/simple/CSimpleCamera.hpp index 5f8c943..2f2fdda 100644 --- a/src/ui/simple/CSimpleCamera.hpp +++ b/src/ui/simple/CSimpleCamera.hpp @@ -4,6 +4,8 @@ #include #include +class CM2Scene; + class CSimpleCamera { public: // Virtual public member functions @@ -14,6 +16,7 @@ class CSimpleCamera { // Public member functions CSimpleCamera(float nearZ, float farZ, float fov); + CM2Scene* GetScene(); void SetFacing(const C3Vector& forward); void SetFacing(const C3Vector& forward, const C3Vector& up); void SetFacing(float yaw, float pitch, float roll); @@ -23,8 +26,8 @@ class CSimpleCamera { protected: // Protected member variables + CM2Scene* m_scene; C3Vector m_position; - float float10; C33Matrix m_facing; float m_nearZ; float m_farZ; From 4628b7d831b694d8fedf9673f0c58c5795a120bd Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 07:02:15 -0600 Subject: [PATCH 07/31] feat(ui): add CSimpleCamera::SetGxProjectionAndView --- src/ui/simple/CSimpleCamera.cpp | 20 ++++++++++++++++++++ src/ui/simple/CSimpleCamera.hpp | 2 ++ 2 files changed, 22 insertions(+) diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index 0164145..8a35c2f 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -1,4 +1,5 @@ #include "ui/simple/CSimpleCamera.hpp" +#include "gx/Transform.hpp" #include "model/Model2.hpp" #include @@ -107,6 +108,25 @@ void CSimpleCamera::SetNearZ(float nearZ) { this->m_nearZ = nearZ; } +void CSimpleCamera::SetGxProjectionAndView(const CRect& projRect) { + // Projection + + this->m_aspect = (projRect.maxX - projRect.minX) / (projRect.maxY - projRect.minY); + + C44Matrix projMat; + GxuXformCreateProjection_Exact(this->m_fov * 0.6f, this->m_aspect, this->m_nearZ, this->m_farZ, projMat); + + GxXformSetProjection(projMat); + + // View + + C3Vector eye; + C44Matrix viewMat; + GxuXformCreateLookAtSgCompat(eye, this->Forward(), this->Up(), viewMat); + + GxXformSetView(viewMat); +} + C3Vector CSimpleCamera::Up() const { return { this->m_facing.c0, this->m_facing.c1, this->m_facing.c2 }; } diff --git a/src/ui/simple/CSimpleCamera.hpp b/src/ui/simple/CSimpleCamera.hpp index 2f2fdda..e39cea6 100644 --- a/src/ui/simple/CSimpleCamera.hpp +++ b/src/ui/simple/CSimpleCamera.hpp @@ -2,6 +2,7 @@ #define UI_SIMPLE_C_SIMPLE_CAMERA_HPP #include +#include #include class CM2Scene; @@ -22,6 +23,7 @@ class CSimpleCamera { void SetFacing(float yaw, float pitch, float roll); void SetFarZ(float farZ); void SetFieldOfView(float fov); + void SetGxProjectionAndView(const CRect& projRect); void SetNearZ(float nearZ); protected: From 6bcaec1fe7dc47d156afe57903c85cd741ac0218 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 07:06:31 -0600 Subject: [PATCH 08/31] fix(ui): use FOV getter in CSimpleCamera::SetGxProjectionAndView --- src/ui/simple/CSimpleCamera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index 8a35c2f..e03757a 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -114,7 +114,7 @@ void CSimpleCamera::SetGxProjectionAndView(const CRect& projRect) { this->m_aspect = (projRect.maxX - projRect.minX) / (projRect.maxY - projRect.minY); C44Matrix projMat; - GxuXformCreateProjection_Exact(this->m_fov * 0.6f, this->m_aspect, this->m_nearZ, this->m_farZ, projMat); + GxuXformCreateProjection_Exact(this->FOV() * 0.6f, this->m_aspect, this->m_nearZ, this->m_farZ, projMat); GxXformSetProjection(projMat); From b3c07f06076755ba1de85b4b23e9dccc0ede24f8 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 07:15:14 -0600 Subject: [PATCH 09/31] fix(ui): const correctness for CSimpleCamera::FOV --- src/ui/simple/CSimpleCamera.cpp | 2 +- src/ui/simple/CSimpleCamera.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index e03757a..990c982 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -64,7 +64,7 @@ CSimpleCamera::CSimpleCamera(float nearZ, float farZ, float fov) { this->SetFacing(0.0f, 0.0f, 0.0f); } -float CSimpleCamera::FOV() { +float CSimpleCamera::FOV() const { return this->m_fov; } diff --git a/src/ui/simple/CSimpleCamera.hpp b/src/ui/simple/CSimpleCamera.hpp index e39cea6..407cdb6 100644 --- a/src/ui/simple/CSimpleCamera.hpp +++ b/src/ui/simple/CSimpleCamera.hpp @@ -10,7 +10,7 @@ class CM2Scene; class CSimpleCamera { public: // Virtual public member functions - virtual float FOV(); + virtual float FOV() const; virtual C3Vector Forward() const; virtual C3Vector Right() const; virtual C3Vector Up() const; From 50685c7cc04d2e231679a6aa76c2119eea48464e Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 12:43:01 -0600 Subject: [PATCH 10/31] chore(build): update typhoon --- lib/typhoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/typhoon b/lib/typhoon index dc8f10e..4ba7e0a 160000 --- a/lib/typhoon +++ b/lib/typhoon @@ -1 +1 @@ -Subproject commit dc8f10e407daa8bdf7e90d9438b55d5883780825 +Subproject commit 4ba7e0a6c3836254daf97bab159807fae6cab039 From 214534893577b2dfde907233c22f7d0d5e232ac4 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 12:43:28 -0600 Subject: [PATCH 11/31] feat(world): add CWorld::GetFarClip and CWorld::GetNearClip --- src/world/CWorld.cpp | 10 ++++++++++ src/world/CWorld.hpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/world/CWorld.cpp b/src/world/CWorld.cpp index 1027380..a49ceaf 100644 --- a/src/world/CWorld.cpp +++ b/src/world/CWorld.cpp @@ -10,9 +10,11 @@ uint32_t CWorld::s_curTimeMs; float CWorld::s_curTimeSec; uint32_t CWorld::s_enables; uint32_t CWorld::s_enables2; +float CWorld::s_farClip; uint32_t CWorld::s_gameTimeFixed; float CWorld::s_gameTimeSec; CM2Scene* CWorld::s_m2Scene; +float CWorld::s_nearClip = 0.1f; uint32_t CWorld::s_tickTimeFixed; uint32_t CWorld::s_tickTimeMs; float CWorld::s_tickTimeSec; @@ -55,6 +57,10 @@ float CWorld::GetCurTimeSec() { return CWorld::s_curTimeSec; } +float CWorld::GetFarClip() { + return CWorld::s_farClip; +} + uint32_t CWorld::GetFixedPrecisionTime(float timeSec) { return static_cast(timeSec * 1024.0f); } @@ -71,6 +77,10 @@ CM2Scene* CWorld::GetM2Scene() { return CWorld::s_m2Scene; } +float CWorld::GetNearClip() { + return CWorld::s_nearClip; +} + uint32_t CWorld::GetTickTimeFixed() { return CWorld::s_tickTimeFixed; } diff --git a/src/world/CWorld.hpp b/src/world/CWorld.hpp index 0ea3682..f181a0e 100644 --- a/src/world/CWorld.hpp +++ b/src/world/CWorld.hpp @@ -57,9 +57,11 @@ class CWorld { static HWORLDOBJECT AddObject(CM2Model* model, void* handler, void* handlerParam, uint64_t param64, uint32_t param32, uint32_t objFlags); static uint32_t GetCurTimeMs(); static float GetCurTimeSec(); + static float GetFarClip(); static uint32_t GetGameTimeFixed(); static float GetGameTimeSec(); static CM2Scene* GetM2Scene(); + static float GetNearClip(); static uint32_t GetTickTimeFixed(); static uint32_t GetTickTimeMs(); static float GetTickTimeSec(); @@ -72,9 +74,11 @@ class CWorld { // Private static variables static uint32_t s_curTimeMs; static float s_curTimeSec; + static float s_farClip; static uint32_t s_gameTimeFixed; static float s_gameTimeSec; static CM2Scene* s_m2Scene; + static float s_nearClip; static uint32_t s_tickTimeFixed; static uint32_t s_tickTimeMs; static float s_tickTimeSec; From 09c016c9359bcd1c594f5c290acd495193a4eb12 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 19:35:22 -0600 Subject: [PATCH 12/31] feat(world): set CMap::s_mapID in CMap::Load --- src/world/map/CMap.cpp | 7 ++++++- src/world/map/CMap.hpp | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/world/map/CMap.cpp b/src/world/map/CMap.cpp index f86ce96..9839f45 100644 --- a/src/world/map/CMap.cpp +++ b/src/world/map/CMap.cpp @@ -28,6 +28,7 @@ uint32_t* CMap::s_mapObjDefGroupHeap; uint32_t* CMap::s_mapObjDefHeap; uint32_t* CMap::s_mapObjGroupHeap; uint32_t* CMap::s_mapObjHeap; +int32_t CMap::s_mapID = -1; char CMap::s_mapName[256]; char CMap::s_mapPath[256]; char CMap::s_wdtFilename[256]; @@ -61,7 +62,7 @@ void CMap::Initialize() { // TODO } -void CMap::Load(const char* mapName, int32_t zoneID) { +void CMap::Load(const char* mapName, int32_t mapID) { // TODO auto nameOfs = SStrCopy(CMap::s_mapPath, "World\\Maps\\"); @@ -72,6 +73,10 @@ void CMap::Load(const char* mapName, int32_t zoneID) { SStrPrintf(CMap::s_wdtFilename, sizeof(CMap::s_wdtFilename), "%s\\%s.wdt", CMap::s_mapPath, CMap::s_mapName); // TODO + + CMap::s_mapID = mapID; + + // TODO } void CMap::MapMemInitialize() { diff --git a/src/world/map/CMap.hpp b/src/world/map/CMap.hpp index c70177b..372c6bb 100644 --- a/src/world/map/CMap.hpp +++ b/src/world/map/CMap.hpp @@ -23,6 +23,7 @@ class CMap { static uint32_t* s_mapObjDefHeap; static uint32_t* s_mapObjGroupHeap; static uint32_t* s_mapObjHeap; + static int32_t s_mapID; static char s_mapName[]; static char s_mapPath[]; static char s_wdtFilename[]; @@ -30,7 +31,7 @@ class CMap { // Static functions static CMapEntity* AllocEntity(int32_t a1); static void Initialize(); - static void Load(const char* mapName, int32_t zoneID); + static void Load(const char* mapName, int32_t mapID); static void MapMemInitialize(); }; From 703dc26df720a2969b024f20e45a16b63a891ccf Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 19:37:19 -0600 Subject: [PATCH 13/31] feat(world): implement CWorldParam::FarClipCallback --- src/world/CWorld.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/world/CWorld.hpp | 2 ++ src/world/CWorldParam.cpp | 4 +++- src/world/CWorldParam.hpp | 2 +- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/world/CWorld.cpp b/src/world/CWorld.cpp index a49ceaf..bb8726a 100644 --- a/src/world/CWorld.cpp +++ b/src/world/CWorld.cpp @@ -2,6 +2,7 @@ #include "gx/Gx.hpp" #include "gx/Shader.hpp" #include "model/Model2.hpp" +#include "world/CWorldParam.hpp" #include "world/Map.hpp" #include "world/Weather.hpp" #include @@ -15,11 +16,31 @@ uint32_t CWorld::s_gameTimeFixed; float CWorld::s_gameTimeSec; CM2Scene* CWorld::s_m2Scene; float CWorld::s_nearClip = 0.1f; +float CWorld::s_prevFarClip; uint32_t CWorld::s_tickTimeFixed; uint32_t CWorld::s_tickTimeMs; float CWorld::s_tickTimeSec; Weather* CWorld::s_weather; +namespace { + +float AdjustFarClip(float farClip, int32_t mapID) { + float minFarClip = 183.33333f; + float maxFarClip = 1583.3334f; + + if (mapID < 530 || mapID == 575 || mapID == 543) { + if (!CWorldParam::cvar_farClipOverride || CWorldParam::cvar_farClipOverride->GetInt() < 1) { + maxFarClip = 791.66669f; + } + } else if (false /* TODO OsGetPhysicalMemory() <= 1073741824 */) { + maxFarClip = 791.66669f; + } + + return std::min(std::max(farClip, minFarClip), maxFarClip); +} + +} + HWORLDOBJECT CWorld::AddObject(CM2Model* model, void* handler, void* handlerParam, uint64_t param64, uint32_t param32, uint32_t objFlags) { auto entity = CMap::AllocEntity(objFlags & 0x8 ? true : false); @@ -157,6 +178,24 @@ int32_t CWorld::OnTick(const EVENT_DATA_TICK* data, void* param) { return 1; } +void CWorld::SetFarClip(float farClip) { + farClip = AdjustFarClip(farClip, CMap::s_mapID); + + if (CWorld::s_farClip == farClip) { + return; + } + + CWorld::s_prevFarClip = CWorld::s_farClip; + CWorld::s_farClip = farClip; + + // TODO CMapRenderChunk::DirtyPools(); + + CWorld::s_nearClip = 0.2f; + + // TODO dword_D1C410 = 1; + // TODO dword_ADEEE0 = 1; +} + void CWorld::SetUpdateTime(float tickTimeSec, uint32_t curTimeMs) { auto tickTimeFixed = CWorld::GetFixedPrecisionTime(tickTimeSec); diff --git a/src/world/CWorld.hpp b/src/world/CWorld.hpp index f181a0e..94a3cdd 100644 --- a/src/world/CWorld.hpp +++ b/src/world/CWorld.hpp @@ -68,6 +68,7 @@ class CWorld { static void Initialize(); static void LoadMap(const char* mapName, const C3Vector& position, int32_t zoneID); static int32_t OnTick(const EVENT_DATA_TICK* data, void* param); + static void SetFarClip(float farClip); static void SetUpdateTime(float tickTimeSec, uint32_t curTimeMs); private: @@ -79,6 +80,7 @@ class CWorld { static float s_gameTimeSec; static CM2Scene* s_m2Scene; static float s_nearClip; + static float s_prevFarClip; static uint32_t s_tickTimeFixed; static uint32_t s_tickTimeMs; static float s_tickTimeSec; diff --git a/src/world/CWorldParam.cpp b/src/world/CWorldParam.cpp index 4b5d68a..6d4dda4 100644 --- a/src/world/CWorldParam.cpp +++ b/src/world/CWorldParam.cpp @@ -1,4 +1,5 @@ #include "world/CWorldParam.hpp" +#include "world/CWorld.hpp" #include "console/CVar.hpp" CVar* CWorldParam::cvar_baseMip; @@ -53,7 +54,8 @@ bool CWorldParam::ExtShadowQualityCallback(CVar* var, const char* oldValue, cons } bool CWorldParam::FarClipCallback(CVar* var, const char* oldValue, const char* value, void* arg) { - // TODO + CWorld::SetFarClip(SStrToFloat(value)); + return true; } diff --git a/src/world/CWorldParam.hpp b/src/world/CWorldParam.hpp index 6e94460..a078072 100644 --- a/src/world/CWorldParam.hpp +++ b/src/world/CWorldParam.hpp @@ -1,7 +1,7 @@ #ifndef WORLD_C_WORLD_PARAM_HPP #define WORLD_C_WORLD_PARAM_HPP -class CVar; +#include "console/CVar.hpp" class CWorldParam { public: From f8f00b599e93938d0d051ab93208b9f5fc7faf79 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 17 Feb 2026 21:46:18 -0600 Subject: [PATCH 14/31] feat(world): set near clip and far clip in CWorld::LoadMap --- src/world/CWorld.cpp | 8 ++++++-- src/world/CWorld.hpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/world/CWorld.cpp b/src/world/CWorld.cpp index bb8726a..8a14a42 100644 --- a/src/world/CWorld.cpp +++ b/src/world/CWorld.cpp @@ -164,10 +164,14 @@ void CWorld::Initialize() { // TODO } -void CWorld::LoadMap(const char* mapName, const C3Vector& position, int32_t zoneID) { +void CWorld::LoadMap(const char* mapName, const C3Vector& position, int32_t mapID) { + CWorld::s_farClip = AdjustFarClip(CWorldParam::cvar_farClip->GetFloat(), mapID); + CWorld::s_nearClip = 0.2f; + CWorld::s_prevFarClip = CWorld::s_farClip; + // TODO - CMap::Load(mapName, zoneID); + CMap::Load(mapName, mapID); // TODO } diff --git a/src/world/CWorld.hpp b/src/world/CWorld.hpp index 94a3cdd..124e370 100644 --- a/src/world/CWorld.hpp +++ b/src/world/CWorld.hpp @@ -66,7 +66,7 @@ class CWorld { static uint32_t GetTickTimeMs(); static float GetTickTimeSec(); static void Initialize(); - static void LoadMap(const char* mapName, const C3Vector& position, int32_t zoneID); + static void LoadMap(const char* mapName, const C3Vector& position, int32_t mapID); static int32_t OnTick(const EVENT_DATA_TICK* data, void* param); static void SetFarClip(float farClip); static void SetUpdateTime(float tickTimeSec, uint32_t curTimeMs); From 8c518f7e6dcb0a80efcbb0fd8e9adef60eac4a0e Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 06:14:31 -0600 Subject: [PATCH 15/31] feat(gx): add EGxBuffer --- src/gx/Types.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gx/Types.hpp b/src/gx/Types.hpp index 9ceaf2d..481e112 100644 --- a/src/gx/Types.hpp +++ b/src/gx/Types.hpp @@ -54,6 +54,12 @@ enum EGxBlend { GxBlends_Last = 12 }; +enum EGxBuffer { + GxBuffers_Color = 0, + GxBuffers_Depth = 1, + GxBuffers_Last, +}; + enum EGxColorFormat { GxCF_argb = 0, GxCF_rgba = 1, From 4782c554fc3b6c988442d265c4f9b9111d3f584e Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 06:15:53 -0600 Subject: [PATCH 16/31] feat(gx): add CGxDevice::TextureTarget --- src/gx/CGxDevice.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gx/CGxDevice.hpp b/src/gx/CGxDevice.hpp index de72727..b4c719d 100644 --- a/src/gx/CGxDevice.hpp +++ b/src/gx/CGxDevice.hpp @@ -38,6 +38,13 @@ struct ShaderConstants { class CGxDevice { public: + // Structs + struct TextureTarget { + CGxTex* m_texture; + uint32_t m_plane; + void* m_apiSpecific; + }; + // Static variables static uint32_t s_alphaRef[]; static C3Vector s_pointScaleIdentity; From 619bcca7781251d163bfb90c965223e5032470dc Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 06:19:28 -0600 Subject: [PATCH 17/31] feat(gx): add CGxDevice::m_textureTarget --- src/gx/CGxDevice.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gx/CGxDevice.hpp b/src/gx/CGxDevice.hpp index b4c719d..250be28 100644 --- a/src/gx/CGxDevice.hpp +++ b/src/gx/CGxDevice.hpp @@ -123,6 +123,9 @@ class CGxDevice { int32_t m_primIndexDirty = 0; TSFixedArray m_appRenderStates; TSFixedArray m_hwRenderStates; + // TODO + TextureTarget m_textureTarget[GxBuffers_Last]; + // TODO uint32_t m_baseMipLevel = 0; // TODO placeholder // Virtual member functions From a51e9ba0828fb05285f43c538f85210e5a54565c Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 08:24:53 -0600 Subject: [PATCH 18/31] feat(gx): add missing initializers to CGxDevice --- src/gx/CGxDevice.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gx/CGxDevice.hpp b/src/gx/CGxDevice.hpp index 250be28..0c7ed1e 100644 --- a/src/gx/CGxDevice.hpp +++ b/src/gx/CGxDevice.hpp @@ -108,12 +108,12 @@ class CGxDevice { uint32_t m_appMasterEnables = 0; uint32_t m_hwMasterEnables = 0; TSList> m_poolList; - CGxBuf* m_bufLocked[GxPoolTargets_Last]; + CGxBuf* m_bufLocked[GxPoolTargets_Last] = {}; CGxPool* m_vertexPool = nullptr; CGxPool* m_indexPool = nullptr; - CGxBuf* m_streamBufs[GxPoolTargets_Last]; + CGxBuf* m_streamBufs[GxPoolTargets_Last] = {}; CGxVertexAttrib m_primVertexFormatAttrib[GxVertexBufferFormats_Last]; - CGxBuf* m_primVertexFormatBuf[GxVertexBufferFormats_Last]; + CGxBuf* m_primVertexFormatBuf[GxVertexBufferFormats_Last] = {}; uint32_t m_primVertexMask = 0; uint32_t m_primVertexDirty = 0; EGxVertexBufferFormat m_primVertexFormat = GxVertexBufferFormats_Last; @@ -124,7 +124,7 @@ class CGxDevice { TSFixedArray m_appRenderStates; TSFixedArray m_hwRenderStates; // TODO - TextureTarget m_textureTarget[GxBuffers_Last]; + TextureTarget m_textureTarget[GxBuffers_Last] = {}; // TODO uint32_t m_baseMipLevel = 0; // TODO placeholder From e7bd5968cf4003df446c4090428ac35930731f68 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 08:43:11 -0600 Subject: [PATCH 19/31] feat(gx): add GxRenderTargetGet --- src/gx/CGxDevice.cpp | 4 ++++ src/gx/CGxDevice.hpp | 1 + src/gx/RenderTarget.cpp | 6 ++++++ src/gx/RenderTarget.hpp | 10 ++++++++++ 4 files changed, 21 insertions(+) create mode 100644 src/gx/RenderTarget.cpp create mode 100644 src/gx/RenderTarget.hpp diff --git a/src/gx/CGxDevice.cpp b/src/gx/CGxDevice.cpp index 880a107..b3eac61 100644 --- a/src/gx/CGxDevice.cpp +++ b/src/gx/CGxDevice.cpp @@ -924,6 +924,10 @@ CGxPool* CGxDevice::PoolCreate(EGxPoolTarget target, EGxPoolUsage usage, uint32_ return pool; } +void CGxDevice::RenderTargetGet(EGxBuffer buffer, CGxTex*& gxTex) { + gxTex = this->m_textureTarget[buffer].m_texture; +} + void CGxDevice::RsGet(EGxRenderState which, int32_t& value) { value = static_cast(this->m_appRenderStates[which].m_value); } diff --git a/src/gx/CGxDevice.hpp b/src/gx/CGxDevice.hpp index 0c7ed1e..edf9f99 100644 --- a/src/gx/CGxDevice.hpp +++ b/src/gx/CGxDevice.hpp @@ -183,6 +183,7 @@ class CGxDevice { void PrimVertexFormat(CGxBuf*, CGxVertexAttrib*, uint32_t); void PrimVertexMask(uint32_t); void PrimVertexPtr(CGxBuf*, EGxVertexBufferFormat); + void RenderTargetGet(EGxBuffer buffer, CGxTex*& gxTex); void RsGet(EGxRenderState, int32_t&); void RsSet(EGxRenderState, int32_t); void RsSet(EGxRenderState, void*); diff --git a/src/gx/RenderTarget.cpp b/src/gx/RenderTarget.cpp new file mode 100644 index 0000000..d847708 --- /dev/null +++ b/src/gx/RenderTarget.cpp @@ -0,0 +1,6 @@ +#include "gx/RenderTarget.hpp" +#include "gx/Device.hpp" + +void GxRenderTargetGet(EGxBuffer buffer, CGxTex*& gxTex) { + g_theGxDevicePtr->RenderTargetGet(buffer, gxTex); +} diff --git a/src/gx/RenderTarget.hpp b/src/gx/RenderTarget.hpp new file mode 100644 index 0000000..c95cad2 --- /dev/null +++ b/src/gx/RenderTarget.hpp @@ -0,0 +1,10 @@ +#ifndef GX_RENDER_TARGET_HPP +#define GX_RENDER_TARGET_HPP + +#include "gx/Types.hpp" + +class CGxTex; + +void GxRenderTargetGet(EGxBuffer buffer, CGxTex*& gxTex); + +#endif From c6e18336de336c573868b30d6a05b59d9efd9492 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 16:28:19 -0600 Subject: [PATCH 20/31] chore(build): update typhoon --- lib/typhoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/typhoon b/lib/typhoon index 4ba7e0a..1f8bf13 160000 --- a/lib/typhoon +++ b/lib/typhoon @@ -1 +1 @@ -Subproject commit 4ba7e0a6c3836254daf97bab159807fae6cab039 +Subproject commit 1f8bf1370dc1cf13da5965be99803633d82a524f From 7682dba2c91198acf4f56525d317366be182d938 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 17:00:56 -0600 Subject: [PATCH 21/31] feat(ui): add CGCamera --- lib/typhoon | 2 +- src/ui/game/CGCamera.cpp | 97 +++++++++++++++++++++++++++++++++ src/ui/game/CGCamera.hpp | 48 ++++++++++++++++ src/ui/game/CGGameUI.cpp | 5 ++ src/ui/game/Types.hpp | 12 ++++ src/ui/simple/CSimpleCamera.cpp | 12 ++-- src/ui/simple/CSimpleCamera.hpp | 1 + 7 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 src/ui/game/CGCamera.cpp create mode 100644 src/ui/game/CGCamera.hpp diff --git a/lib/typhoon b/lib/typhoon index 1f8bf13..1e5366b 160000 --- a/lib/typhoon +++ b/lib/typhoon @@ -1 +1 @@ -Subproject commit 1f8bf1370dc1cf13da5965be99803633d82a524f +Subproject commit 1e5366bbc6935e3363abf5921f0be12f902e790a diff --git a/src/ui/game/CGCamera.cpp b/src/ui/game/CGCamera.cpp new file mode 100644 index 0000000..f278f6e --- /dev/null +++ b/src/ui/game/CGCamera.cpp @@ -0,0 +1,97 @@ +#include "ui/game/CGCamera.hpp" +#include "ui/game/Types.hpp" +#include "console/CVar.hpp" +#include "world/World.hpp" +#include +#include +#include + +static CVar* s_cameraView; + +CGCamera::CameraViewData CGCamera::s_cameraViewDataDefault[MAX_CAMERA_VIEWS] = { + { "0.0", "0.0", "0.0" }, // VIEW_FIRST_PERSON + { "0.0", "0.0", "0.0" }, // VIEW_THIRD_PERSON_A + { "5.55", "10.0", "0.0" }, // VIEW_THIRD_PERSON_B + { "5.55", "20.0", "0.0" }, // VIEW_THIRD_PERSON_C + { "13.88", "30.0", "0.0" }, // VIEW_THIRD_PERSON_D + { "13.88", "10.0", "0.0" }, // VIEW_THIRD_PERSON_E + { "0.0", "0.0", "0.0" }, // VIEW_COMMENTATOR + { "5.0", "10.0", "0.0" }, // VIEW_BARBER_SHOP +}; + +namespace { + +bool ValidateCameraView(CVar* var, const char* oldValue, const char* value, void* arg) { + auto view = SStrToFloat(value); + auto min = static_cast(VIEW_FIRST_PERSON); + auto max = static_cast(VIEW_BARBER_SHOP); + + if (view >= min && view <= max) { + return true; + } + + // TODO ConsoleWriteA("Value out of range (%f - %f)\n", DEFAULT_COLOR, min, max); + + return false; +} + +} + +CGCamera::CGCamera() : CSimpleCamera(CWorld::GetNearClip(), CWorld::GetFarClip(), 90.0f * CMath::DEG2RAD) { + this->m_relativeTo = 0; + + this->m_view = s_cameraView->GetInt(); + + this->m_distance = SStrToFloat(CGCamera::s_cameraViewDataDefault[this->m_view].m_distance); + this->m_yaw = 0.0f; + this->m_pitch = SStrToFloat(CGCamera::s_cameraViewDataDefault[this->m_view].m_pitch); + this->m_roll = 0.0f; + + this->m_fovOffset = 0.0f; +} + +float CGCamera::FOV() const { + // Clamp offset-adjusted FOV between 0pi and 1pi + return std::min(std::max(this->m_fov + this->m_fovOffset, 0.0f), CMath::PI); +} + +C3Vector CGCamera::Forward() const { + if (this->m_relativeTo) { + return this->CSimpleCamera::Forward() * this->ParentToWorld(); + } + + return this->CSimpleCamera::Forward(); +} + +C33Matrix CGCamera::ParentToWorld() const { + // TODO + return {}; +} + +C3Vector CGCamera::Right() const { + if (this->m_relativeTo) { + return this->CSimpleCamera::Right() * this->ParentToWorld(); + } + + return this->CSimpleCamera::Right(); +} + +void CGCamera::SetupWorldProjection(const CRect& projRect) { + this->SetGxProjectionAndView(projRect); +} + +C3Vector CGCamera::Up() const { + if (this->m_relativeTo) { + return this->CSimpleCamera::Up() * this->ParentToWorld(); + } + + return this->CSimpleCamera::Up(); +} + +void CameraRegisterCVars() { + // TODO + + s_cameraView = CVar::Register("cameraView", nullptr, 0x10, "2", &ValidateCameraView, DEFAULT); + + // TODO +} diff --git a/src/ui/game/CGCamera.hpp b/src/ui/game/CGCamera.hpp new file mode 100644 index 0000000..b0aafb7 --- /dev/null +++ b/src/ui/game/CGCamera.hpp @@ -0,0 +1,48 @@ +#ifndef UI_GAME_C_G_CAMERA_HPP +#define UI_GAME_C_G_CAMERA_HPP + +#include "ui/simple/CSimpleCamera.hpp" +#include "util/GUID.hpp" + +class CGCamera : public CSimpleCamera { + public: + // Public structs + struct CameraViewData { + const char* m_distance; + const char* m_pitch; + const char* m_yaw; + }; + + // Public static variables + static CameraViewData s_cameraViewDataDefault[]; + + // Virtual public member functions + virtual ~CGCamera() = default; + virtual float FOV() const; + virtual C3Vector Forward() const; + virtual C3Vector Right() const; + virtual C3Vector Up() const; + + // Public member functions + CGCamera(); + C33Matrix ParentToWorld() const; + void SetupWorldProjection(const CRect& projRect); + + private: + // Private member variables + // TODO + WOWGUID m_relativeTo; + // TODO + int32_t m_view; + // TODO + float m_distance; + float m_yaw; + float m_pitch; + float m_roll; + // TODO + float m_fovOffset; +}; + +void CameraRegisterCVars(); + +#endif diff --git a/src/ui/game/CGGameUI.cpp b/src/ui/game/CGGameUI.cpp index a92b41f..791b850 100644 --- a/src/ui/game/CGGameUI.cpp +++ b/src/ui/game/CGGameUI.cpp @@ -8,6 +8,7 @@ #include "ui/game/ActionBarScript.hpp" #include "ui/game/BattlefieldInfoScript.hpp" #include "ui/game/BattlenetUI.hpp" +#include "ui/game/CGCamera.hpp" #include "ui/game/CGCharacterModelBase.hpp" #include "ui/game/CGCooldown.hpp" #include "ui/game/CGDressUpModelFrame.hpp" @@ -284,4 +285,8 @@ void CGGameUI::RegisterGameCVars() { CVar::Register("fullSizeFocusFrame", "Increases the size of the focus frame to that of the target frame", 0x20, "0", nullptr, GAME); // TODO + + CameraRegisterCVars(); + + // TODO } diff --git a/src/ui/game/Types.hpp b/src/ui/game/Types.hpp index a54dce4..78d1696 100644 --- a/src/ui/game/Types.hpp +++ b/src/ui/game/Types.hpp @@ -13,4 +13,16 @@ enum SCRIPTEVENT { // TODO }; +enum CAMERA_VIEW { + VIEW_FIRST_PERSON = 0, + VIEW_THIRD_PERSON_A = 1, + VIEW_THIRD_PERSON_B = 2, + VIEW_THIRD_PERSON_C = 3, + VIEW_THIRD_PERSON_D = 4, + VIEW_THIRD_PERSON_E = 5, + VIEW_COMMENTATOR = 6, + VIEW_BARBER_SHOP = 7, + MAX_CAMERA_VIEWS, +}; + #endif diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index 990c982..15a0dc6 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -104,10 +104,6 @@ void CSimpleCamera::SetFieldOfView(float fov) { this->m_fov = fov; } -void CSimpleCamera::SetNearZ(float nearZ) { - this->m_nearZ = nearZ; -} - void CSimpleCamera::SetGxProjectionAndView(const CRect& projRect) { // Projection @@ -127,6 +123,14 @@ void CSimpleCamera::SetGxProjectionAndView(const CRect& projRect) { GxXformSetView(viewMat); } +void CSimpleCamera::SetNearZ(float nearZ) { + this->m_nearZ = nearZ; +} + +void CSimpleCamera::SetScreenAspect(const CRect& screenRect) { + this->m_aspect = (screenRect.maxX - screenRect.minX) / (screenRect.maxY - screenRect.minY); +} + C3Vector CSimpleCamera::Up() const { return { this->m_facing.c0, this->m_facing.c1, this->m_facing.c2 }; } diff --git a/src/ui/simple/CSimpleCamera.hpp b/src/ui/simple/CSimpleCamera.hpp index 407cdb6..3387a35 100644 --- a/src/ui/simple/CSimpleCamera.hpp +++ b/src/ui/simple/CSimpleCamera.hpp @@ -25,6 +25,7 @@ class CSimpleCamera { void SetFieldOfView(float fov); void SetGxProjectionAndView(const CRect& projRect); void SetNearZ(float nearZ); + void SetScreenAspect(const CRect& screenRect); protected: // Protected member variables From e5cc9de4866e6d96a8395a8a0d3d5c9e7a6cd223 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Wed, 18 Feb 2026 19:34:52 -0600 Subject: [PATCH 22/31] feat(ui): add CGWorldFrame::OnFrameSizeChanged --- src/ui/game/CGWorldFrame.cpp | 29 +++++++++++++++++++++++++++++ src/ui/game/CGWorldFrame.hpp | 13 +++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/ui/game/CGWorldFrame.cpp b/src/ui/game/CGWorldFrame.cpp index 3446f1b..fab12fd 100644 --- a/src/ui/game/CGWorldFrame.cpp +++ b/src/ui/game/CGWorldFrame.cpp @@ -1,6 +1,8 @@ #include "ui/game/CGWorldFrame.hpp" +#include "gx/Coordinate.hpp" #include "gx/Shader.hpp" #include "gx/Transform.hpp" +#include "ui/game/CGCamera.hpp" #include "ui/game/PlayerName.hpp" #include #include @@ -46,6 +48,10 @@ CGWorldFrame::CGWorldFrame(CSimpleFrame* parent) : CSimpleFrame(parent) { this->EnableEvent(SIMPLE_EVENT_MOUSEWHEEL, -1); // TODO + + this->m_camera = STORM_NEW(CGCamera); + + // TODO } void CGWorldFrame::OnFrameRender(CRenderBatch* batch, uint32_t layer) { @@ -56,6 +62,29 @@ void CGWorldFrame::OnFrameRender(CRenderBatch* batch, uint32_t layer) { } } +void CGWorldFrame::OnFrameSizeChanged(const CRect& rect) { + this->CSimpleFrame::OnFrameSizeChanged(rect); + + // Screen rect (DDC) + this->m_screenRect.minX = std::max(this->m_rect.minX, 0.0f); + this->m_screenRect.minY = std::max(this->m_rect.minY, 0.0f); + this->m_screenRect.maxX = std::min(this->m_rect.maxX, NDCToDDCWidth(1.0f)); + this->m_screenRect.maxY = std::min(this->m_rect.maxY, NDCToDDCHeight(1.0f)); + + // Camera aspect ratio + if (this->m_camera) { + this->m_camera->SetScreenAspect(this->m_screenRect); + } + + // Viewport (NDC) + DDCToNDC(this->m_rect.minX, this->m_rect.minY, &this->m_viewport.minX, &this->m_viewport.minY); + DDCToNDC(this->m_rect.maxX, this->m_rect.maxY, &this->m_viewport.maxX, &this->m_viewport.maxY); + this->m_viewport.minX = std::max(this->m_viewport.minX, 0.0f); + this->m_viewport.minY = std::max(this->m_viewport.minY, 0.0f); + this->m_viewport.maxX = std::min(this->m_viewport.maxX, 1.0f); + this->m_viewport.maxY = std::min(this->m_viewport.maxY, 1.0f); +} + void CGWorldFrame::OnWorldRender() { // TODO } diff --git a/src/ui/game/CGWorldFrame.hpp b/src/ui/game/CGWorldFrame.hpp index 6cec83a..169940c 100644 --- a/src/ui/game/CGWorldFrame.hpp +++ b/src/ui/game/CGWorldFrame.hpp @@ -4,6 +4,8 @@ #include "ui/simple/CSimpleFrame.hpp" #include +class CGCamera; + class CGWorldFrame : public CSimpleFrame { public: // Static variables @@ -15,11 +17,22 @@ class CGWorldFrame : public CSimpleFrame { // Virtual member functions virtual void OnFrameRender(CRenderBatch* batch, uint32_t layer); + // TODO + virtual void OnFrameSizeChanged(const CRect& rect); // Member functions CGWorldFrame(CSimpleFrame* parent); void OnWorldRender(); void OnWorldUpdate(); + + private: + // Private member variables + // TODO + CRect m_screenRect; + CRect m_viewport; + // TODO + CGCamera* m_camera; + // TODO }; #endif From 06186d12515b3140803e66f0192e25bd2b1c98c6 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Thu, 19 Feb 2026 06:56:43 -0600 Subject: [PATCH 23/31] feat(ui): call CGCamera::SetupWorldProjection from CGWorldFrame::OnWorldUpdate --- src/ui/game/CGWorldFrame.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/game/CGWorldFrame.cpp b/src/ui/game/CGWorldFrame.cpp index fab12fd..1b0c823 100644 --- a/src/ui/game/CGWorldFrame.cpp +++ b/src/ui/game/CGWorldFrame.cpp @@ -91,4 +91,8 @@ void CGWorldFrame::OnWorldRender() { void CGWorldFrame::OnWorldUpdate() { // TODO + + this->m_camera->SetupWorldProjection(this->m_screenRect); + + // TODO } From 6675586a2900fd814de087d166f7f0ff0de0d100 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 21 Feb 2026 14:07:33 -0600 Subject: [PATCH 24/31] feat(ui): add CSimpleCamera::Position --- src/ui/simple/CSimpleCamera.cpp | 4 ++++ src/ui/simple/CSimpleCamera.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/ui/simple/CSimpleCamera.cpp b/src/ui/simple/CSimpleCamera.cpp index 15a0dc6..a4e67c2 100644 --- a/src/ui/simple/CSimpleCamera.cpp +++ b/src/ui/simple/CSimpleCamera.cpp @@ -84,6 +84,10 @@ C3Vector CSimpleCamera::Right() const { return { this->m_facing.b0, this->m_facing.b1, this->m_facing.b2 }; } +const C3Vector& CSimpleCamera::Position() const { + return this->m_position; +} + void CSimpleCamera::SetFacing(const C3Vector& forward) { BuildBillboardMatrix(forward, this->m_facing); } diff --git a/src/ui/simple/CSimpleCamera.hpp b/src/ui/simple/CSimpleCamera.hpp index 3387a35..e5a166d 100644 --- a/src/ui/simple/CSimpleCamera.hpp +++ b/src/ui/simple/CSimpleCamera.hpp @@ -18,6 +18,7 @@ class CSimpleCamera { // Public member functions CSimpleCamera(float nearZ, float farZ, float fov); CM2Scene* GetScene(); + const C3Vector& Position() const; void SetFacing(const C3Vector& forward); void SetFacing(const C3Vector& forward, const C3Vector& up); void SetFacing(float yaw, float pitch, float roll); From 817cec99feebb0b6e7e629e7fd92a0d54173e60f Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 21 Feb 2026 14:11:22 -0600 Subject: [PATCH 25/31] feat(ui): add CGCamera::Target --- src/ui/game/CGCamera.cpp | 4 ++++ src/ui/game/CGCamera.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/ui/game/CGCamera.cpp b/src/ui/game/CGCamera.cpp index f278f6e..bb9a454 100644 --- a/src/ui/game/CGCamera.cpp +++ b/src/ui/game/CGCamera.cpp @@ -80,6 +80,10 @@ void CGCamera::SetupWorldProjection(const CRect& projRect) { this->SetGxProjectionAndView(projRect); } +C3Vector CGCamera::Target() const { + return this->m_position + this->Forward(); +} + C3Vector CGCamera::Up() const { if (this->m_relativeTo) { return this->CSimpleCamera::Up() * this->ParentToWorld(); diff --git a/src/ui/game/CGCamera.hpp b/src/ui/game/CGCamera.hpp index b0aafb7..a23d789 100644 --- a/src/ui/game/CGCamera.hpp +++ b/src/ui/game/CGCamera.hpp @@ -27,6 +27,7 @@ class CGCamera : public CSimpleCamera { CGCamera(); C33Matrix ParentToWorld() const; void SetupWorldProjection(const CRect& projRect); + C3Vector Target() const; private: // Private member variables From 58c897576981e6c03448ae3d5731c374b5da0d21 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 21 Feb 2026 21:15:01 -0600 Subject: [PATCH 26/31] feat(ui): add CGCamera::GetTarget --- src/ui/game/CGCamera.cpp | 4 ++++ src/ui/game/CGCamera.hpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/ui/game/CGCamera.cpp b/src/ui/game/CGCamera.cpp index bb9a454..1fd1098 100644 --- a/src/ui/game/CGCamera.cpp +++ b/src/ui/game/CGCamera.cpp @@ -63,6 +63,10 @@ C3Vector CGCamera::Forward() const { return this->CSimpleCamera::Forward(); } +const WOWGUID& CGCamera::GetTarget() const { + return this->m_target; +} + C33Matrix CGCamera::ParentToWorld() const { // TODO return {}; diff --git a/src/ui/game/CGCamera.hpp b/src/ui/game/CGCamera.hpp index a23d789..13d18ad 100644 --- a/src/ui/game/CGCamera.hpp +++ b/src/ui/game/CGCamera.hpp @@ -25,6 +25,7 @@ class CGCamera : public CSimpleCamera { // Public member functions CGCamera(); + const WOWGUID& GetTarget() const; C33Matrix ParentToWorld() const; void SetupWorldProjection(const CRect& projRect); C3Vector Target() const; @@ -32,6 +33,8 @@ class CGCamera : public CSimpleCamera { private: // Private member variables // TODO + WOWGUID m_target; + // TODO WOWGUID m_relativeTo; // TODO int32_t m_view; From cb8291af1acd3c01ceb53ecce5b9e6b2435cf2d8 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 21 Feb 2026 21:41:08 -0600 Subject: [PATCH 27/31] feat(ui): add CGCamera::HasModel --- src/ui/game/CGCamera.cpp | 7 +++++++ src/ui/game/CGCamera.hpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/ui/game/CGCamera.cpp b/src/ui/game/CGCamera.cpp index 1fd1098..60b736c 100644 --- a/src/ui/game/CGCamera.cpp +++ b/src/ui/game/CGCamera.cpp @@ -38,6 +38,9 @@ bool ValidateCameraView(CVar* var, const char* oldValue, const char* value, void } CGCamera::CGCamera() : CSimpleCamera(CWorld::GetNearClip(), CWorld::GetFarClip(), 90.0f * CMath::DEG2RAD) { + this->m_model = nullptr; + + this->m_target = 0; this->m_relativeTo = 0; this->m_view = s_cameraView->GetInt(); @@ -67,6 +70,10 @@ const WOWGUID& CGCamera::GetTarget() const { return this->m_target; } +int32_t CGCamera::HasModel() const { + return this->m_model != nullptr; +} + C33Matrix CGCamera::ParentToWorld() const { // TODO return {}; diff --git a/src/ui/game/CGCamera.hpp b/src/ui/game/CGCamera.hpp index 13d18ad..5a3a5b2 100644 --- a/src/ui/game/CGCamera.hpp +++ b/src/ui/game/CGCamera.hpp @@ -4,6 +4,8 @@ #include "ui/simple/CSimpleCamera.hpp" #include "util/GUID.hpp" +class CM2Model; + class CGCamera : public CSimpleCamera { public: // Public structs @@ -26,12 +28,14 @@ class CGCamera : public CSimpleCamera { // Public member functions CGCamera(); const WOWGUID& GetTarget() const; + int32_t HasModel() const; C33Matrix ParentToWorld() const; void SetupWorldProjection(const CRect& projRect); C3Vector Target() const; private: // Private member variables + CM2Model* m_model; // TODO WOWGUID m_target; // TODO From 6cb53104301aa9ec1da80689f2d12c26f7aa5ecf Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 21 Feb 2026 21:41:37 -0600 Subject: [PATCH 28/31] feat(object): add CGObject_C::GetPosition --- src/object/client/CGObject_C.cpp | 4 ++++ src/object/client/CGObject_C.hpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/object/client/CGObject_C.cpp b/src/object/client/CGObject_C.cpp index e9cd9a2..f8b1451 100644 --- a/src/object/client/CGObject_C.cpp +++ b/src/object/client/CGObject_C.cpp @@ -103,6 +103,10 @@ CM2Model* CGObject_C::GetObjectModel() { return this->m_model; } +C3Vector CGObject_C::GetPosition() const { + return { 0.0f, 0.0f, 0.0f }; +} + int32_t CGObject_C::IsInReenable() { return this->m_inReenable; } diff --git a/src/object/client/CGObject_C.hpp b/src/object/client/CGObject_C.hpp index fdb5813..788bbb5 100644 --- a/src/object/client/CGObject_C.hpp +++ b/src/object/client/CGObject_C.hpp @@ -36,6 +36,8 @@ class CGObject_C : public CGObject, public TSHashObject Date: Sat, 21 Feb 2026 21:42:02 -0600 Subject: [PATCH 29/31] feat(world): stub CWorld::Update --- src/world/CWorld.cpp | 4 ++++ src/world/CWorld.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/world/CWorld.cpp b/src/world/CWorld.cpp index 8a14a42..1ebc1c1 100644 --- a/src/world/CWorld.cpp +++ b/src/world/CWorld.cpp @@ -213,3 +213,7 @@ void CWorld::SetUpdateTime(float tickTimeSec, uint32_t curTimeMs) { CWorld::s_tickTimeMs = static_cast(tickTimeSec * 1000.0f); CWorld::s_tickTimeSec = tickTimeSec; } + +void CWorld::Update(const C3Vector& cameraPos, const C3Vector& cameraTarget, const C3Vector& targetPos) { + // TODO +} diff --git a/src/world/CWorld.hpp b/src/world/CWorld.hpp index 124e370..63c19ec 100644 --- a/src/world/CWorld.hpp +++ b/src/world/CWorld.hpp @@ -70,6 +70,7 @@ class CWorld { static int32_t OnTick(const EVENT_DATA_TICK* data, void* param); static void SetFarClip(float farClip); static void SetUpdateTime(float tickTimeSec, uint32_t curTimeMs); + static void Update(const C3Vector& cameraPos, const C3Vector& cameraTarget, const C3Vector& targetPos); private: // Private static variables From af4b798942e3c44875d8fd2c81d1cd85ad7fd58b Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 21 Feb 2026 21:42:41 -0600 Subject: [PATCH 30/31] feat(ui): call CWorld::Update from CGWorldFrame::OnWorldUpdate --- src/ui/game/CGWorldFrame.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ui/game/CGWorldFrame.cpp b/src/ui/game/CGWorldFrame.cpp index 1b0c823..ccea161 100644 --- a/src/ui/game/CGWorldFrame.cpp +++ b/src/ui/game/CGWorldFrame.cpp @@ -2,8 +2,10 @@ #include "gx/Coordinate.hpp" #include "gx/Shader.hpp" #include "gx/Transform.hpp" +#include "object/Client.hpp" #include "ui/game/CGCamera.hpp" #include "ui/game/PlayerName.hpp" +#include "world/World.hpp" #include #include @@ -92,7 +94,19 @@ void CGWorldFrame::OnWorldRender() { void CGWorldFrame::OnWorldUpdate() { // TODO + auto target = ClntObjMgrObjectPtr(this->m_camera->GetTarget(), TYPE_OBJECT, __FILE__, __LINE__); + + // TODO + this->m_camera->SetupWorldProjection(this->m_screenRect); // TODO + + auto targetPos = target && !this->m_camera->HasModel() + ? target->GetPosition() + : this->m_camera->Position(); + + CWorld::Update(this->m_camera->Position(), this->m_camera->Target(), targetPos); + + // TODO } From fa98bbc1f05266b4e00b976a5af00d67bfaca3e0 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 22 Feb 2026 21:57:26 -0600 Subject: [PATCH 31/31] feat(object): add CGObject_C::GetFacing --- src/object/client/CGObject_C.cpp | 4 ++++ src/object/client/CGObject_C.hpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/object/client/CGObject_C.cpp b/src/object/client/CGObject_C.cpp index f8b1451..3ae73a7 100644 --- a/src/object/client/CGObject_C.cpp +++ b/src/object/client/CGObject_C.cpp @@ -95,6 +95,10 @@ void CGObject_C::Disable() { this->m_disableTimeMs = CWorld::GetCurTimeMs(); } +float CGObject_C::GetFacing() const { + return 0.0f; +} + int32_t CGObject_C::GetModelFileName(const char*& name) const { return false; } diff --git a/src/object/client/CGObject_C.hpp b/src/object/client/CGObject_C.hpp index 788bbb5..f7d9400 100644 --- a/src/object/client/CGObject_C.hpp +++ b/src/object/client/CGObject_C.hpp @@ -38,6 +38,8 @@ class CGObject_C : public CGObject, public TSHashObject