From 01a9c940f015022e6208431510b1daf5e120804f Mon Sep 17 00:00:00 2001
From: CatChow0 <thetrueshibadoggo@gmail.com>
Date: Sun, 12 Jan 2025 00:59:43 +0100
Subject: [PATCH] Minor update - frustum rework

Complete overhaul of frustum culling
---
 enginecustom/applicationclass.cpp         | 110 +++++++++-------------
 enginecustom/applicationclass.h           |  24 ++++-
 enginecustom/enginecustom.vcxproj         |   7 +-
 enginecustom/enginecustom.vcxproj.filters |  12 ++-
 enginecustom/frustum.cpp                  |  88 +++++++++++++++++
 enginecustom/frustum.h                    |  12 +++
 enginecustom/imgui.ini                    |   6 +-
 enginecustom/imguiManager.cpp             |   7 ++
 enginecustom/object.cpp                   |   8 +-
 enginecustom/object.h                     |   4 +
 10 files changed, 201 insertions(+), 77 deletions(-)
 create mode 100644 enginecustom/frustum.cpp
 create mode 100644 enginecustom/frustum.h

diff --git a/enginecustom/applicationclass.cpp b/enginecustom/applicationclass.cpp
index 1784448..c3e34d6 100644
--- a/enginecustom/applicationclass.cpp
+++ b/enginecustom/applicationclass.cpp
@@ -17,7 +17,6 @@ ApplicationClass::ApplicationClass() : m_ShouldQuit(false)
 	m_RenderCountString = 0;
 	m_ModelList = 0;
 	m_Position = 0;
-	m_Frustum = 0;
 	m_DisplayPlane = 0;
 	m_BathModel = 0;
 	m_WaterModel = 0;
@@ -382,9 +381,6 @@ bool ApplicationClass::Initialize(int screenWidth, int screenHeight, HWND hwnd)
 		// Create the position class object.
 		m_Position = new PositionClass;
 
-		// Create the frustum class object.
-		m_Frustum = new FrustumClass;
-
 		// Create and initialize the fps object.
 		m_Fps = new FpsClass();
 
@@ -472,17 +468,6 @@ void ApplicationClass::Shutdown()
 		m_Physics = 0;
 	}
 
