diff options
Diffstat (limited to 'src')
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; }; }; |
