aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Core/Camera.cpp181
-rw-r--r--src/Core/Camera.h75
-rw-r--r--src/Engine/Engine.cpp347
-rw-r--r--src/Engine/Engine.h118
-rw-r--r--src/Engine/Object.cpp46
-rw-r--r--src/Engine/Object.h38
-rw-r--r--src/Engine/Scene.cpp57
-rw-r--r--src/Engine/Scene.h20
-rw-r--r--src/Platform/OpenGL/OpenGLRendererAPI.cpp16
-rw-r--r--src/Platform/OpenGL/OpenGLRendererAPI.h3
-rw-r--r--src/Platform/OpenGL/OpenGLUniformBuffer.cpp29
-rw-r--r--src/Platform/OpenGL/OpenGLUniformBuffer.h22
-rw-r--r--src/Platform/Vulkan/VulkanRendererAPI.cpp15
-rw-r--r--src/Platform/Vulkan/VulkanRendererAPI.h3
-rw-r--r--src/Platform/Vulkan/VulkanUniformBuffer.cpp25
-rw-r--r--src/Platform/Vulkan/VulkanUniformBuffer.h20
-rw-r--r--src/Rendering/IndexBuffer.cpp6
-rw-r--r--src/Rendering/IndexBuffer.h3
-rw-r--r--src/Rendering/Renderer.cpp8
-rw-r--r--src/Rendering/Renderer.h22
-rw-r--r--src/Rendering/Shader.cpp22
-rw-r--r--src/Rendering/Shader.h6
-rw-r--r--src/Rendering/UniformBuffer.cpp23
-rw-r--r--src/Rendering/UniformBuffer.h18
-rw-r--r--src/Rendering/VertexArray.cpp6
-rw-r--r--src/Rendering/VertexArray.h2
-rw-r--r--src/Rendering/VertexBuffer.cpp6
-rw-r--r--src/Rendering/VertexBuffer.h6
-rw-r--r--src/States/SimulationState.cpp93
-rw-r--r--src/States/SimulationState.h6
30 files changed, 1168 insertions, 74 deletions
diff --git a/src/Core/Camera.cpp b/src/Core/Camera.cpp
index 4dff2d7..6f86124 100644
--- a/src/Core/Camera.cpp
+++ b/src/Core/Camera.cpp
@@ -28,22 +28,32 @@ namespace Donut
void Camera::RecalculateViewMatrix()
{
- float pitch = glm::radians(m_Rotation.x);
- float yaw = glm::radians(m_Rotation.y);
- float roll = glm::radians(m_Rotation.z);
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ float pitch = glm::radians(m_Rotation.x);
+ float yaw = glm::radians(m_Rotation.y);
+ float roll = glm::radians(m_Rotation.z);
- glm::vec3 direction;
- direction.x = cos(yaw) * cos(pitch);
- direction.y = sin(pitch);
- direction.z = sin(yaw) * cos(pitch);
+ glm::vec3 direction;
+ direction.x = cos(yaw) * cos(pitch);
+ direction.y = sin(pitch);
+ direction.z = sin(yaw) * cos(pitch);
- glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
- glm::vec3 front = glm::normalize(direction);
- glm::vec3 right = glm::normalize(glm::cross(front, worldUp));
- glm::vec3 up = glm::normalize(glm::cross(right, front));
+ glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
+ glm::vec3 front = glm::normalize(direction);
+ glm::vec3 right = glm::normalize(glm::cross(front, worldUp));
+ glm::vec3 up = glm::normalize(glm::cross(right, front));
- m_ViewMatrix = glm::lookAt(m_Position, m_Position + front, up);
- m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
+ m_ViewMatrix = glm::lookAt(m_Position, m_Position + front, up);
+ m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
+ }
+ else if (m_CameraMode == CameraMode::Orbital)
+ {
+ glm::vec3 position = GetOrbitalPosition();
+ glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
+ m_ViewMatrix = glm::lookAt(position, m_Target, worldUp);
+ m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
+ }
}
glm::vec3 Camera::GetForwardDirection() const
@@ -72,58 +82,153 @@ namespace Donut
void Camera::OnMouseMove(float xOffset, float yOffset, bool constrainPitch)
{
- xOffset *= m_MouseSensitivity;
- yOffset *= m_MouseSensitivity;
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ xOffset *= m_MouseSensitivity;
+ yOffset *= m_MouseSensitivity;
- m_Rotation.y += xOffset;
- m_Rotation.x += yOffset;
+ m_Rotation.y += xOffset;
+ m_Rotation.x += yOffset;
- if (constrainPitch)
- {
- if (m_Rotation.x > 89.0f)
- m_Rotation.x = 89.0f;
- if (m_Rotation.x < -89.0f)
- m_Rotation.x = -89.0f;
- }
+ if (constrainPitch)
+ {
+ if (m_Rotation.x > 89.0f)
+ m_Rotation.x = 89.0f;
+ if (m_Rotation.x < -89.0f)
+ m_Rotation.x = -89.0f;
+ }
- RecalculateViewMatrix();
+ RecalculateViewMatrix();
+ }
}
void Camera::MoveForward(float deltaTime)
{
- m_Position += GetForwardDirection() * m_MovementSpeed * deltaTime;
- RecalculateViewMatrix();
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ m_Position += GetForwardDirection() * m_MovementSpeed * deltaTime;
+ RecalculateViewMatrix();
+ }
}
void Camera::MoveBackward(float deltaTime)
{
- m_Position -= GetForwardDirection() * m_MovementSpeed * deltaTime;
- RecalculateViewMatrix();
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ m_Position -= GetForwardDirection() * m_MovementSpeed * deltaTime;
+ RecalculateViewMatrix();
+ }
}
void Camera::MoveRight(float deltaTime)
{
- m_Position += GetRightDirection() * m_MovementSpeed * deltaTime;
- RecalculateViewMatrix();
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ m_Position += GetRightDirection() * m_MovementSpeed * deltaTime;
+ RecalculateViewMatrix();
+ }
}
void Camera::MoveLeft(float deltaTime)
{
- m_Position -= GetRightDirection() * m_MovementSpeed * deltaTime;
- RecalculateViewMatrix();
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ m_Position -= GetRightDirection() * m_MovementSpeed * deltaTime;
+ RecalculateViewMatrix();
+ }
}
void Camera::MoveUp(float deltaTime)
{
- glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
- m_Position += worldUp * m_MovementSpeed * deltaTime;
- RecalculateViewMatrix();
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
+ m_Position += worldUp * m_MovementSpeed * deltaTime;
+ RecalculateViewMatrix();
+ }
}
void Camera::MoveDown(float deltaTime)
{
- glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
- m_Position -= worldUp * m_MovementSpeed * deltaTime;
+ if (m_CameraMode == CameraMode::FPS)
+ {
+ glm::vec3 worldUp(0.0f, 1.0f, 0.0f);
+ m_Position -= worldUp * m_MovementSpeed * deltaTime;
+ RecalculateViewMatrix();
+ }
+ }
+
+ // Orbital Camera Methods
+ void Camera::SetOrbitalMode(bool enabled)
+ {
+ m_CameraMode = enabled ? CameraMode::Orbital : CameraMode::FPS;
+ RecalculateViewMatrix();
+ }
+
+ glm::vec3 Camera::GetOrbitalPosition() const
+ {
+ float clampedElevation = glm::clamp(m_Elevation, 0.01f, float(M_PI) - 0.01f);
+ return glm::vec3(
+ m_Radius * sin(clampedElevation) * cos(m_Azimuth),
+ m_Radius * cos(clampedElevation),
+ m_Radius * sin(clampedElevation) * sin(m_Azimuth)
+ );
+ }
+
+ void Camera::ProcessOrbitalMouseMove(double x, double y)
+ {
+ if (m_Dragging && !m_Panning)
+ {
+ float dx = float(x - m_OrbitalLastX);
+ float dy = float(y - m_OrbitalLastY);
+
+ m_Azimuth += dx * m_OrbitSpeed;
+ m_Elevation -= dy * m_OrbitSpeed;
+ m_Elevation = glm::clamp(m_Elevation, 0.01f, float(M_PI) - 0.01f);
+ }
+
+ m_OrbitalLastX = x;
+ m_OrbitalLastY = y;
+ UpdateOrbitalState();
RecalculateViewMatrix();
}
+
+ void Camera::ProcessOrbitalMouseButton(int button, int action, int mods)
+ {
+ if (button == GLFW_MOUSE_BUTTON_LEFT)
+ {
+ if (action == GLFW_PRESS)
+ {
+ m_Dragging = true;
+ m_Panning = false;
+ }
+ else if (action == GLFW_RELEASE)
+ {
+ m_Dragging = false;
+ m_Panning = false;
+ }
+ }
+ UpdateOrbitalState();
+ }
+
+ void Camera::ProcessOrbitalScroll(double xoffset, double yoffset)
+ {
+ m_Radius -= yoffset * m_ZoomSpeed;
+ m_Radius = glm::clamp(m_Radius, m_MinRadius, m_MaxRadius);
+ UpdateOrbitalState();
+ RecalculateViewMatrix();
+ }
+
+ void Camera::UpdateOrbitalState()
+ {
+ m_Target = glm::vec3(0.0f, 0.0f, 0.0f);
+ if (m_Dragging || m_Panning)
+ {
+ m_Moving = true;
+ }
+ else
+ {
+ m_Moving = false;
+ }
+ }
}
diff --git a/src/Core/Camera.h b/src/Core/Camera.h
index e3569b8..7fe3bd9 100644
--- a/src/Core/Camera.h
+++ b/src/Core/Camera.h
@@ -2,9 +2,21 @@
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
+#include <GLFW/glfw3.h>
+
+#define _USE_MATH_DEFINES
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
namespace Donut
{
+ enum class CameraMode
+ {
+ FPS,
+ Orbital
+ };
+
class Camera
{
public:
@@ -12,6 +24,7 @@ namespace Donut
float nearPlane = 0.1f, float farPlane = 100.0f);
~Camera() = default;
+ // FPS Camera Methods
void SetPosition(const glm::vec3& position) { m_Position = position; RecalculateViewMatrix(); }
void SetRotation(const glm::vec3& rotation) { m_Rotation = rotation; RecalculateViewMatrix(); }
@@ -42,10 +55,57 @@ namespace Donut
void SetMovementSpeed(float speed) { m_MovementSpeed = speed; }
float GetMovementSpeed() const { return m_MovementSpeed; }
+ // Orbital Camera Methods
+ void SetOrbitalMode(bool enabled);
+ bool IsOrbitalMode() const { return m_CameraMode == CameraMode::Orbital; }
+
+ void SetTarget(const glm::vec3& target) { m_Target = target; }
+ const glm::vec3& GetTarget() const { return m_Target; }
+
+ void SetRadius(double radius) { m_Radius = radius; }
+ double GetRadius() const { return m_Radius; }
+
+ void SetMinRadius(double minRadius) { m_MinRadius = minRadius; }
+ double GetMinRadius() const { return m_MinRadius; }
+
+ void SetMaxRadius(double maxRadius) { m_MaxRadius = maxRadius; }
+ double GetMaxRadius() const { return m_MaxRadius; }
+
+ void SetAzimuth(float azimuth) { m_Azimuth = azimuth; }
+ float GetAzimuth() const { return m_Azimuth; }
+
+ void SetElevation(float elevation) { m_Elevation = elevation; }
+ float GetElevation() const { return m_Elevation; }
+
+ void SetOrbitSpeed(float orbitSpeed) { m_OrbitSpeed = orbitSpeed; }
+ float GetOrbitSpeed() const { return m_OrbitSpeed; }
+
+ void SetZoomSpeed(double zoomSpeed) { m_ZoomSpeed = zoomSpeed; }
+ double GetZoomSpeed() const { return m_ZoomSpeed; }
+
+ // Orbital camera position calculation
+ glm::vec3 GetOrbitalPosition() const;
+
+ // Input handling for orbital camera
+ void ProcessOrbitalMouseMove(double x, double y);
+ void ProcessOrbitalMouseButton(int button, int action, int mods);
+ void ProcessOrbitalScroll(double xoffset, double yoffset);
+
+ // State management
+ bool IsDragging() const { return m_Dragging; }
+ bool IsPanning() const { return m_Panning; }
+ bool IsMoving() const { return m_Moving; }
+
private:
void RecalculateViewMatrix();
void RecalculateProjectionMatrix();
+ void UpdateOrbitalState();
+
private:
+ // Camera mode
+ CameraMode m_CameraMode = CameraMode::FPS;
+
+ // FPS Camera members
glm::mat4 m_ProjectionMatrix;
glm::mat4 m_ViewMatrix;
glm::mat4 m_ViewProjectionMatrix;
@@ -63,5 +123,20 @@ namespace Donut
bool m_FirstMouse = true;
float m_LastX = 0.0f;
float m_LastY = 0.0f;
+
+ // Orbital Camera members
+ glm::vec3 m_Target = glm::vec3(0.0f, 0.0f, 0.0f);
+ double m_Radius = 6.34194e10;
+ double m_MinRadius = 1e10;
+ double m_MaxRadius = 1e12;
+ float m_Azimuth = 0.0f;
+ float m_Elevation = static_cast<float>(M_PI) / 2.0f;
+ float m_OrbitSpeed = 0.01f;
+ double m_ZoomSpeed = 25e9f;
+ bool m_Dragging = false;
+ bool m_Panning = false;
+ bool m_Moving = false;
+ double m_OrbitalLastX = 0.0;
+ double m_OrbitalLastY = 0.0;
};
}
diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp
new file mode 100644
index 0000000..614e8e5
--- /dev/null
+++ b/src/Engine/Engine.cpp
@@ -0,0 +1,347 @@
+#include "Engine.h"
+#include <GLFW/glfw3.h>
+#include <glad/glad.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <limits>
+#include "Rendering/VertexBuffer.h"
+#include "Rendering/IndexBuffer.h"
+
+namespace Donut
+{
+ Engine::Engine()
+ : m_SagA(glm::vec3(0.0f, 0.0f, 0.0f),
+ static_cast<float>(8.54e36))
+ {
+ GLFWwindow* window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
+ glfwGetFramebufferSize(window, &m_Width, &m_Height);
+ m_ComputeHeight = 420;
+ m_ComputeWidth = (m_Width * 420) / m_Height;
+
+ m_Camera.SetOrbitalMode(true);
+ m_Camera.SetRadius(6.34194e10);
+ m_Camera.SetMinRadius(1e10);
+ m_Camera.SetMaxRadius(1e12);
+ m_Camera.SetOrbitSpeed(0.01f);
+ m_Camera.SetZoomSpeed(25e9f);
+
+ m_Objects =
+ {
+ { glm::vec4(4e11f, 0.0f, 0.0f, 4e10f), glm::vec4(1,1,0,1), static_cast<float>(1.98892e30) },
+ { glm::vec4(0.0f, 0.0f, 4e11f, 4e10f), glm::vec4(1,0,0,1), static_cast<float>(1.98892e30) },
+ { glm::vec4(0.0f, 0.0f, 0.0f, m_SagA.m_Rs), glm::vec4(0,0,0,1), static_cast<float>(m_SagA.m_Mass) }
+ };
+
+ m_QuadShader = Shader::Create("Assets/Shaders/Quad.glsl");
+ m_GridShader = Shader::Create("Assets/Shaders/Grid.glsl");
+ m_ComputeShader = Shader::CreateCompute("Geodesic", LoadComputeShader("Assets/Shaders/Geodesic.glsl"));
+
+ m_CameraUBO = UniformBuffer::Create(128, 1);
+ m_DiskUBO = UniformBuffer::Create(sizeof(float) * 4, 2);
+
+ uint32_t objUBOSize = sizeof(int) + 3 * sizeof(float)
+ + 16 * (sizeof(glm::vec4) + sizeof(glm::vec4))
+ + 16 * sizeof(float);
+ m_ObjectsUBO = UniformBuffer::Create(objUBOSize, 3);
+
+ float quadVertices[] =
+ {
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+
+ m_QuadVAO = VertexArray::Create();
+
+ auto vertexBuffer = VertexBuffer::Create(quadVertices, static_cast<uint32_t>(sizeof(quadVertices)));
+ VertexBufferLayout layout;
+ layout.Push<float>(2);
+ layout.Push<float>(2);
+ vertexBuffer->SetLayout(layout);
+ m_QuadVAO->AddVertexBuffer(vertexBuffer);
+
+ m_Texture = Texture2D::Create(m_Width, m_Height);
+ }
+
+ void Engine::GenerateGrid(const std::vector<ObjectData>& objects)
+ {
+ const int gridSize = 25;
+ const float spacing = 1e10f;
+
+ std::vector<glm::vec3> vertices;
+ std::vector<uint32_t> indices;
+
+ for (int z = 0; z <= gridSize; ++z)
+ {
+ for (int x = 0; x <= gridSize; ++x)
+ {
+ float worldX = (x - gridSize / 2) * spacing;
+ float worldZ = (z - gridSize / 2) * spacing;
+ float y = 0.0f;
+
+ for (const auto& obj : objects)
+ {
+ glm::vec3 objPos = glm::vec3(obj.m_PosRadius);
+ double mass = obj.m_Mass;
+ double radius = obj.m_PosRadius.w;
+
+ double r_s = 2.0 * G * mass / (c * c);
+ double dx = worldX - objPos.x;
+ double dz = worldZ - objPos.z;
+ double dist = sqrt(dx * dx + dz * dz);
+
+ if (dist > r_s)
+ {
+ double deltaY = 2.0 * sqrt(r_s * (dist - r_s));
+ y += static_cast<float>(deltaY) - 3e10f;
+ }
+ else
+ {
+ y += 2.0f * static_cast<float>(sqrt(r_s * r_s)) - 3e10f;
+ }
+ }
+
+ vertices.emplace_back(worldX, y, worldZ);
+ }
+ }
+
+ for (int z = 0; z < gridSize; ++z)
+ {
+ for (int x = 0; x < gridSize; ++x)
+ {
+ int i = z * (gridSize + 1) + x;
+ indices.push_back(i);
+ indices.push_back(i + 1);
+ indices.push_back(i);
+ indices.push_back(i + gridSize + 1);
+ }
+ }
+
+ if (!m_GridVAO)
+ {
+ m_GridVAO = Ref<VertexArray>(VertexArray::Create());
+
+ auto vertexBuffer = Ref<VertexBuffer>(VertexBuffer::Create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(glm::vec3))));
+ VertexBufferLayout layout;
+ layout.Push<float>(3);
+ vertexBuffer->SetLayout(layout);
+ m_GridVAO->AddVertexBuffer(vertexBuffer);
+
+ auto indexBuffer = Ref<IndexBuffer>(IndexBuffer::Create(indices.data(), static_cast<uint32_t>(indices.size())));
+ m_GridVAO->SetIndexBuffer(indexBuffer);
+ }
+ else
+ {
+ auto vertexBuffer = m_GridVAO->GetVertexBuffers()[0];
+ vertexBuffer->SetData(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(glm::vec3)));
+ }
+
+ m_GridIndexCount = static_cast<int>(indices.size());
+ }
+
+ void Engine::DrawGrid(const glm::mat4& viewProj)
+ {
+ if (!m_GridShader || !m_GridVAO)
+ return;
+
+ m_GridShader->Bind();
+ m_GridShader->SetMat4("viewProj", viewProj);
+
+ RenderCommand::DisableDepthTest();
+ RenderCommand::EnableBlending();
+
+ m_GridVAO->Bind();
+ glDrawElements(GL_LINES, m_GridIndexCount, GL_UNSIGNED_INT, nullptr);
+
+ RenderCommand::EnableDepthTest();
+ }
+
+ void Engine::UpdateWindowDimensions()
+ {
+ GLFWwindow* window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
+ int oldWidth = m_Width;
+ int oldHeight = m_Height;
+ glfwGetFramebufferSize(window, &m_Width, &m_Height);
+ m_ComputeHeight = 420;
+ m_ComputeWidth = (m_Width * 420) / m_Height;
+
+ if (oldWidth != m_Width || oldHeight != m_Height)
+ m_Texture = Texture2D::Create(m_Width, m_Height);
+ }
+
+ void Engine::DrawFullScreenQuad()
+ {
+ RenderCommand::SetViewport(0, 0, m_Width, m_Height);
+
+ m_QuadShader->Bind();
+ std::cout << "Texture ID: " << m_Texture->GetRendererID() << ", Size: " << m_Texture->GetWidth() << "x" << m_Texture->GetHeight() << std::endl;
+ m_Texture->Bind(0);
+ m_QuadShader->SetInt("screenTexture", 0);
+ std::cout << "Set screenTexture uniform to slot 0\n";
+
+ RenderCommand::DisableDepthTest();
+ RenderCommand::DrawIndexed(m_QuadVAO, 6);
+ RenderCommand::EnableDepthTest();
+ }
+
+ void Engine::DispatchCompute(const Camera& cam)
+ {
+ int cw = m_ComputeWidth;
+ int ch = m_ComputeHeight;
+
+ if (m_Texture->GetWidth() != cw || m_Texture->GetHeight() != ch)
+ m_Texture = Texture2D::Create(cw, ch);
+
+ m_ComputeShader->Bind();
+ UploadCameraUBO(cam);
+ UploadDiskUBO();
+ UploadObjectsUBO(m_Objects);
+
+ m_Texture->BindAsImage(0, false);
+
+ uint32_t groupsX = (uint32_t)std::ceil(cw / 16.0f);
+ uint32_t groupsY = (uint32_t)std::ceil(ch / 16.0f);
+ m_ComputeShader->Dispatch(groupsX, groupsY, 1);
+ m_ComputeShader->MemoryBarrier(IMAGE_ACCESS_BARRIER_BIT);
+
+ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
+ glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
+ }
+
+ void Engine::UploadCameraUBO(const Camera& cam)
+ {
+ struct UBOData
+ {
+ glm::vec3 pos; float _pad0;
+ glm::vec3 right; float _pad1;
+ glm::vec3 up; float _pad2;
+ glm::vec3 forward; float _pad3;
+ float tanHalfFov;
+ float aspect;
+ bool moving;
+ int _pad4;
+ } data;
+
+ glm::vec3 fwd = glm::normalize(cam.GetTarget() - cam.GetOrbitalPosition());
+ glm::vec3 up = glm::vec3(0, 1, 0);
+ glm::vec3 right = glm::normalize(glm::cross(fwd, up));
+ up = glm::cross(right, fwd);
+
+ data.pos = cam.GetOrbitalPosition();
+ data.right = right;
+ data.up = up;
+ data.forward = fwd;
+ data.tanHalfFov = static_cast<float>(tan(glm::radians(60.0f * 0.5f)));
+ data.aspect = static_cast<float>(m_Width) / static_cast<float>(m_Height);
+ data.moving = cam.IsDragging() || cam.IsPanning();
+
+ m_CameraUBO->SetData(&data, sizeof(UBOData));
+ }
+
+ void Engine::UploadObjectsUBO(const std::vector<ObjectData>& objs)
+ {
+ struct UBOData
+ {
+ int numObjects;
+ float _pad0, _pad1, _pad2;
+ glm::vec4 posRadius[16];
+ glm::vec4 color[16];
+ float mass[16];
+ } data;
+
+ size_t count = std::min(objs.size(), size_t(16));
+ data.numObjects = static_cast<int>(count);
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ data.posRadius[i] = objs[i].m_PosRadius;
+ data.color[i] = objs[i].m_Color;
+ data.mass[i] = objs[i].m_Mass;
+ }
+
+ m_ObjectsUBO->SetData(&data, sizeof(data));
+ }
+
+ void Engine::UploadDiskUBO()
+ {
+ float r1 = static_cast<float>(m_SagA.m_Rs * 2.2);
+ float r2 = static_cast<float>(m_SagA.m_Rs * 5.2);
+ float num = 2.0f;
+ float thickness = 1e9f;
+ float diskData[4] = { r1, r2, num, thickness };
+
+ m_DiskUBO->SetData(diskData, sizeof(diskData));
+ }
+
+ void Engine::UpdatePhysics(float deltaTime)
+ {
+ for (auto& obj : m_Objects)
+ {
+ for (auto& obj2 : m_Objects)
+ {
+ if (&obj == &obj2) continue;
+ float dx = obj2.m_PosRadius.x - obj.m_PosRadius.x;
+ float dy = obj2.m_PosRadius.y - obj.m_PosRadius.y;
+ float dz = obj2.m_PosRadius.z - obj.m_PosRadius.z;
+ float distance = sqrt(dx * dx + dy * dy + dz * dz);
+
+ if (distance > 0)
+ {
+ std::vector<double> direction = {dx / distance, dy / distance, dz / distance};
+ double Gforce = (G * obj.m_Mass * obj2.m_Mass) / (distance * distance);
+ double acc1 = Gforce / obj.m_Mass;
+ std::vector<double> acc = {direction[0] * acc1, direction[1] * acc1, direction[2] * acc1};
+
+ if (m_Gravity)
+ {
+ obj.m_Velocity.x += static_cast<float>(acc[0]);
+ obj.m_Velocity.y += static_cast<float>(acc[1]);
+ obj.m_Velocity.z += static_cast<float>(acc[2]);
+
+ obj.m_PosRadius.x += static_cast<float>(obj.m_Velocity.x);
+ obj.m_PosRadius.y += static_cast<float>(obj.m_Velocity.y);
+ obj.m_PosRadius.z += static_cast<float>(obj.m_Velocity.z);
+ }
+ }
+ }
+ }
+ }
+
+ void Engine::RenderScene()
+ {
+ glm::mat4 view = glm::lookAt(m_Camera.GetOrbitalPosition(), m_Camera.GetTarget(), glm::vec3(0,1,0));
+ glm::mat4 proj = glm::perspective(glm::radians(60.0f), float(m_Width)/m_Height, 1e9f, 1e14f);
+ glm::mat4 viewProj = proj * view;
+
+ GenerateGrid(m_Objects);
+ DrawGrid(viewProj);
+
+ RenderCommand::SetViewport(0, 0, m_Width, m_Height);
+ DispatchCompute(m_Camera);
+ DrawFullScreenQuad();
+ }
+
+ std::string Engine::LoadComputeShader(const std::string& path)
+ {
+ std::ifstream in(path);
+ if(!in.is_open())
+ {
+ std::cerr << "Failed to open compute shader: " << path << "\n";
+ return "";
+ }
+
+ std::stringstream ss;
+ ss << in.rdbuf();
+ std::string result = ss.str();
+ if (result.empty())
+ std::cerr << "Warning: Compute shader file is empty: " << path << "\n";
+ else
+ std::cout << "Successfully loaded compute shader: " << path << " (size: " << result.size() << " bytes)\n";
+ return result;
+ }
+}
diff --git a/src/Engine/Engine.h b/src/Engine/Engine.h
new file mode 100644
index 0000000..2368bb8
--- /dev/null
+++ b/src/Engine/Engine.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <vector>
+#include <iostream>
+#include <GLFW/glfw3.h>
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <fstream>
+#include <sstream>
+#include <chrono>
+#include <cmath>
+
+#include "Core/Application.h"
+#include "Core/Camera.h"
+#include "Rendering/Renderer.h"
+#include "Rendering/Shader.h"
+#include "Rendering/Texture.h"
+#include "Rendering/VertexArray.h"
+#include "Rendering/UniformBuffer.h"
+
+namespace Donut
+{
+ const double c = 299792458.0;
+ const double G = 6.67430e-11;
+
+ struct BlackHole
+ {
+ glm::vec3 m_Position;
+ double m_Mass;
+ double m_Radius;
+ double m_Rs;
+
+ BlackHole(glm::vec3 pos, float mass)
+ : m_Position(pos),
+ m_Mass(mass)
+ {
+ m_Rs = 2.0 * G * m_Mass / (c * c);
+ }
+
+ bool Intercept(float px, float py, float pz) const
+ {
+ double dx = double(px) - double(m_Position.x);
+ double dy = double(py) - double(m_Position.y);
+ double dz = double(pz) - double(m_Position.z);
+ double dist2 = dx * dx + dy * dy + dz * dz;
+ return dist2 < m_Rs * m_Rs;
+ }
+ };
+
+ struct ObjectData
+ {
+ glm::vec4 m_PosRadius;
+ glm::vec4 m_Color;
+ float m_Mass;
+ glm::vec3 m_Velocity = glm::vec3(0.0f, 0.0f, 0.0f);
+ };
+
+ class Engine
+ {
+ public:
+ Engine();
+ ~Engine() = default;
+
+ void GenerateGrid(const std::vector<ObjectData>& objects);
+ void DrawGrid(const glm::mat4& viewProj);
+ void DrawFullScreenQuad();
+ void DispatchCompute(const Camera& cam);
+ void UploadCameraUBO(const Camera& cam);
+ void UploadObjectsUBO(const std::vector<ObjectData>& objs);
+ void UploadDiskUBO();
+ void RenderScene();
+ void UpdatePhysics(float deltaTime);
+ void UpdateWindowDimensions();
+
+ Camera& GetCamera() { return m_Camera; }
+ const Camera& GetCamera() const { return m_Camera; }
+
+ const std::vector<ObjectData>& GetObjects() const { return m_Objects; }
+ std::vector<ObjectData>& GetObjects() { return m_Objects; }
+
+ bool GetGravity() const { return m_Gravity; }
+ void SetGravity(bool gravity) { m_Gravity = gravity; }
+
+ int GetWidth() const { return m_Width; }
+ int GetHeight() const { return m_Height; }
+ int GetComputeWidth() const { return m_ComputeWidth; }
+ int GetComputeHeight() const { return m_ComputeHeight; }
+
+ private:
+ std::string CreateBasicVertexShader();
+ std::string CreateBasicFragmentShader();
+ std::string LoadComputeShader(const std::string& path);
+ private:
+ Ref<Shader> m_GridShader;
+ Ref<Shader> m_QuadShader;
+ Ref<Shader> m_ComputeShader;
+ Ref<Texture2D> m_Texture;
+ Ref<VertexArray> m_QuadVAO;
+ Ref<VertexArray> m_GridVAO;
+ Ref<UniformBuffer> m_CameraUBO;
+ Ref<UniformBuffer> m_DiskUBO;
+ Ref<UniformBuffer> m_ObjectsUBO;
+
+ int m_GridIndexCount = 0;
+ int m_Width;
+ int m_Height;
+ int m_ComputeWidth;
+ int m_ComputeHeight;
+ float m_WidthScale = 100000000000.0f;
+ float m_HeightScale = 75000000000.0f;
+
+ std::vector<ObjectData> m_Objects;
+ BlackHole m_SagA;
+ Camera m_Camera;
+ bool m_Gravity = false;
+ };
+}
diff --git a/src/Engine/Object.cpp b/src/Engine/Object.cpp
new file mode 100644
index 0000000..8e042fd
--- /dev/null
+++ b/src/Engine/Object.cpp
@@ -0,0 +1,46 @@
+#include "Object.h"
+
+namespace Donut
+{
+ Ray::Ray(glm::vec3 o, glm::vec3 d)
+ : m_Origin(o),
+ m_Direction(glm::normalize(d)) { }
+
+ Material::Material(glm::vec3 c, float s, float e)
+ : m_Color(c),
+ m_Specular(s),
+ m_Emission(e) { }
+
+ Object::Object(glm::vec3 c, float r, Material m)
+ : m_Centre(c),
+ m_Radius(r),
+ m_Material(m) { }
+
+ bool Object::Intersect(Ray &ray, float &t)
+ {
+ glm::vec3 oc = ray.m_Origin - m_Centre;
+ float a = glm::dot(ray.m_Direction, ray.m_Direction);
+ float b = 2.0f * glm::dot(oc, ray.m_Direction);
+ float c = glm::dot(oc, oc) - m_Radius * m_Radius;
+ double discriminant = b*b - 4*a*c;
+
+ if(discriminant < 0)
+ return false;
+
+ float intercept = (-b - sqrt(discriminant)) / (2.0f*a);
+ if(intercept < 0)
+ {
+ intercept = (-b + sqrt(discriminant)) / (2.0f*a);
+ if(intercept<0)
+ return false;
+ }
+
+ t = intercept;
+ return true;
+ }
+
+ glm::vec3 Object::GetNormal(glm::vec3 &point) const
+ {
+ return glm::normalize(point - m_Centre);
+ }
+}
diff --git a/src/Engine/Object.h b/src/Engine/Object.h
new file mode 100644
index 0000000..0ae3430
--- /dev/null
+++ b/src/Engine/Object.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <glm/glm.hpp>
+
+namespace Donut
+{
+ class Ray
+ {
+ public:
+ glm::vec3 m_Direction;
+ glm::vec3 m_Origin;
+
+ Ray(glm::vec3 o, glm::vec3 d);
+ };
+
+ class Material
+ {
+ public:
+ glm::vec3 m_Color;
+ float m_Specular;
+ float m_Emission;
+
+ Material(glm::vec3 c, float s, float e);
+ };
+
+ class Object
+ {
+ public:
+ glm::vec3 m_Centre;
+ float m_Radius;
+ Material m_Material;
+
+ Object(glm::vec3 c, float r, Material m);
+
+ bool Intersect(Ray &ray, float &t);
+ glm::vec3 GetNormal(glm::vec3 &point) const;
+ };
+};
diff --git a/src/Engine/Scene.cpp b/src/Engine/Scene.cpp
new file mode 100644
index 0000000..f92dc68
--- /dev/null
+++ b/src/Engine/Scene.cpp
@@ -0,0 +1,57 @@
+#include "Scene.h"
+
+namespace Donut
+{
+ Scene::Scene()
+ : m_LightPos(5.0f, 5.0f, 5.0f) { }
+
+ glm::vec3 Scene::Trace(Ray &ray)
+ {
+ float closest = std::numeric_limits<float>::infinity();
+ const Object* hitObj = nullptr;
+
+ for(auto& obj : objs)
+ {
+ float t;
+
+ if(obj.Intersect(ray, t))
+ if(t < closest)
+ {
+ closest = t;
+ hitObj = &obj;
+ }
+ }
+
+ if(hitObj)
+ {
+ glm::vec3 hitPoint = ray.m_Origin + ray.m_Direction * closest;
+ glm::vec3 normal = hitObj->GetNormal(hitPoint);
+ glm::vec3 lightDir = glm::normalize(m_LightPos - hitPoint);
+
+ float diff = std::max(glm::dot(normal, lightDir), 0.0f);
+
+ Ray shadowRay(hitPoint + normal * 0.001f, lightDir);
+ bool inShadow = false;
+
+ for(auto& obj : objs)
+ {
+ float t;
+
+ if(obj.Intersect(shadowRay, t))
+ {
+ inShadow = true;
+ break;
+ }
+ }
+
+ glm::vec3 color = hitObj->m_Material.m_Color;
+ float ambient = 0.1f;
+
+ if (inShadow)
+ return color * ambient;
+ return color * (ambient + diff * 0.9f);
+ }
+
+ return glm::vec3(0.0f, 0.0f, 0.1f);
+ }
+}
diff --git a/src/Engine/Scene.h b/src/Engine/Scene.h
new file mode 100644
index 0000000..fa80302
--- /dev/null
+++ b/src/Engine/Scene.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <vector>
+#include <limits>
+#include <glm/glm.hpp>
+
+#include "Object.h"
+
+namespace Donut
+{
+ class Scene
+ {
+ public:
+ std::vector<Object> objs;
+ glm::vec3 m_LightPos;
+
+ Scene();
+ glm::vec3 Trace(Ray &ray);
+ };
+}; \ No newline at end of file
diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/src/Platform/OpenGL/OpenGLRendererAPI.cpp
index 3c49144..d181203 100644
--- a/src/Platform/OpenGL/OpenGLRendererAPI.cpp
+++ b/src/Platform/OpenGL/OpenGLRendererAPI.cpp
@@ -49,6 +49,11 @@ namespace Donut
glEnable(GL_DEPTH_TEST);
}
+ void OpenGLRendererAPI::DisableDepthTest()
+ {
+ glDisable(GL_DEPTH_TEST);
+ }
+
void OpenGLRendererAPI::SetFaceCulling(bool enabled)
{
if (enabled)
@@ -61,6 +66,17 @@ namespace Donut
glDisable(GL_CULL_FACE);
}
+ void OpenGLRendererAPI::EnableBlending()
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ void OpenGLRendererAPI::DisableBlending()
+ {
+ glDisable(GL_BLEND);
+ }
+
void OpenGLRendererAPI::DrawIndexed(const Ref<VertexArray>& vertexArray, uint32_t indexCount)
{
uint32_t count = indexCount ? indexCount : vertexArray->GetIndexBuffer()->GetCount();
diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.h b/src/Platform/OpenGL/OpenGLRendererAPI.h
index 97e508b..f6b9fb4 100644
--- a/src/Platform/OpenGL/OpenGLRendererAPI.h
+++ b/src/Platform/OpenGL/OpenGLRendererAPI.h
@@ -19,7 +19,10 @@ namespace Donut
virtual void SetClearColor(const glm::vec4& color) override;
virtual void Clear() override;
virtual void EnableDepthTest() override;
+ virtual void DisableDepthTest() override;
virtual void SetFaceCulling(bool enabled) override;
+ virtual void EnableBlending() override;
+ virtual void DisableBlending() override;
virtual void DrawIndexed(const Ref<VertexArray>& vertexArray,
uint32_t indexCount = 0) override;
diff --git a/src/Platform/OpenGL/OpenGLUniformBuffer.cpp b/src/Platform/OpenGL/OpenGLUniformBuffer.cpp
new file mode 100644
index 0000000..631b863
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLUniformBuffer.cpp
@@ -0,0 +1,29 @@
+#include "OpenGLUniformBuffer.h"
+
+namespace Donut
+{
+ OpenGLUniformBuffer::OpenGLUniformBuffer(uint32_t size, uint32_t binding)
+ : m_Size(size), m_Binding(binding)
+ {
+ glGenBuffers(1, &m_RendererID);
+ glBindBuffer(GL_UNIFORM_BUFFER, m_RendererID);
+ glBufferData(GL_UNIFORM_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
+ glBindBufferBase(GL_UNIFORM_BUFFER, binding, m_RendererID);
+ }
+
+ OpenGLUniformBuffer::~OpenGLUniformBuffer()
+ {
+ glDeleteBuffers(1, &m_RendererID);
+ }
+
+ void OpenGLUniformBuffer::SetData(const void* data, uint32_t size, uint32_t offset)
+ {
+ glBindBuffer(GL_UNIFORM_BUFFER, m_RendererID);
+ glBufferSubData(GL_UNIFORM_BUFFER, offset, size, data);
+ }
+
+ void OpenGLUniformBuffer::Bind(uint32_t binding)
+ {
+ glBindBufferBase(GL_UNIFORM_BUFFER, binding, m_RendererID);
+ }
+};
diff --git a/src/Platform/OpenGL/OpenGLUniformBuffer.h b/src/Platform/OpenGL/OpenGLUniformBuffer.h
new file mode 100644
index 0000000..6e7fac1
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLUniformBuffer.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "Rendering/UniformBuffer.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ class OpenGLUniformBuffer : public UniformBuffer
+ {
+ public:
+ OpenGLUniformBuffer(uint32_t size, uint32_t binding);
+ virtual ~OpenGLUniformBuffer();
+
+ virtual void SetData(const void* data, uint32_t size, uint32_t offset = 0) override;
+ virtual void Bind(uint32_t binding) override;
+
+ private:
+ uint32_t m_RendererID = 0;
+ uint32_t m_Size = 0;
+ uint32_t m_Binding = 0;
+ };
+};
diff --git a/src/Platform/Vulkan/VulkanRendererAPI.cpp b/src/Platform/Vulkan/VulkanRendererAPI.cpp
index 86d9653..6f0e73e 100644
--- a/src/Platform/Vulkan/VulkanRendererAPI.cpp
+++ b/src/Platform/Vulkan/VulkanRendererAPI.cpp
@@ -27,11 +27,26 @@ namespace Donut
// TODO(Hachem): Implement Vulkan depth test enabling
}
+ void VulkanRendererAPI::DisableDepthTest()
+ {
+ // TODO(Hachem): Implement Vulkan depth test disabling
+ }
+
void VulkanRendererAPI::SetFaceCulling(bool enabled)
{
// TODO(Hachem): Implement Vulkan face culling setting
}
+ void VulkanRendererAPI::EnableBlending()
+ {
+ // TODO(Hachem): Implement Vulkan blending enabling
+ }
+
+ void VulkanRendererAPI::DisableBlending()
+ {
+ // TODO(Hachem): Implement Vulkan blending disabling
+ }
+
void VulkanRendererAPI::DrawIndexed(const Ref<VertexArray>& vertexArray, uint32_t indexCount)
{
// TODO(Hachem): Implement Vulkan indexed drawing
diff --git a/src/Platform/Vulkan/VulkanRendererAPI.h b/src/Platform/Vulkan/VulkanRendererAPI.h
index 47342ac..8ba3942 100644
--- a/src/Platform/Vulkan/VulkanRendererAPI.h
+++ b/src/Platform/Vulkan/VulkanRendererAPI.h
@@ -15,7 +15,10 @@ namespace Donut
virtual void SetClearColor(const glm::vec4& color) override;
virtual void Clear() override;
virtual void EnableDepthTest() override;
+ virtual void DisableDepthTest() override;
virtual void SetFaceCulling(bool enabled) override;
+ virtual void EnableBlending() override;
+ virtual void DisableBlending() override;
virtual void DrawIndexed(const Ref<VertexArray>& vertexArray,
uint32_t indexCount = 0) override;
diff --git a/src/Platform/Vulkan/VulkanUniformBuffer.cpp b/src/Platform/Vulkan/VulkanUniformBuffer.cpp
new file mode 100644
index 0000000..8152478
--- /dev/null
+++ b/src/Platform/Vulkan/VulkanUniformBuffer.cpp
@@ -0,0 +1,25 @@
+#include "VulkanUniformBuffer.h"
+
+namespace Donut
+{
+ VulkanUniformBuffer::VulkanUniformBuffer(uint32_t size, uint32_t binding)
+ : m_Size(size), m_Binding(binding)
+ {
+ // TODO: Implement Vulkan uniform buffer
+ }
+
+ VulkanUniformBuffer::~VulkanUniformBuffer()
+ {
+ // TODO: Implement Vulkan uniform buffer cleanup
+ }
+
+ void VulkanUniformBuffer::SetData(const void* data, uint32_t size, uint32_t offset)
+ {
+ // TODO: Implement Vulkan uniform buffer data setting
+ }
+
+ void VulkanUniformBuffer::Bind(uint32_t binding)
+ {
+ // TODO: Implement Vulkan uniform buffer binding
+ }
+};
diff --git a/src/Platform/Vulkan/VulkanUniformBuffer.h b/src/Platform/Vulkan/VulkanUniformBuffer.h
new file mode 100644
index 0000000..a2e9ce2
--- /dev/null
+++ b/src/Platform/Vulkan/VulkanUniformBuffer.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "Rendering/UniformBuffer.h"
+
+namespace Donut
+{
+ class VulkanUniformBuffer : public UniformBuffer
+ {
+ public:
+ VulkanUniformBuffer(uint32_t size, uint32_t binding);
+ virtual ~VulkanUniformBuffer();
+
+ virtual void SetData(const void* data, uint32_t size, uint32_t offset = 0) override;
+ virtual void Bind(uint32_t binding) override;
+
+ private:
+ uint32_t m_Size = 0;
+ uint32_t m_Binding = 0;
+ };
+};
diff --git a/src/Rendering/IndexBuffer.cpp b/src/Rendering/IndexBuffer.cpp
index 185684b..dc900ed 100644
--- a/src/Rendering/IndexBuffer.cpp
+++ b/src/Rendering/IndexBuffer.cpp
@@ -6,14 +6,14 @@
namespace Donut
{
- IndexBuffer* IndexBuffer::Create(const uint32_t* indices, uint32_t count)
+ Ref<IndexBuffer> IndexBuffer::Create(const uint32_t* indices, uint32_t count)
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::OpenGL:
- return new OpenGLIndexBuffer(indices, count);
+ return CreateRef<OpenGLIndexBuffer>(indices, count);
case RendererAPI::API::Vulkan:
- return new VulkanIndexBuffer((uint32_t*)indices, count);
+ return CreateRef<VulkanIndexBuffer>((uint32_t*)indices, count);
default:
return nullptr;
}
diff --git a/src/Rendering/IndexBuffer.h b/src/Rendering/IndexBuffer.h
index a58cc6c..bb1b3a1 100644
--- a/src/Rendering/IndexBuffer.h
+++ b/src/Rendering/IndexBuffer.h
@@ -1,5 +1,6 @@
#pragma once
+#include "Core/Memory.h"
#include <cstdint>
namespace Donut
@@ -13,6 +14,6 @@ namespace Donut
virtual void Unbind() const = 0;
virtual uint32_t GetCount() const = 0;
- static IndexBuffer* Create(const uint32_t* indices, uint32_t count);
+ static Ref<IndexBuffer> Create(const uint32_t* indices, uint32_t count);
};
};
diff --git a/src/Rendering/Renderer.cpp b/src/Rendering/Renderer.cpp
index c0684cb..c1001d8 100644
--- a/src/Rendering/Renderer.cpp
+++ b/src/Rendering/Renderer.cpp
@@ -7,14 +7,14 @@
namespace Donut
{
- Scope<RendererAPI> RendererAPI::Create()
+ Ref<RendererAPI> RendererAPI::Create()
{
switch (s_API)
{
case API::OpenGL:
- return CreateScope<OpenGLRendererAPI>();
+ return CreateRef<OpenGLRendererAPI>();
case API::Vulkan:
- return CreateScope<VulkanRendererAPI>();
+ return CreateRef<VulkanRendererAPI>();
default:
return nullptr;
}
@@ -50,7 +50,7 @@ namespace Donut
RenderCommand::DrawIndexed(vertexArray);
}
- Scope<RendererAPI> RenderCommand::s_RendererAPI = RendererAPI::Create();
+ Ref<RendererAPI> RenderCommand::s_RendererAPI = RendererAPI::Create();
void Renderer::SetClearColor(const glm::vec4& color)
{
diff --git a/src/Rendering/Renderer.h b/src/Rendering/Renderer.h
index fa37fc8..b2a44a4 100644
--- a/src/Rendering/Renderer.h
+++ b/src/Rendering/Renderer.h
@@ -26,14 +26,17 @@ namespace Donut
virtual void SetClearColor(const glm::vec4& color) = 0;
virtual void Clear() = 0;
virtual void EnableDepthTest() = 0;
+ virtual void DisableDepthTest() = 0;
virtual void SetFaceCulling(bool enabled) = 0;
+ virtual void EnableBlending() = 0;
+ virtual void DisableBlending() = 0;
virtual void DrawIndexed(const Ref<VertexArray>& vertexArray,
uint32_t indexCount = 0) = 0;
inline static API GetAPI() { return s_API; }
inline static void SetAPI(API api) { s_API = api; }
- static Scope<RendererAPI> Create();
+ static Ref<RendererAPI> Create();
private:
static API s_API;
};
@@ -66,18 +69,33 @@ namespace Donut
s_RendererAPI->EnableDepthTest();
}
+ inline static void DisableDepthTest()
+ {
+ s_RendererAPI->DisableDepthTest();
+ }
+
inline static void SetFaceCulling(bool enabled)
{
s_RendererAPI->SetFaceCulling(enabled);
}
+ inline static void EnableBlending()
+ {
+ s_RendererAPI->EnableBlending();
+ }
+
+ inline static void DisableBlending()
+ {
+ s_RendererAPI->DisableBlending();
+ }
+
inline static void DrawIndexed(const Ref<VertexArray>& vertexArray, uint32_t indexCount = 0)
{
s_RendererAPI->DrawIndexed(vertexArray, indexCount);
}
private:
- static Scope<RendererAPI> s_RendererAPI;
+ static Ref<RendererAPI> s_RendererAPI;
};
class Renderer
diff --git a/src/Rendering/Shader.cpp b/src/Rendering/Shader.cpp
index 8266e00..2198663 100644
--- a/src/Rendering/Shader.cpp
+++ b/src/Rendering/Shader.cpp
@@ -6,40 +6,40 @@
namespace Donut
{
- Shader* Shader::Create(const std::string& filepath)
+ Ref<Shader> Shader::Create(const std::string& filepath)
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::OpenGL:
- return new OpenGLShader(filepath);
+ return CreateRef<OpenGLShader>(filepath);
case RendererAPI::API::Vulkan:
- return new VulkanShader(filepath);
+ return CreateRef<VulkanShader>(filepath);
default:
return nullptr;
}
}
- Shader* Shader::Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc)
+ Ref<Shader> Shader::Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc)
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::OpenGL:
- return new OpenGLShader(name, vertexSrc, fragmentSrc);
+ return CreateRef<OpenGLShader>(name, vertexSrc, fragmentSrc);
case RendererAPI::API::Vulkan:
- return new VulkanShader(name, vertexSrc, fragmentSrc);
+ return CreateRef<VulkanShader>(name, vertexSrc, fragmentSrc);
default:
return nullptr;
}
}
- Shader* Shader::CreateCompute(const std::string& name, const std::string& computeSrc)
+ Ref<Shader> Shader::CreateCompute(const std::string& name, const std::string& computeSrc)
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::OpenGL:
- return new OpenGLShader(name, computeSrc);
+ return CreateRef<OpenGLShader>(name, computeSrc);
case RendererAPI::API::Vulkan:
- return new VulkanShader(name, computeSrc);
+ return CreateRef<VulkanShader>(name, computeSrc);
default:
return nullptr;
}
@@ -58,14 +58,14 @@ namespace Donut
Ref<Shader> ShaderLibrary::Load(const std::string& filepath)
{
- auto shader = Ref<Shader>(Shader::Create(filepath));
+ auto shader = Shader::Create(filepath);
Add(shader);
return shader;
}
Ref<Shader> ShaderLibrary::Load(const std::string& name, const std::string& filepath)
{
- auto shader = Ref<Shader>(Shader::Create(filepath));
+ auto shader = Shader::Create(filepath);
Add(name, shader);
return shader;
}
diff --git a/src/Rendering/Shader.h b/src/Rendering/Shader.h
index e2d8d2a..9cfecd9 100644
--- a/src/Rendering/Shader.h
+++ b/src/Rendering/Shader.h
@@ -35,9 +35,9 @@ namespace Donut
virtual const std::string& GetName() const = 0;
- static Shader* Create(const std::string& filepath);
- static Shader* Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc);
- static Shader* CreateCompute(const std::string& name, const std::string& computeSrc);
+ static Ref<Shader> Create(const std::string& filepath);
+ static Ref<Shader> Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc);
+ static Ref<Shader> CreateCompute(const std::string& name, const std::string& computeSrc);
};
class ShaderLibrary
diff --git a/src/Rendering/UniformBuffer.cpp b/src/Rendering/UniformBuffer.cpp
new file mode 100644
index 0000000..16cf04c
--- /dev/null
+++ b/src/Rendering/UniformBuffer.cpp
@@ -0,0 +1,23 @@
+#include "UniformBuffer.h"
+#include "Renderer.h"
+
+#include "Platform/OpenGL/OpenGLUniformBuffer.h"
+#include "Platform/Vulkan/VulkanUniformBuffer.h"
+
+namespace Donut
+{
+ Ref<UniformBuffer> UniformBuffer::Create(uint32_t size, uint32_t binding)
+ {
+ switch (Renderer::GetAPI())
+ {
+ case RendererAPI::API::OpenGL:
+ return CreateRef<OpenGLUniformBuffer>(size, binding);
+ case RendererAPI::API::Vulkan:
+ return CreateRef<VulkanUniformBuffer>(size, binding);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+};
diff --git a/src/Rendering/UniformBuffer.h b/src/Rendering/UniformBuffer.h
new file mode 100644
index 0000000..ce68908
--- /dev/null
+++ b/src/Rendering/UniformBuffer.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Core/Memory.h"
+#include <cstdint>
+
+namespace Donut
+{
+ class UniformBuffer
+ {
+ public:
+ virtual ~UniformBuffer() = default;
+
+ virtual void SetData(const void* data, uint32_t size, uint32_t offset = 0) = 0;
+ virtual void Bind(uint32_t binding) = 0;
+
+ static Ref<UniformBuffer> Create(uint32_t size, uint32_t binding);
+ };
+};
diff --git a/src/Rendering/VertexArray.cpp b/src/Rendering/VertexArray.cpp
index 366675f..bca1f4a 100644
--- a/src/Rendering/VertexArray.cpp
+++ b/src/Rendering/VertexArray.cpp
@@ -17,14 +17,14 @@ namespace Donut
}
}
- VertexArray* VertexArray::Create()
+ Ref<VertexArray> VertexArray::Create()
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::OpenGL:
- return new OpenGLVertexArray();
+ return CreateRef<OpenGLVertexArray>();
case RendererAPI::API::Vulkan:
- return new VulkanVertexArray();
+ return CreateRef<VulkanVertexArray>();
default:
return nullptr;
}
diff --git a/src/Rendering/VertexArray.h b/src/Rendering/VertexArray.h
index 10fff89..aa857e4 100644
--- a/src/Rendering/VertexArray.h
+++ b/src/Rendering/VertexArray.h
@@ -23,6 +23,6 @@ namespace Donut
virtual const std::vector<Ref<VertexBuffer>>& GetVertexBuffers() const = 0;
virtual const Ref<IndexBuffer>& GetIndexBuffer() const = 0;
- static VertexArray* Create();
+ static Ref<VertexArray> Create();
};
};
diff --git a/src/Rendering/VertexBuffer.cpp b/src/Rendering/VertexBuffer.cpp
index a7e2504..dd59546 100644
--- a/src/Rendering/VertexBuffer.cpp
+++ b/src/Rendering/VertexBuffer.cpp
@@ -6,14 +6,14 @@
namespace Donut
{
- VertexBuffer* VertexBuffer::Create(const void* data, uint32_t size)
+ Ref<VertexBuffer> VertexBuffer::Create(const void* data, uint32_t size)
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::OpenGL:
- return new OpenGLVertexBuffer(data, size);
+ return CreateRef<OpenGLVertexBuffer>(data, size);
case RendererAPI::API::Vulkan:
- return new VulkanVertexBuffer((float*)data, size);
+ return CreateRef<VulkanVertexBuffer>((float*)data, size);
default:
return nullptr;
}
diff --git a/src/Rendering/VertexBuffer.h b/src/Rendering/VertexBuffer.h
index 35b9a84..db85755 100644
--- a/src/Rendering/VertexBuffer.h
+++ b/src/Rendering/VertexBuffer.h
@@ -1,5 +1,7 @@
#pragma once
+#include "Core/Memory.h"
+
#include <cstdint>
#include <vector>
@@ -22,7 +24,7 @@ namespace Donut
~VertexBufferLayout() = default;
template<typename T>
- void Push(uint32_t count)
+ void Push(uint32_t count)
{
static_assert(false);
}
@@ -68,6 +70,6 @@ namespace Donut
virtual const VertexBufferLayout& GetLayout() const = 0;
virtual void SetLayout(const VertexBufferLayout& layout) = 0;
- static VertexBuffer* Create(const void* data, uint32_t size);
+ static Ref<VertexBuffer> Create(const void* data, uint32_t size);
};
};
diff --git a/src/States/SimulationState.cpp b/src/States/SimulationState.cpp
index 349100c..4663e99 100644
--- a/src/States/SimulationState.cpp
+++ b/src/States/SimulationState.cpp
@@ -1,14 +1,18 @@
#include "SimulationState.h"
#include "Rendering/Renderer.h"
#include "Core/Application.h"
+#include "Core/Window.h"
+#include "Core/Event.h"
#include <imgui.h>
+#include <GLFW/glfw3.h>
namespace Donut
{
void SimulationState::OnEnter()
{
DONUT_INFO("Entering Simulation State");
+ m_Initialized = true;
}
void SimulationState::OnExit()
@@ -18,23 +22,79 @@ namespace Donut
void SimulationState::OnUpdate(float deltaTime)
{
+
+ m_Engine.UpdateWindowDimensions();
+ m_Engine.UpdatePhysics(deltaTime);
+
+ if (m_Engine.GetCamera().IsDragging())
+ {
+ GLFWwindow* window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
+ double xpos, ypos;
+ glfwGetCursorPos(window, &xpos, &ypos);
+ m_Engine.GetCamera().ProcessOrbitalMouseMove(xpos, ypos);
+ }
}
void SimulationState::OnRender()
{
- Renderer::SetClearColor({ 0.0f, 0.0f, 0.0f, 1.0f });
- Renderer::Clear();
+ if (!m_Initialized) return;
+
+ RenderCommand::SetClearColor(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
+ RenderCommand::Clear();
+
+ m_Engine.GenerateGrid(m_Engine.GetObjects());
+
+ glm::mat4 view = glm::lookAt(m_Engine.GetCamera().GetOrbitalPosition(), m_Engine.GetCamera().GetTarget(), glm::vec3(0,1,0));
+ glm::mat4 proj = glm::perspective(glm::radians(60.0f), float(m_Engine.GetWidth())/m_Engine.GetHeight(), 1e9f, 1e14f);
+ glm::mat4 viewProj = proj * view;
+
+ m_Engine.DrawGrid(viewProj);
+
+ RenderCommand::SetViewport(0, 0, m_Engine.GetWidth(), m_Engine.GetHeight());
+ m_Engine.DispatchCompute(m_Engine.GetCamera());
+ m_Engine.DrawFullScreenQuad();
}
void SimulationState::OnEvent(Event& event)
{
+ if (!m_Initialized) return;
+
+ if (event.GetEventType() == EventType::MouseButtonPressed)
+ {
+ MouseButtonPressedEvent& e = (MouseButtonPressedEvent&)event;
+ int button = e.GetMouseButton();
+
+ m_Engine.GetCamera().ProcessOrbitalMouseButton(button, GLFW_PRESS, 0);
+ }
+ else if (event.GetEventType() == EventType::MouseButtonReleased)
+ {
+ MouseButtonReleasedEvent& e = (MouseButtonReleasedEvent&)event;
+ int button = e.GetMouseButton();
+ m_Engine.GetCamera().ProcessOrbitalMouseButton(button, GLFW_RELEASE, 0);
+ }
+
+ if (event.GetEventType() == EventType::MouseScrolled)
+ {
+ MouseScrolledEvent& e = (MouseScrolledEvent&)event;
+ m_Engine.GetCamera().ProcessOrbitalScroll(e.GetXOffset(), e.GetYOffset());
+ }
+
+ if (event.GetEventType() == EventType::KeyPressed)
+ {
+ KeyPressedEvent& e = (KeyPressedEvent&)event;
+ if (e.GetKeyCode() == GLFW_KEY_G)
+ {
+ m_Engine.SetGravity(!m_Engine.GetGravity());
+ DONUT_INFO("Gravity turned {}", m_Engine.GetGravity() ? "ON" : "OFF");
+ }
+ }
}
void SimulationState::OnImUIRender()
{
ImGui::Begin("Simulation Controls");
- ImGui::Text("Simulation State");
+ ImGui::Text("Black Hole Simulation");
if (ImGui::Button("Back to Config"))
Application::Get().GetStateManager().SwitchToState("Config");
@@ -43,6 +103,33 @@ namespace Donut
ImGui::Text("Simulation Info:");
ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate);
ImGui::Text("Frame Time: %.3f ms", 1000.0f / ImGui::GetIO().Framerate);
+ ImGui::Text("Resolution: %dx%d", m_Engine.GetWidth(), m_Engine.GetHeight());
+ ImGui::Text("Compute Resolution: %dx%d", m_Engine.GetComputeWidth(), m_Engine.GetComputeHeight());
+ ImGui::Text("Objects: %zu", m_Engine.GetObjects().size());
+
+ ImGui::Separator();
+
+ ImGui::Text("Controls:");
+ ImGui::Text("Left Mouse: Orbit camera");
+ ImGui::Text("Scroll: Zoom in/out");
+ ImGui::Text("G: Toggle gravity");
+ ImGui::Text("Right Mouse: Enable gravity (hold)");
+
+ ImGui::Separator();
+
+ ImGui::Text("Physics:");
+ bool gravity = m_Engine.GetGravity();
+ if (ImGui::Checkbox("Gravity Enabled", &gravity))
+ m_Engine.SetGravity(gravity);
+
+ ImGui::Text("Camera:");
+ ImGui::Text("Position: (%.2e, %.2e, %.2e)",
+ m_Engine.GetCamera().GetOrbitalPosition().x,
+ m_Engine.GetCamera().GetOrbitalPosition().y,
+ m_Engine.GetCamera().GetOrbitalPosition().z);
+ ImGui::Text("Radius: %.2e", m_Engine.GetCamera().GetRadius());
+ ImGui::Text("Azimuth: %.2f", m_Engine.GetCamera().GetAzimuth());
+ ImGui::Text("Elevation: %.2f", m_Engine.GetCamera().GetElevation());
ImGui::End();
}
diff --git a/src/States/SimulationState.h b/src/States/SimulationState.h
index 3da7bd7..ba1c242 100644
--- a/src/States/SimulationState.h
+++ b/src/States/SimulationState.h
@@ -3,6 +3,8 @@
#include "Core/State.h"
#include "Core/Event.h"
#include "Core/Log.h"
+#include "Engine/Engine.h"
+#include <vector>
namespace Donut
{
@@ -18,5 +20,9 @@ namespace Donut
void OnRender() override;
void OnImUIRender() override;
void OnEvent(Event& event) override;
+
+ private:
+ Engine m_Engine;
+ bool m_Initialized = false;
};
};