-	// Release the frustum class object.
-	if (m_Frustum)
-	{
-		Logger::Get().Log("Releasing the frustum class object", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
-
-		delete m_Frustum;
-		m_Frustum = 0;
-
-		Logger::Get().Log("Frustum class object released", __FILE__, __LINE__, Logger::LogLevel::Shutdown);
-	}
-
 	// Release the display plane object.
 	if (m_DisplayPlane)
 	{
@@ -1087,6 +1072,15 @@ bool ApplicationClass::Render(float rotation, float x, float y, float z, float t
 		return false;
 	}
 
+	// Update the render count text.
+	result = UpdateRenderCountString(GetRenderCount());
+	if (!result)
+	{
+		Logger::Get().Log("Could not update the render count string", __FILE__, __LINE__, Logger::LogLevel::Error);
+		return false;
+	}
+
+
 	// Translate to where the bath model will be rendered.
 	worldMatrix = XMMatrixTranslation(0.0f, -10.0f, 0.0f);
 
@@ -1164,57 +1158,6 @@ bool ApplicationClass::Render(float rotation, float x, float y, float z, float t
 		return false;
 	}
 
-	// Construct the frustum.
-	m_Frustum->ConstructFrustum(viewMatrix, projectionMatrix, SCREEN_DEPTH);
-
-	// Get the number of models that will be rendered.
-	modelCount = m_ModelList->GetModelCount();
-
-	// Initialize the count of models that have been rendered.
-	renderCount = 0;
-
-	// Go through all the models and render them only if they can be seen by the camera view.
-	for (i = 0; i < modelCount; i++)
-	{
-		// Get the position and color of the sphere model at this index.
-		m_ModelList->GetData(i, positionX, positionY, positionZ);
-
-		// Set the radius of the sphere to 1.0 since this is already known.
-		radius = 1.0f;
-
-		// Check if the sphere model is in the view frustum.
-		renderModel = m_Frustum->CheckSphere(positionX, positionY, positionZ, radius);
-
-		// If it can be seen then render it, if not skip this model and check the next sphere.
-		if (renderModel)
-		{
-			// Move the model to the location it should be rendered at.
-			worldMatrix = XMMatrixTranslation(positionX, positionY, positionZ);
-
-			// Render the model using the light shader.
-			m_Model->Render(m_Direct3D->GetDeviceContext());
-
-			result = m_ShaderManager->RenderlightShader(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_Model->GetTexture(0),
-				diffuseColor, lightPosition, ambientColor);
-			if (!result)
-			{
-				Logger::Get().Log("Could not render the model using the light shader", __FILE__, __LINE__, Logger::LogLevel::Error);
-				return false;
-			}
-
-			// Since this model was rendered then increase the count for this frame.
-			renderCount++;
-		}
-	}
-
-	// Update the render count text.
-	result = UpdateRenderCountString(renderCount);
-	if (!result)
-	{
-		Logger::Get().Log("Could not update the render count string", __FILE__, __LINE__, Logger::LogLevel::Error);
-		return false;
-	}
-
 	// Disable the Z buffer and enable alpha blending for 2D rendering.
 	m_Direct3D->TurnZBufferOff();
 	m_Direct3D->EnableAlphaBlending();
@@ -1560,10 +1503,10 @@ void ApplicationClass::AddKobject(WCHAR* filepath)
 
 	// Liste des fichiers de texture
 	std::vector<std::wstring> kobjTexture = {
-		L"assets/Texture/Bricks2K.png"
+		L"assets/Texture/Bricks2K.png",
+		L"assets/Texture/EmptyTexture.png"
 	};
 
-
 	textures.clear();
 	for (const auto& textureFilename : kobjTexture)
 	{
@@ -1917,6 +1860,11 @@ bool ApplicationClass::RenderPass(const std::vector<std::reference_wrapper<std::
 	XMMATRIX worldMatrix, scaleMatrix, rotateMatrix, translateMatrix, srMatrix;
 	bool result;
 
+	int renderCount = 0;
+
+	ConstructFrustum();	
+
+
 	for (const auto& RenderQueue : RenderQueues)
 	{
 		for (auto& object : RenderQueue.get())
@@ -1927,6 +1875,21 @@ bool ApplicationClass::RenderPass(const std::vector<std::reference_wrapper<std::
 				return false;
 			}
 
+			XMVECTOR objposition = object->GetPosition();
+			float x = XMVectorGetX(objposition);
+			float y = XMVectorGetY(objposition);
+			float z = XMVectorGetZ(objposition);
+			float radius = object->GetBoundingRadius();
+
+			// V�rifie si l'objet est dans le frustum
+			if (!m_FrustumCulling.CheckCube(x, y, z, radius, GetFrustumTolerance()))
+			{
+				
+				continue;
+			}
+
+			renderCount++;
+
 			scaleMatrix = object->GetScaleMatrix();
 			rotateMatrix = object->GetRotateMatrix();
 			translateMatrix = object->GetTranslateMatrix();
@@ -1981,5 +1944,16 @@ bool ApplicationClass::RenderPass(const std::vector<std::reference_wrapper<std::
 		}
 	}
 
+	SetRenderCount(renderCount);
+
 	return true;
 }
+
+void ApplicationClass::ConstructFrustum()
+{
+	XMMATRIX projectionMatrix = m_Direct3D->GetProjectionMatrix();
+	XMMATRIX viewMatrix;
+	m_Camera->GetViewMatrix(viewMatrix);
+
+	m_FrustumCulling.ConstructFrustum(SCREEN_DEPTH, projectionMatrix, viewMatrix);
+}
\ No newline at end of file
diff --git a/enginecustom/applicationclass.h b/enginecustom/applicationclass.h
index 00c0a81..3e8231e 100644
--- a/enginecustom/applicationclass.h
+++ b/enginecustom/applicationclass.h
@@ -29,6 +29,7 @@
 #include "translateshaderclass.h"
 #include "reflectionshaderclass.h"
 #include "physics.h"
+#include "frustum.h"
 
 #include <WICTextureLoader.h>
 #include <comdef.h> // Pour _com_error
@@ -104,6 +105,19 @@ public:
 
 	Physics* GetPhysics() const { return m_Physics; };
 
+	// ----------------------------------- //
+	// ------------- Frustum ------------- //
+	// ----------------------------------- //
+
+	Frustum GetFrustum() const { return m_FrustumCulling; };
+	void SetFrustum(Frustum frustum) { m_FrustumCulling = frustum; };
+
+	void ConstructFrustum();
+	int GetRenderCount() const { return m_renderCount; };
+	void SetRenderCount(int renderCount) { m_renderCount = renderCount; };
+	float GetFrustumTolerance() const { return m_FrustumCullingTolerance; };
+	void SetFrustumTolerance(float frustumTolerance) { m_FrustumCullingTolerance = frustumTolerance; };
+
 private:
 	bool Render(float, float, float, float, float);
 	bool RenderPhysics(float x, float y, float z);
@@ -115,6 +129,7 @@ private:
 	bool RenderReflectionToTexture();
 	bool RenderPass(const std::vector<std::reference_wrapper<std::vector<Object*>>>& RenderQueues, XMFLOAT4* diffuse, XMFLOAT4* position, XMFLOAT4* ambient, XMMATRIX view, XMMATRIX projection);
 
+
 private :
 
 	// ------------------------------------- //
@@ -140,7 +155,6 @@ private :
 	int m_screenWidth, m_screenHeight;
 	CameraClass* m_Camera;
 	PositionClass* m_Position;
-	FrustumClass* m_Frustum;
 
 	// ------------------------------------ //
 	// ------------- OBJECTS -------------- //
@@ -204,6 +218,14 @@ private :
 	Physics* m_Physics;
 	float m_gravity;
 	XMVECTOR m_previousPosition;
+
+	// ------------------------------------------------- //
+	// ------------------- Frustum --------------------- //
+	// ------------------------------------------------- //
+
+	Frustum m_FrustumCulling;
+	int m_renderCount;
+	float m_FrustumCullingTolerance = 5.f;
 };
 
 #endif
\ No newline at end of file
diff --git a/enginecustom/enginecustom.vcxproj b/enginecustom/enginecustom.vcxproj
index e76a0b5..a649b5c 100644
--- a/enginecustom/enginecustom.vcxproj
+++ b/enginecustom/enginecustom.vcxproj
@@ -26,6 +26,7 @@
     <ClCompile Include="CelShadingShader.cpp" />
     <ClCompile Include="Colorshaderclass.cpp" />
     <ClCompile Include="d3dclass.cpp" />
+    <ClCompile Include="frustum.cpp" />
     <ClCompile Include="imguiManager.cpp" />
     <ClCompile Include="include\backends\imgui_impl_dx11.cpp" />
     <ClCompile Include="include\backends\imgui_impl_win32.cpp" />
@@ -79,6 +80,7 @@
     <ClInclude Include="CelShadingShader.h" />
     <ClInclude Include="Colorshaderclass.h" />
     <ClInclude Include="d3dclass.h" />
+    <ClInclude Include="frustum.h" />
     <ClInclude Include="imguiManager.h" />
     <ClInclude Include="include\backends\imgui_impl_dx11.h" />
     <ClInclude Include="include\backends\imgui_impl_win32.h" />
@@ -304,7 +306,10 @@
     <CopyFileToFolders Include="assets\Texture\water01.png">
       <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)\assets\Texture\</DestinationFolders>
     </CopyFileToFolders>
-    <Image Include="assets\Texture\EmptyTexture.png" />
+    <CopyFileToFolders Include="assets\Texture\EmptyTexture.png">
+      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)\assets\Texture\</DestinationFolders>
+      <DestinationFolders Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)\assets\Texture\</DestinationFolders>
+    </CopyFileToFolders>
     <Image Include="KhaoticIcon.ico" />
     <CopyFileToFolders Include="sprite01.tga" />
     <CopyFileToFolders Include="sprite02.tga" />
diff --git a/enginecustom/enginecustom.vcxproj.filters b/enginecustom/enginecustom.vcxproj.filters
index 84d1d6c..7e551de 100644
--- a/enginecustom/enginecustom.vcxproj.filters
+++ b/enginecustom/enginecustom.vcxproj.filters
@@ -219,6 +219,9 @@
     <ClCompile Include="textureclass.cpp">
       <Filter>Fichiers sources\System</Filter>
     </ClCompile>
+    <ClCompile Include="frustum.cpp">
+      <Filter>Fichiers sources\System</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="systemclass.h">
@@ -383,14 +386,14 @@
     <ClInclude Include="object.h">
       <Filter>Fichiers d%27en-tête\System</Filter>
     </ClInclude>
+    <ClInclude Include="frustum.h">
+      <Filter>Fichiers d%27en-tête\System</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Image Include="KhaoticIcon.ico">
       <Filter>Assets</Filter>
     </Image>
-    <Image Include="assets\Texture\EmptyTexture.png">
-      <Filter>Assets\Texture</Filter>
-    </Image>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
@@ -620,5 +623,8 @@
     <CopyFileToFolders Include="assets\Model\OBJ\plane.obj">
       <Filter>Assets\Model\OBJ</Filter>
     </CopyFileToFolders>
+    <CopyFileToFolders Include="assets\Texture\EmptyTexture.png">
+      <Filter>Assets\Texture</Filter>
+    </CopyFileToFolders>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/enginecustom/frustum.cpp b/enginecustom/frustum.cpp
new file mode 100644
index 0000000..2057088
--- /dev/null
+++ b/enginecustom/frustum.cpp
@@ -0,0 +1,88 @@
+#include "frustum.h"
+
+void Frustum::ConstructFrustum(float screenDepth, XMMATRIX projectionMatrix, XMMATRIX viewMatrix)
+{
+    XMMATRIX matrix;
+    XMVECTOR planes[6];
+
+    // Calculate the minimum Z distance in the frustum.
+    float zMinimum = -projectionMatrix.r[3].m128_f32[2] / projectionMatrix.r[2].m128_f32[2];
+    float r = screenDepth / (screenDepth - zMinimum);
+    projectionMatrix.r[2].m128_f32[2] = r;
+    projectionMatrix.r[3].m128_f32[2] = -r * zMinimum;
+
+    // Create the frustum matrix from the view matrix and updated projection matrix.
+    matrix = XMMatrixMultiply(viewMatrix, projectionMatrix);
+
+    // Calculate near plane of frustum.
+    planes[0] = XMPlaneNormalize(XMVectorSet(matrix.r[0].m128_f32[3] + matrix.r[0].m128_f32[2],
+        matrix.r[1].m128_f32[3] + matrix.r[1].m128_f32[2],
+        matrix.r[2].m128_f32[3] + matrix.r[2].m128_f32[2],
+        matrix.r[3].m128_f32[3] + matrix.r[3].m128_f32[2]));
+
+    // Calculate far plane of frustum.
+    planes[1] = XMPlaneNormalize(XMVectorSet(matrix.r[0].m128_f32[3] - matrix.r[0].m128_f32[2],
+        matrix.r[1].m128_f32[3] - matrix.r[1].m128_f32[2],
+        matrix.r[2].m128_f32[3] - matrix.r[2].m128_f32[2],
+        matrix.r[3].m128_f32[3] - matrix.r[3].m128_f32[2]));
+
+    // Calculate left plane of frustum.
+    planes[2] = XMPlaneNormalize(XMVectorSet(matrix.r[0].m128_f32[3] + matrix.r[0].m128_f32[0],
+        matrix.r[1].m128_f32[3] + matrix.r[1].m128_f32[0],
+        matrix.r[2].m128_f32[3] + matrix.r[2].m128_f32[0],
+        matrix.r[3].m128_f32[3] + matrix.r[3].m128_f32[0]));
+
+    // Calculate right plane of frustum.
+    planes[3] = XMPlaneNormalize(XMVectorSet(matrix.r[0].m128_f32[3] - matrix.r[0].m128_f32[0],
+        matrix.r[1].m128_f32[3] - matrix.r[1].m128_f32[0],
+        matrix.r[2].m128_f32[3] - matrix.r[2].m128_f32[0],
+        matrix.r[3].m128_f32[3] - matrix.r[3].m128_f32[0]));
+
+    // Calculate top plane of frustum.
+    planes[4] = XMPlaneNormalize(XMVectorSet(matrix.r[0].m128_f32[3] - matrix.r[0].m128_f32[1],
+        matrix.r[1].m128_f32[3] - matrix.r[1].m128_f32[1],
+        matrix.r[2].m128_f32[3] - matrix.r[2].m128_f32[1],
+        matrix.r[3].m128_f32[3] - matrix.r[3].m128_f32[1]));
+
+    // Calculate bottom plane of frustum.
+    planes[5] = XMPlaneNormalize(XMVectorSet(matrix.r[0].m128_f32[3] + matrix.r[0].m128_f32[1],
+        matrix.r[1].m128_f32[3] + matrix.r[1].m128_f32[1],
+        matrix.r[2].m128_f32[3] + matrix.r[2].m128_f32[1],
+        matrix.r[3].m128_f32[3] + matrix.r[3].m128_f32[1]));
+
+    for (int i = 0; i < 6; i++)
+    {
+        m_planes[i] = planes[i];
+    }
+}
+
+bool Frustum::CheckCube(float xCenter, float yCenter, float zCenter, float radius, float tolerance)
+{
+    // V�rifiez chaque plan du frustum pour voir si le cube est � l'int�rieur
+    for (int i = 0; i < 6; i++)
+    {
+        XMVECTOR plane = m_planes[i];
+        if (XMVectorGetX(plane) * (xCenter - radius) + XMVectorGetY(plane) * (yCenter - radius) + XMVectorGetZ(plane) * (zCenter - radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter + radius) + XMVectorGetY(plane) * (yCenter - radius) + XMVectorGetZ(plane) * (zCenter - radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter - radius) + XMVectorGetY(plane) * (yCenter + radius) + XMVectorGetZ(plane) * (zCenter - radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter + radius) + XMVectorGetY(plane) * (yCenter + radius) + XMVectorGetZ(plane) * (zCenter - radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter - radius) + XMVectorGetY(plane) * (yCenter - radius) + XMVectorGetZ(plane) * (zCenter + radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter + radius) + XMVectorGetY(plane) * (yCenter - radius) + XMVectorGetZ(plane) * (zCenter + radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter - radius) + XMVectorGetY(plane) * (yCenter + radius) + XMVectorGetZ(plane) * (zCenter + radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+        if (XMVectorGetX(plane) * (xCenter + radius) + XMVectorGetY(plane) * (yCenter + radius) + XMVectorGetZ(plane) * (zCenter + radius) + XMVectorGetW(plane) > -tolerance)
+            continue;
+
+        // Si le cube est en dehors de l'un des plans, il n'est pas dans le frustum
+        return false;
+    }
+
+    // Si le cube est � l'int�rieur de tous les plans, il est dans le frustum
+    return true;
+}
diff --git a/enginecustom/frustum.h b/enginecustom/frustum.h
new file mode 100644
index 0000000..eac209a
--- /dev/null
+++ b/enginecustom/frustum.h
@@ -0,0 +1,12 @@
+#include <DirectXMath.h>
+using namespace DirectX;
+
+class Frustum
+{
+public:
+    void ConstructFrustum(float screenDepth, XMMATRIX projectionMatrix, XMMATRIX viewMatrix);
+    bool CheckCube(float xCenter, float yCenter, float zCenter, float radius, float tolerance);
+
+private:
+    XMVECTOR m_planes[6];
+};
\ No newline at end of file
diff --git a/enginecustom/imgui.ini b/enginecustom/imgui.ini
index d0ff702..9d74d7a 100644
--- a/enginecustom/imgui.ini
+++ b/enginecustom/imgui.ini
@@ -11,7 +11,7 @@ Pos=934,36
 Size=457,294
 
 [Window][Terrain]
-Pos=60,60
+Pos=58,62
 Size=342,82
 
 [Window][Light]
@@ -23,6 +23,6 @@ Pos=471,90
 Size=180,79
 
 [Window][Engine Settings]
-Pos=106,213
-Size=168,77
+Pos=106,212
+Size=407,81
 
diff --git a/enginecustom/imguiManager.cpp b/enginecustom/imguiManager.cpp
index 68621db..6771062 100644
--- a/enginecustom/imguiManager.cpp
+++ b/enginecustom/imguiManager.cpp
@@ -435,5 +435,12 @@ void imguiManager::WidgetEngineSettingsWindow(ApplicationClass* app)
 		app->SetVsync(vsync);
 	}
 
+	// float input for frustum tolerance
+	float frustumTolerance = app->GetFrustumTolerance();
+	if (ImGui::DragFloat("Frustum Tolerance", &frustumTolerance, 0.1f, 0.0f, 100.0f))
+	{
+		app->SetFrustumTolerance(frustumTolerance);
+	}
+
 	ImGui::End();
 }
\ No newline at end of file
diff --git a/enginecustom/object.cpp b/enginecustom/object.cpp
index 3d16471..9417cd9 100644
--- a/enginecustom/object.cpp
+++ b/enginecustom/object.cpp
@@ -13,6 +13,7 @@ Object::Object() : ModelClass()
 	m_mass = NULL;
 	m_isGrounded = false;
 	m_id = NULL;
+	m_boundingRadius = 1.0f;
 }
 
 Object::~Object()
@@ -233,4 +234,9 @@ bool Object::IsPhysicsEnabled() const
 void Object::SetPhysicsEnabled(bool state)
 {
 	m_isPhysicsEnabled = state;
-}
\ No newline at end of file
+}
+
+float Object::GetBoundingRadius() const
+{
+	return m_boundingRadius;
+}
diff --git a/enginecustom/object.h b/enginecustom/object.h
index 111e34b..6abbc30 100644
--- a/enginecustom/object.h
+++ b/enginecustom/object.h
@@ -70,6 +70,8 @@ public:
 	ShaderType GetActiveShader() const { return m_activeShader; };
 	void SetActiveShader(ShaderType activeShader) { m_activeShader = activeShader; };
 
+	float GetBoundingRadius() const;
+
 public :
 	bool m_demoSpinning = false;
 	XMVECTOR m_previousPosition;
@@ -91,4 +93,6 @@ private:
 	std::string m_name;
 
 	ShaderType m_activeShader = LIGHTING;
+
+	float m_boundingRadius;
 };