diff options
33 files changed, 755 insertions, 705 deletions
diff --git a/assets/shaders/compute_texture_quad.glsl b/assets/shaders/compute_texture_quad.glsl new file mode 100644 index 0000000..1b83f8a --- /dev/null +++ b/assets/shaders/compute_texture_quad.glsl @@ -0,0 +1,27 @@ +#type vertex + +#version 330 core +layout (location = 0) in vec2 a_Pos; +layout (location = 1) in vec2 a_TexCoord; + +out vec2 v_TexCoord; + +void main() +{ + gl_Position = vec4(a_Pos, 0.0, 1.0); + v_TexCoord = a_TexCoord; +} + +#type fragment + +#version 330 core + +in vec2 v_TexCoord; +out vec4 o_FragColor; + +uniform sampler2D u_ScreenTexture; + +void main() +{ + o_FragColor = texture(u_ScreenTexture, v_TexCoord); +} diff --git a/assets/shaders/geodesic.glsl b/assets/shaders/geodesic.glsl index 6b077be..88cc2a1 100644 --- a/assets/shaders/geodesic.glsl +++ b/assets/shaders/geodesic.glsl @@ -2,16 +2,15 @@ layout(local_size_x = 16, local_size_y = 16) in; layout(binding = 0, rgba8) writeonly uniform image2D outImage; - layout(std140, binding = 1) uniform Camera { - vec3 camPos; float _pad0; - vec3 camRight; float _pad1; - vec3 camUp; float _pad2; - vec3 camForward; float _pad3; + vec3 camPos; float _pad0; + vec3 camRight; float _pad1; + vec3 camUp; float _pad2; + vec3 camForward; float _pad3; float tanHalfFov; float aspect; - bool moving; + bool moving; int _pad4; } cam; @@ -25,65 +24,83 @@ layout(std140, binding = 2) uniform Disk layout(std140, binding = 3) uniform Objects { - int numObjects; - vec4 objPosRadius[16]; - vec4 objColor[16]; - float mass[16]; + int numObjects; + vec4 objPosRadius[16]; + vec4 objColor[16]; + float mass[16]; }; -const float SagA_rs = 1.269e10; -const float D_LAMBDA = 1e7; +const float SagA_rs = 1.269e10; +const float D_LAMBDA = 1e7; const double ESCAPE_R = 1e30; +const int MAX_STEPS_MOVING = 60000; +const int MAX_STEPS_STATIC = 30000; +const float EARLY_EXIT_DISTANCE = 5e11; + vec4 objectColor = vec4(0.0); vec3 hitCenter = vec3(0.0); float hitRadius = 0.0; struct Ray { - float x, y, z, radius, theta, phi; - float dRadius, dTheta, dPhi; - float energy, angularMomentum; + float x, y, z; + float r, theta, phi; + float dr, dtheta, dphi; + float E, L; }; -Ray InitRay(vec3 position, vec3 direction) +Ray InitRay(vec3 pos, vec3 dir) { Ray ray; - ray.x = position.x; - ray.y = position.y; - ray.z = position.z; - ray.radius = length(position); - ray.theta = acos(position.z / ray.radius); - ray.phi = atan(position.y, position.x); + ray.x = pos.x; + ray.y = pos.y; + ray.z = pos.z; + ray.r = length(pos); + ray.theta = acos(pos.z / ray.r); + ray.phi = atan(pos.y, pos.x); + + float dx = dir.x; + float dy = dir.y; + float dz = dir.z; + + ray.dr = sin(ray.theta)*cos(ray.phi)*dx + + sin(ray.theta)*sin(ray.phi)*dy + + cos(ray.theta)*dz; + + ray.dtheta = (cos(ray.theta)*cos(ray.phi)*dx + + cos(ray.theta)*sin(ray.phi)*dy - + sin(ray.theta)*dz) / ray.r; - float dx = direction.x, dy = direction.y, dz = direction.z; - ray.dRadius = sin(ray.theta) * cos(ray.phi) * dx + sin(ray.theta) * sin(ray.phi) * dy + cos(ray.theta) * dz; - ray.dTheta = (cos(ray.theta) * cos(ray.phi) * dx + cos(ray.theta) * sin(ray.phi) * dy - sin(ray.theta) * dz) / ray.radius; - ray.dPhi = (-sin(ray.phi) * dx + cos(ray.phi) * dy) / (ray.radius * sin(ray.theta)); + ray.dphi = (-sin(ray.phi)*dx + cos(ray.phi)*dy) / + (ray.r * sin(ray.theta)); - ray.angularMomentum = ray.radius * ray.radius * sin(ray.theta) * ray.dPhi; - float f = 1.0 - SagA_rs / ray.radius; - float dt_dL = sqrt((ray.dRadius * ray.dRadius) / f + ray.radius * ray.radius * (ray.dTheta * ray.dTheta + sin(ray.theta) * sin(ray.theta) * ray.dPhi * ray.dPhi)); - ray.energy = f * dt_dL; + ray.L = ray.r * ray.r * sin(ray.theta) * ray.dphi; + float f = 1.0 - SagA_rs / ray.r; + float dt_dL = sqrt((ray.dr*ray.dr)/f + + ray.r*ray.r*(ray.dtheta*ray.dtheta + + sin(ray.theta)*sin(ray.theta)* + ray.dphi*ray.dphi)); + ray.E = f * dt_dL; return ray; } -bool Intercept(Ray ray, float schwarzschildRadius) +bool Intercept(Ray ray, float rs) { - return ray.radius <= schwarzschildRadius; + return ray.r <= rs; } bool InterceptObject(Ray ray) { - vec3 position = vec3(ray.x, ray.y, ray.z); + vec3 P = vec3(ray.x, ray.y, ray.z); for (int i = 0; i < numObjects; ++i) { - vec3 center = objPosRadius[i].xyz; + vec3 center = objPosRadius[i].xyz; float radius = objPosRadius[i].w; - - if (distance(position, center) <= radius) + + if (distance(P, center) <= radius) { objectColor = objColor[i]; hitCenter = center; @@ -91,75 +108,94 @@ bool InterceptObject(Ray ray) return true; } } - + return false; } -void GeodesicRHS(Ray ray, out vec3 derivatives1, out vec3 derivatives2) +void GeodesicRHS(Ray ray, out vec3 d1, out vec3 d2) { - float radius = ray.radius, theta = ray.theta; - float dRadius = ray.dRadius, dTheta = ray.dTheta, dPhi = ray.dPhi; - float f = 1.0 - SagA_rs / radius; - float dt_dL = ray.energy / f; + float r = ray.r; + float theta = ray.theta; + float dr = ray.dr; + float dtheta = ray.dtheta; + float dphi = ray.dphi; + float f = 1.0 - SagA_rs / r; + float dt_dL = ray.E / f; - derivatives1 = vec3(dRadius, dTheta, dPhi); - derivatives2.x = -(SagA_rs / (2.0 * radius * radius)) * f * dt_dL * dt_dL - + (SagA_rs / (2.0 * radius * radius * f)) * dRadius * dRadius - + radius * (dTheta * dTheta + sin(theta) * sin(theta) * dPhi * dPhi); - derivatives2.y = -2.0 * dRadius * dTheta / radius + sin(theta) * cos(theta) * dPhi * dPhi; - derivatives2.z = -2.0 * dRadius * dPhi / radius - 2.0 * cos(theta) / sin(theta) * dTheta * dPhi; + d1 = vec3(dr, dtheta, dphi); + d2.x = - (SagA_rs / (2.0 * r*r)) * f * dt_dL * dt_dL + + (SagA_rs / (2.0 * r*r * f)) * dr * dr + + r * (dtheta*dtheta + sin(theta)*sin(theta)*dphi*dphi); + d2.y = -2.0*dr*dtheta/r + sin(theta)*cos(theta)*dphi*dphi; + d2.z = -2.0*dr*dphi/r - 2.0*cos(theta)/(sin(theta)) * dtheta * dphi; } -void RK4Step(inout Ray ray, float deltaLambda) +void RK4Step(inout Ray ray, float dL) { vec3 k1a, k1b; GeodesicRHS(ray, k1a, k1b); - ray.radius += deltaLambda * k1a.x; - ray.theta += deltaLambda * k1a.y; - ray.phi += deltaLambda * k1a.z; - ray.dRadius += deltaLambda * k1b.x; - ray.dTheta += deltaLambda * k1b.y; - ray.dPhi += deltaLambda * k1b.z; + ray.r += dL * k1a.x; + ray.theta += dL * k1a.y; + ray.phi += dL * k1a.z; + ray.dr += dL * k1b.x; + ray.dtheta += dL * k1b.y; + ray.dphi += dL * k1b.z; - ray.x = ray.radius * sin(ray.theta) * cos(ray.phi); - ray.y = ray.radius * sin(ray.theta) * sin(ray.phi); - ray.z = ray.radius * cos(ray.theta); + ray.x = ray.r * sin(ray.theta) * cos(ray.phi); + ray.y = ray.r * sin(ray.theta) * sin(ray.phi); + ray.z = ray.r * cos(ray.theta); } -bool CrossesEquatorialPlane(vec3 oldPosition, vec3 newPosition) +bool CrossesEquatorialPlane(vec3 oldPos, vec3 newPos) { - bool crossed = (oldPosition.y * newPosition.y < 0.0); - float radius = length(vec2(newPosition.x, newPosition.z)); - return crossed && (radius >= disk_r1 && radius <= disk_r2); + bool crossed = (oldPos.y * newPos.y < 0.0); + float r = length(vec2(newPos.x, newPos.z)); + return crossed && (r >= disk_r1 && r <= disk_r2); } void main() { - ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); - int width = imageSize(outImage).x; - int height = imageSize(outImage).y; - - if (pixel.x >= width || pixel.y >= height) + ivec2 pix = ivec2(gl_GlobalInvocationID.xy); + int WIDTH = imageSize(outImage).x; + int HEIGHT = imageSize(outImage).y; + + if (pix.x >= WIDTH || + pix.y >= HEIGHT) return; - float u = (2.0 * (pixel.x + 0.5) / width - 1.0) * cam.aspect * cam.tanHalfFov; - float v = (1.0 - 2.0 * (pixel.y + 0.5) / height) * cam.tanHalfFov; - vec3 direction = normalize(u * cam.camRight - v * cam.camUp + cam.camForward); - Ray ray = InitRay(cam.camPos, direction); + float u = (2.0 * (pix.x + 0.5) / WIDTH - 1.0) * + cam.aspect * cam.tanHalfFov; + float v = (1.0 - 2.0 * (pix.y + 0.5) / HEIGHT) * + cam.tanHalfFov; + vec3 dir = normalize(u * cam.camRight - + v * cam.camUp + + cam.camForward); + Ray ray = InitRay(cam.camPos, dir); - vec4 color = vec4(0.0); - vec3 prevPosition = vec3(ray.x, ray.y, ray.z); - float lambda = 0.0; + vec4 color = vec4(0.0); + vec3 prevPos = vec3(ray.x, ray.y, ray.z); + float lambda = 0.0; bool hitBlackHole = false; - bool hitDisk = false; - bool hitObject = false; + bool hitDisk = false; + bool hitObject = false; - int steps = cam.moving ? 60000 : 60000; + int maxSteps = cam.moving ? MAX_STEPS_MOVING : MAX_STEPS_STATIC; + + float cameraDistance = length(cam.camPos); + if (cameraDistance > 1e12) + maxSteps = maxSteps / 4; + else if (cameraDistance > 5e11) + maxSteps = maxSteps / 2; - for (int i = 0; i < steps; ++i) + for (int i = 0; i < maxSteps; ++i) { + if (ray.r > EARLY_EXIT_DISTANCE) + break; + if (ray.r > ESCAPE_R) + break; + if (Intercept(ray, SagA_rs)) { hitBlackHole = true; @@ -169,9 +205,9 @@ void main() RK4Step(ray, D_LAMBDA); lambda += D_LAMBDA; - vec3 newPosition = vec3(ray.x, ray.y, ray.z); + vec3 newPos = vec3(ray.x, ray.y, ray.z); - if (CrossesEquatorialPlane(prevPosition, newPosition)) + if (CrossesEquatorialPlane(prevPos, newPos)) { hitDisk = true; break; @@ -183,33 +219,31 @@ void main() break; } - prevPosition = newPosition; - - if (ray.radius > ESCAPE_R) - break; + prevPos = newPos; } if (hitDisk) { - double radius = length(vec3(ray.x, ray.y, ray.z)) / disk_r2; - vec3 diskColor = vec3(1.0, radius, 0.2); - color = vec4(diskColor, radius); - } - else if (hitBlackHole) + double r = length(vec3(ray.x, ray.y, ray.z)) / disk_r2; + vec3 diskColor = vec3(1.0, r, 0.2); + color = vec4(diskColor, r); + + } else if (hitBlackHole) color = vec4(0.0, 0.0, 0.0, 1.0); else if (hitObject) { - vec3 position = vec3(ray.x, ray.y, ray.z); - vec3 normal = normalize(position - hitCenter); - vec3 viewDirection = normalize(cam.camPos - position); - float ambient = 0.1; - float diffuse = max(dot(normal, viewDirection), 0.0); - float intensity = ambient + (1.0 - ambient) * diffuse; - vec3 shaded = objectColor.rgb * intensity; + vec3 P = vec3(ray.x, ray.y, ray.z); + vec3 N = normalize(P - hitCenter); + vec3 V = normalize(cam.camPos - P); + + float ambient = 0.1; + float diff = max(dot(N, V), 0.0); + float intensity = ambient + (1.0 - ambient) * diff; + vec3 shaded = objectColor.rgb * intensity; + color = vec4(shaded, objectColor.a); - } - else + } else color = vec4(0.0); - imageStore(outImage, pixel, color); + imageStore(outImage, pix, color); } diff --git a/assets/shaders/grid.glsl b/assets/shaders/grid.glsl deleted file mode 100644 index 66096c4..0000000 --- a/assets/shaders/grid.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#type vertex -#version 330 core -layout (location = 0) in vec3 aPos; - -uniform mat4 viewProj; - -void main() -{ - gl_Position = viewProj * vec4(aPos, 1.0); -} - -#type fragment -#version 330 core -out vec4 FragColor; - -void main() -{ - FragColor = vec4(0.5, 0.5, 0.5, 0.3); -} diff --git a/assets/shaders/quad.glsl b/assets/shaders/quad.glsl deleted file mode 100644 index 57693a6..0000000 --- a/assets/shaders/quad.glsl +++ /dev/null @@ -1,25 +0,0 @@ -#type vertex -#version 330 core -layout(location = 0) in vec2 a_Pos; -layout(location = 1) in vec2 a_TexCoord; - -out vec2 v_TexCoord; - -void main() -{ - gl_Position = vec4(a_Pos.xy, 0.0, 1.0); - v_TexCoord = a_TexCoord; -} - -#type fragment -#version 330 core -out vec4 FragColor; - -in vec2 v_TexCoord; - -uniform sampler2D screenTexture; - -void main() -{ - FragColor = texture(screenTexture, v_TexCoord); -} diff --git a/src/core/camera.cpp b/src/core/camera.cpp index 43cb1ee..bba6ee2 100644 --- a/src/core/camera.cpp +++ b/src/core/camera.cpp @@ -1,6 +1,7 @@ #include "camera.h" #include <glm/gtc/quaternion.hpp> +#include <GLFW/glfw3.h> namespace Donut { @@ -50,8 +51,10 @@ namespace Donut else if (m_camera_mode == CameraMode::Orbital) { glm::vec3 position = get_orbital_position(); - glm::vec3 world_up(0.0f, 1.0f, 0.0f); - m_view_matrix = glm::lookAt(position, m_target, world_up); + glm::vec3 target = m_orbital_target; + glm::vec3 up(0.0f, 1.0f, 0.0f); + + m_view_matrix = glm::lookAt(position, target, up); m_view_projection_matrix = m_projection_matrix * m_view_matrix; } } @@ -158,76 +161,65 @@ namespace Donut } } - void Camera::set_orbital_mode(bool enabled) - { - m_camera_mode = enabled ? CameraMode::Orbital : CameraMode::FPS; - recalculate_view_matrix(); - } - glm::vec3 Camera::get_orbital_position() const { float clamped_elevation = glm::clamp(m_elevation, 0.01f, float(M_PI) - 0.01f); - return glm::vec3( - m_radius * sin(clamped_elevation) * cos(m_azimuth), - m_radius * cos(clamped_elevation), - m_radius * sin(clamped_elevation) * sin(m_azimuth) + return glm::vec3 + ( + m_orbital_radius * sin(clamped_elevation) * cos(m_azimuth), + m_orbital_radius * cos(clamped_elevation), + m_orbital_radius * sin(clamped_elevation) * sin(m_azimuth) ); } + void Camera::update_orbital() + { + m_orbital_target = glm::vec3(0.0f, 0.0f, 0.0f); + if (m_dragging || m_panning) + m_moving = true; + else + m_moving = false; + recalculate_view_matrix(); + } + void Camera::process_orbital_mouse_move(double x, double y) { - if (m_dragging && !m_panning) + if (m_dragging && !m_panning) { - float dx = float(x - m_orbital_last_x); - float dy = float(y - m_orbital_last_y); + float dx = float(x - m_last_x_orbital); + float dy = float(y - m_last_y_orbital); - m_azimuth += dx * m_orbit_speed; - m_elevation -= dy * m_orbit_speed; + m_azimuth += dx * m_orbital_speed; + m_elevation -= dy * m_orbital_speed; m_elevation = glm::clamp(m_elevation, 0.01f, float(M_PI) - 0.01f); } - m_orbital_last_x = x; - m_orbital_last_y = y; - update_orbital_state(); - recalculate_view_matrix(); + m_last_x_orbital = x; + m_last_y_orbital = y; + update_orbital(); } void Camera::process_orbital_mouse_button(int button, int action, int mods) { - if (button == GLFW_MOUSE_BUTTON_LEFT) + if (button == GLFW_MOUSE_BUTTON_LEFT) { - if (action == GLFW_PRESS) + if (action == GLFW_PRESS) { m_dragging = true; m_panning = false; - } - else if (action == GLFW_RELEASE) + } + else if (action == GLFW_RELEASE) { m_dragging = false; m_panning = false; } } - update_orbital_state(); } void Camera::process_orbital_scroll(double x_offset, double y_offset) { - m_radius -= y_offset * m_zoom_speed; - m_radius = glm::clamp(m_radius, m_min_radius, m_max_radius); - update_orbital_state(); - recalculate_view_matrix(); - } - - void Camera::update_orbital_state() - { - m_target = glm::vec3(0.0f, 0.0f, 0.0f); - if (m_dragging || m_panning) - { - m_moving = true; - } - else - { - m_moving = false; - } + m_orbital_radius -= y_offset * m_zoom_speed; + m_orbital_radius = glm::clamp(m_orbital_radius, m_orbital_min_radius, m_orbital_max_radius); + update_orbital(); } } diff --git a/src/core/camera.h b/src/core/camera.h index 7ea5472..809be48 100644 --- a/src/core/camera.h +++ b/src/core/camera.h @@ -2,7 +2,6 @@ #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> -#include <GLFW/glfw3.h> #define _USE_MATH_DEFINES #ifndef M_PI @@ -54,20 +53,23 @@ namespace Donut void set_movement_speed(float speed) { m_movement_speed = speed; } float get_movement_speed() const { return m_movement_speed; } - void set_orbital_mode(bool enabled); - bool is_orbital_mode() const { return m_camera_mode == CameraMode::Orbital; } + void set_orbital_target(const glm::vec3& target) { m_orbital_target = target; } + const glm::vec3& get_orbital_target() const { return m_orbital_target; } - void set_target(const glm::vec3& target) { m_target = target; } - const glm::vec3& get_target() const { return m_target; } + void set_orbital_radius(double radius) { m_orbital_radius = radius; } + double get_orbital_radius() const { return m_orbital_radius; } - void set_radius(double radius) { m_radius = radius; } - double get_radius() const { return m_radius; } + void set_orbital_limits(double min_radius, double max_radius) + { + m_orbital_min_radius = min_radius; + m_orbital_max_radius = max_radius; + } - void set_min_radius(double min_radius) { m_min_radius = min_radius; } - double get_min_radius() const { return m_min_radius; } + void set_orbital_speed(float speed) { m_orbital_speed = speed; } + float get_orbital_speed() const { return m_orbital_speed; } - void set_max_radius(double max_radius) { m_max_radius = max_radius; } - double get_max_radius() const { return m_max_radius; } + void set_zoom_speed(double speed) { m_zoom_speed = speed; } + double get_zoom_speed() const { return m_zoom_speed; } void set_azimuth(float azimuth) { m_azimuth = azimuth; } float get_azimuth() const { return m_azimuth; } @@ -75,30 +77,27 @@ namespace Donut void set_elevation(float elevation) { m_elevation = elevation; } float get_elevation() const { return m_elevation; } - void set_orbit_speed(float orbit_speed) { m_orbit_speed = orbit_speed; } - float get_orbit_speed() const { return m_orbit_speed; } - - void set_zoom_speed(double zoom_speed) { m_zoom_speed = zoom_speed; } - double get_zoom_speed() const { return m_zoom_speed; } - glm::vec3 get_orbital_position() const; - + void update_orbital(); void process_orbital_mouse_move(double x, double y); void process_orbital_mouse_button(int button, int action, int mods); void process_orbital_scroll(double x_offset, double y_offset); - bool is_dragging() const { return m_dragging; } - bool is_panning() const { return m_panning; } - bool is_moving() const { return m_moving; } + void set_camera_mode(CameraMode mode) { m_camera_mode = mode; } + CameraMode get_camera_mode() const { return m_camera_mode; } + + bool is_dragging() const { return m_dragging; } + bool is_panning() const { return m_panning; } + bool is_moving() const { return m_moving; } + double get_last_x() const { return m_last_x; } + double get_last_y() const { return m_last_y; } private: void recalculate_view_matrix(); void recalculate_projection_matrix(); - void update_orbital_state(); - private: CameraMode m_camera_mode = CameraMode::FPS; - + glm::mat4 m_projection_matrix; glm::mat4 m_view_matrix; glm::mat4 m_view_projection_matrix; @@ -116,19 +115,19 @@ namespace Donut bool m_first_mouse = true; float m_last_x = 0.0f; float m_last_y = 0.0f; - - glm::vec3 m_target = glm::vec3(0.0f, 0.0f, 0.0f); - double m_radius = 6.34194e10; - double m_min_radius = 1e10; - double m_max_radius = 1e12; - float m_azimuth = 0.0f; - float m_elevation = static_cast<float>(M_PI) / 2.0f; - float m_orbit_speed = 0.01f; - double m_zoom_speed = 25e9f; - bool m_dragging = false; - bool m_panning = false; - bool m_moving = false; - double m_orbital_last_x = 0.0; - double m_orbital_last_y = 0.0; + + glm::vec3 m_orbital_target = glm::vec3(0.0f, 0.0f, 0.0f); + double m_orbital_radius = 6.34194e10; + double m_orbital_min_radius = 1e10; + double m_orbital_max_radius = 1e12; + float m_azimuth = 0.0f; + float m_elevation = static_cast<float>(M_PI) / 2.0f; + float m_orbital_speed = 0.01f; + double m_zoom_speed = 25e9f; + bool m_dragging = false; + bool m_panning = false; + bool m_moving = false; + double m_last_x_orbital = 0.0; + double m_last_y_orbital = 0.0; }; } diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 29fa65a..c2a84a8 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1,251 +1,144 @@ -#include "engine.h" -#include <GLFW/glfw3.h> -#include <glad/glad.h> #include <iostream> #include <fstream> #include <sstream> -#include <limits> + +#include <GLFW/glfw3.h> + +#include "engine.h" #include "rendering/vertex_buffer.h" #include "rendering/index_buffer.h" namespace Donut { - Engine::Engine() - : m_sag_a(glm::vec3(0.0f, 0.0f, 0.0f), - static_cast<float>(8.54e36)) + Engine::Engine() + : m_sag_a(glm::vec3(0.0f, 0.0f, 0.0f), 8.54e36f) { GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); glfwGetFramebufferSize(window, &m_width, &m_height); - m_compute_height = 420; - m_compute_width = (m_width * 420) / m_height; - m_camera.set_orbital_mode(true); - m_camera.set_radius(6.34194e10); - m_camera.set_min_radius(1e10); - m_camera.set_max_radius(1e12); - m_camera.set_orbit_speed(0.01f); + m_camera.set_camera_mode(CameraMode::Orbital); + m_camera.set_orbital_radius(6.34194e10); + m_camera.set_orbital_limits(1e10, 1e12); + m_camera.set_orbital_speed(0.01f); m_camera.set_zoom_speed(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_sag_a.m_rs), glm::vec4(0,0,0,1), static_cast<float>(m_sag_a.m_mass) } + { glm::vec4(4e11f, 0.00f, 0.00f, 4e10f), glm::vec4(1, 1, 0, 1), static_cast<float>(1.98892e30) }, + { glm::vec4(0.00f, 0.00f, 4e11f, 4e10f), glm::vec4(1, 0, 0, 1), static_cast<float>(1.98892e30) }, + { glm::vec4(0.00f, 0.00f, 0.00f, m_sag_a.m_rs), glm::vec4(0, 0, 0, 1), static_cast<float>(m_sag_a.m_mass) } }; - m_quad_shader = Shader::create("assets/shaders/quad.glsl"); - m_grid_shader = Shader::create("assets/shaders/grid.glsl"); - m_compute_shader = Shader::create_compute("Geodesic", load_compute_shader("assets/shaders/geodesic.glsl")); + m_shader_program = Ref<Shader>(Shader::create("assets/shaders/compute_texture_quad.glsl")); + m_compute_program = create_compute_program("assets/shaders/geodesic.glsl"); m_camera_ubo = UniformBuffer::create(128, 1); - m_disk_ubo = UniformBuffer::create(sizeof(float) * 4, 2); + m_disk_ubo = UniformBuffer::create(sizeof(float) * 4, 2); uint32_t obj_ubo_size = sizeof(int) + 3 * sizeof(float) + 16 * (sizeof(glm::vec4) + sizeof(glm::vec4)) + 16 * sizeof(float); m_objects_ubo = UniformBuffer::create(obj_ubo_size, 3); - float quad_vertices[] = - { - -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_quad_vao = VertexArray::create(); - - auto vertex_buffer = VertexBuffer::create(quad_vertices, static_cast<uint32_t>(sizeof(quad_vertices))); - VertexBufferLayout layout; - layout.push<float>(2); - layout.push<float>(2); - vertex_buffer->set_layout(layout); - m_quad_vao->add_vertex_buffer(vertex_buffer); - - m_texture = Texture2D::create(m_width, m_height); + auto result = quad_vao(); + m_quad_vao = result.first; + m_texture = result.second; } - void Engine::generate_grid(const std::vector<ObjectData>& objects) + void Engine::update_window_dimensions() { - const int grid_size = 25; - const float spacing = 1e10f; - - std::vector<glm::vec3> vertices; - std::vector<uint32_t> indices; - - for (int z = 0; z <= grid_size; ++z) - { - for (int x = 0; x <= grid_size; ++x) - { - float world_x = (x - grid_size / 2) * spacing; - float world_z = (z - grid_size / 2) * spacing; - float y = 0.0f; - - for (const auto& obj : objects) - { - glm::vec3 obj_pos = glm::vec3(obj.m_pos_radius); - double mass = obj.m_mass; - double radius = obj.m_pos_radius.w; - - double r_s = 2.0 * G * mass / (c * c); - double dx = world_x - obj_pos.x; - double dz = world_z - obj_pos.z; - double dist = sqrt(dx * dx + dz * dz); - - if (dist > r_s) - { - double delta_y = 2.0 * sqrt(r_s * (dist - r_s)); - y += static_cast<float>(delta_y) - 3e10f; - } - else - { - y += 2.0f * static_cast<float>(sqrt(r_s * r_s)) - 3e10f; - } - } - - vertices.emplace_back(world_x, y, world_z); - } - } - - for (int z = 0; z < grid_size; ++z) - { - for (int x = 0; x < grid_size; ++x) - { - int i = z * (grid_size + 1) + x; - indices.push_back(i); - indices.push_back(i + 1); - indices.push_back(i); - indices.push_back(i + grid_size + 1); - } - } - - if (!m_grid_vao) - { - m_grid_vao = Ref<VertexArray>(VertexArray::create()); - - auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(glm::vec3)))); - VertexBufferLayout layout; - layout.push<float>(3); - vertex_buffer->set_layout(layout); - m_grid_vao->add_vertex_buffer(vertex_buffer); - - auto index_buffer = Ref<IndexBuffer>(IndexBuffer::create(indices.data(), static_cast<uint32_t>(indices.size()))); - m_grid_vao->set_index_buffer(index_buffer); - } - else - { - auto vertex_buffer = m_grid_vao->get_vertex_buffers()[0]; - vertex_buffer->set_data(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(glm::vec3))); - } - - m_grid_index_count = static_cast<int>(indices.size()); + GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); + int old_width = m_width; + int old_height = m_height; + int old_compute_height = m_compute_height; + + glfwGetFramebufferSize(window, &m_width, &m_height); + + if (old_width != m_width || + old_height != m_height || + old_compute_height != m_compute_height) + update_compute_dimensions(); } - void Engine::draw_grid(const glm::mat4& view_proj) + void Engine::update_performance(float delta_time) { - if (!m_grid_shader || !m_grid_vao) - return; - - m_grid_shader->bind(); - m_grid_shader->set_mat4("viewProj", view_proj); - - RenderCommand::disable_depth_test(); - RenderCommand::enable_blending(); - - m_grid_vao->bind(); - glDrawElements(GL_LINES, m_grid_index_count, GL_UNSIGNED_INT, nullptr); - - RenderCommand::enable_depth_test(); + if (delta_time > 0.0f) + m_current_fps = 1.0f / delta_time; } - void Engine::update_window_dimensions() + void Engine::update_compute_dimensions() { - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - int old_width = m_width; - int old_height = m_height; - glfwGetFramebufferSize(window, &m_width, &m_height); - m_compute_height = 420; - m_compute_width = (m_width * 420) / m_height; - - if (old_width != m_width || old_height != m_height) - m_texture = Texture2D::create(m_width, m_height); + m_texture = Texture2D::create(get_compute_width(), m_compute_height); } - void Engine::draw_full_screen_quad() + void Engine::draw_full_screen_quad() { RenderCommand::set_viewport(0, 0, m_width, m_height); - m_quad_shader->bind(); - std::cout << "Texture ID: " << m_texture->get_renderer_id() << ", Size: " << m_texture->get_width() << "x" << m_texture->get_height() << std::endl; + m_shader_program->bind(); + m_quad_vao->bind(); + m_texture->bind(0); - m_quad_shader->set_int("screenTexture", 0); - std::cout << "Set screenTexture uniform to slot 0\n"; + m_shader_program->set_int("u_ScreenTexture", 0); RenderCommand::disable_depth_test(); - RenderCommand::draw_indexed(m_quad_vao, 6); + RenderCommand::draw_arrays(6); RenderCommand::enable_depth_test(); } - void Engine::dispatch_compute(const Camera& cam) + void Engine::dispatch_compute(const Camera& cam) { - int cw = m_compute_width; + int cw = get_compute_width(); int ch = m_compute_height; - if (m_texture->get_width() != cw || m_texture->get_height() != ch) - m_texture = Texture2D::create(cw, ch); + m_texture->set_data(nullptr, cw * ch * 4); - m_compute_shader->bind(); + m_compute_program->bind(); upload_camera_ubo(cam); upload_disk_ubo(); upload_objects_ubo(m_objects); - m_texture->bind_as_image(0, false); - uint32_t groups_x = (uint32_t)std::ceil(cw / 16.0f); - uint32_t groups_y = (uint32_t)std::ceil(ch / 16.0f); - m_compute_shader->dispatch(groups_x, groups_y, 1); - m_compute_shader->memory_barrier(IMAGE_ACCESS_BARRIER_BIT); - - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); + uint32_t groups_x = static_cast<uint32_t>(std::ceil(cw / 16.0f)); + uint32_t groups_y = static_cast<uint32_t>(std::ceil(ch / 16.0f)); + m_compute_program->dispatch(groups_x, groups_y, 1); + m_compute_program->memory_barrier(IMAGE_ACCESS_BARRIER_BIT); } - void Engine::upload_camera_ubo(const Camera& cam) + void Engine::upload_camera_ubo(const Camera& cam) { - struct UBOData + struct UBOData { - glm::vec3 pos; float _pad0; - glm::vec3 right; float _pad1; - glm::vec3 up; float _pad2; + glm::vec3 pos; float _pad0; + glm::vec3 right; float _pad1; + glm::vec3 up; float _pad2; glm::vec3 forward; float _pad3; float tan_half_fov; float aspect; - bool moving; - int _pad4; + bool moving; + int _pad4; } data; - glm::vec3 fwd = glm::normalize(cam.get_target() - cam.get_orbital_position()); - glm::vec3 up = glm::vec3(0, 1, 0); + glm::vec3 fwd = glm::normalize(cam.get_orbital_target() - cam.get_orbital_position()); + 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.get_orbital_position(); - data.right = right; - data.up = up; - data.forward = fwd; + data.pos = cam.get_orbital_position(); + data.right = right; + data.up = up; + data.forward = fwd; data.tan_half_fov = 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.is_dragging() || cam.is_panning(); + data.aspect = static_cast<float>(get_compute_width()) / static_cast<float>(m_compute_height); + data.moving = cam.is_dragging() || cam.is_panning(); m_camera_ubo->set_data(&data, sizeof(UBOData)); + m_camera_ubo->bind(1); } - void Engine::upload_objects_ubo(const std::vector<ObjectData>& objs) + void Engine::upload_objects_ubo(const std::vector<ObjectData>& objs) { - struct UBOData + struct UBOData { int num_objects; float _pad0, _pad1, _pad2; @@ -257,7 +150,7 @@ namespace Donut size_t count = std::min(objs.size(), size_t(16)); data.num_objects = static_cast<int>(count); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { data.pos_radius[i] = objs[i].m_pos_radius; data.color[i] = objs[i].m_color; @@ -265,9 +158,10 @@ namespace Donut } m_objects_ubo->set_data(&data, sizeof(data)); + m_objects_ubo->bind(3); } - void Engine::upload_disk_ubo() + void Engine::upload_disk_ubo() { float r1 = static_cast<float>(m_sag_a.m_rs * 2.2); float r2 = static_cast<float>(m_sag_a.m_rs * 5.2); @@ -276,28 +170,28 @@ namespace Donut float disk_data[4] = { r1, r2, num, thickness }; m_disk_ubo->set_data(disk_data, sizeof(disk_data)); + m_disk_ubo->bind(2); } - void Engine::update_physics(float delta_time) + void Engine::update_physics(float delta_time) { - for (auto& obj : m_objects) + for (auto& obj : m_objects) { - for (auto& obj2 : m_objects) + for (auto& obj2 : m_objects) { if (&obj == &obj2) continue; float dx = obj2.m_pos_radius.x - obj.m_pos_radius.x; float dy = obj2.m_pos_radius.y - obj.m_pos_radius.y; float dz = obj2.m_pos_radius.z - obj.m_pos_radius.z; float distance = sqrt(dx * dx + dy * dy + dz * dz); - - if (distance > 0) + 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) + + if (m_gravity) { obj.m_velocity.x += static_cast<float>(acc[0]); obj.m_velocity.y += static_cast<float>(acc[1]); @@ -314,34 +208,49 @@ namespace Donut void Engine::render_scene() { - glm::mat4 view = glm::lookAt(m_camera.get_orbital_position(), m_camera.get_target(), glm::vec3(0,1,0)); - glm::mat4 proj = glm::perspective(glm::radians(60.0f), float(m_width)/m_height, 1e9f, 1e14f); - glm::mat4 view_proj = proj * view; - - generate_grid(m_objects); - draw_grid(view_proj); - - RenderCommand::set_viewport(0, 0, m_width, m_height); - dispatch_compute(m_camera); - draw_full_screen_quad(); + RenderCommand::clear(); + m_shader_program->bind(); + m_quad_vao->bind(); + m_texture->bind(0); + RenderCommand::draw_arrays(6); } - std::string Engine::load_compute_shader(const std::string& path) + Ref<Shader> Engine::create_compute_program(const char* path) { std::ifstream in(path); - if(!in.is_open()) + if(!in.is_open()) { std::cerr << "Failed to open compute shader: " << path << "\n"; - return ""; + return nullptr; } - 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; + std::string src_str = ss.str(); + return Ref<Shader>(Shader::create_compute("ComputeShader", src_str)); + } + + std::pair<Ref<VertexArray>, Ref<Texture2D>> Engine::quad_vao() + { + float quad_vertices[] = + { + -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 + }; + + auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(quad_vertices, static_cast<uint32_t>(sizeof(quad_vertices)))); + VertexBufferLayout layout; + layout.push<float>(2); + layout.push<float>(2); + vertex_buffer->set_layout(layout); + + auto vertex_array = Ref<VertexArray>(VertexArray::create()); + vertex_array->add_vertex_buffer(vertex_buffer); + auto texture = Texture2D::create(get_compute_width(), m_compute_height); + + return { vertex_array, texture }; } } diff --git a/src/engine/engine.h b/src/engine/engine.h index 6f90efb..39791c1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -2,10 +2,6 @@ #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> @@ -15,16 +11,27 @@ #include "core/camera.h" #include "rendering/renderer.h" #include "rendering/shader.h" -#include "rendering/texture.h" #include "rendering/vertex_array.h" +#include "rendering/texture.h" #include "rendering/uniform_buffer.h" +#include "rendering/texture_manager.h" + +#include <GLFW/glfw3.h> +#include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> +#include <glm/gtc/type_ptr.hpp> + +#define _USE_MATH_DEFINES +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif namespace Donut { const double c = 299792458.0; const double G = 6.67430e-11; - struct BlackHole + struct BlackHole { glm::vec3 m_position; double m_mass; @@ -32,13 +39,12 @@ namespace Donut double m_rs; BlackHole(glm::vec3 pos, float mass) - : m_position(pos), - m_mass(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 + 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); @@ -48,11 +54,11 @@ namespace Donut } }; - struct ObjectData + struct ObjectData { glm::vec4 m_pos_radius; glm::vec4 m_color; - float m_mass; + float m_mass; glm::vec3 m_velocity = glm::vec3(0.0f, 0.0f, 0.0f); }; @@ -62,8 +68,6 @@ namespace Donut Engine(); ~Engine() = default; - void generate_grid(const std::vector<ObjectData>& objects); - void draw_grid(const glm::mat4& view_proj); void draw_full_screen_quad(); void dispatch_compute(const Camera& cam); void upload_camera_ubo(const Camera& cam); @@ -73,46 +77,47 @@ namespace Donut void update_physics(float delta_time); void update_window_dimensions(); - Camera& get_camera() { return m_camera; } - const Camera& get_camera() const { return m_camera; } - - const std::vector<ObjectData>& get_objects() const { return m_objects; } - std::vector<ObjectData>& get_objects() { return m_objects; } - - bool get_gravity() const { return m_gravity; } - void set_gravity(bool gravity) { m_gravity = gravity; } - - int get_width() const { return m_width; } - int get_height() const { return m_height; } - int get_compute_width() const { return m_compute_width; } - int get_compute_height() const { return m_compute_height; } + int get_width() const { return m_width; } + int get_height() const { return m_height; } + + std::vector<ObjectData>& get_objects() { return m_objects; } + BlackHole& get_sag_a() { return m_sag_a; } + Camera& get_camera() { return m_camera; } + bool& get_gravity() { return m_gravity; } + void update_performance(float delta_time); + void set_target_fps(int fps) { m_target_fps = fps; } + int get_target_fps() const { return m_target_fps; } + float get_current_fps() const { return m_current_fps; } + void set_compute_height(int height) { m_compute_height = height; } + int get_compute_height() const { return m_compute_height; } + int get_compute_width() const { return (m_width * m_compute_height) / m_height; } + void update_compute_dimensions(); private: - std::string create_basic_vertex_shader(); - std::string create_basic_fragment_shader(); - std::string load_compute_shader(const std::string& path); + Ref<Shader> create_compute_program(const char* path); + std::pair<Ref<VertexArray>, Ref<Texture2D>> quad_vao(); private: - Ref<Shader> m_grid_shader; - Ref<Shader> m_quad_shader; - Ref<Shader> m_compute_shader; - Ref<Texture2D> m_texture; Ref<VertexArray> m_quad_vao; - Ref<VertexArray> m_grid_vao; + Ref<Texture2D> m_texture; + Ref<Shader> m_shader_program; + Ref<Shader> m_compute_program; Ref<UniformBuffer> m_camera_ubo; Ref<UniformBuffer> m_disk_ubo; Ref<UniformBuffer> m_objects_ubo; - - int m_grid_index_count = 0; + int m_width; int m_height; - int m_compute_width; - int m_compute_height; - float m_width_scale = 100000000000.0f; - float m_height_scale = 75000000000.0f; + float m_width_f = 100*10e10f; + float m_height_f = 75*10e10f; + + int m_target_fps = 60; + float m_current_fps = 60.0f; + float m_last_frame_time = 0.0f; + int m_compute_height = 320; std::vector<ObjectData> m_objects; BlackHole m_sag_a; Camera m_camera; bool m_gravity = false; }; -} +}; diff --git a/src/engine/object.cpp b/src/engine/object.cpp deleted file mode 100644 index 2e76b16..0000000 --- a/src/engine/object.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#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::get_normal(glm::vec3 &point) const - { - return glm::normalize(point - m_centre); - } -} diff --git a/src/engine/object.h b/src/engine/object.h index 5f5d86f..c45815b 100644 --- a/src/engine/object.h +++ b/src/engine/object.h @@ -10,7 +10,9 @@ namespace Donut glm::vec3 m_direction; glm::vec3 m_origin; - Ray(glm::vec3 o, glm::vec3 d); + Ray(glm::vec3 o, glm::vec3 d) + : m_origin(o), + m_direction(glm::normalize(d)) { } }; class Material @@ -20,7 +22,10 @@ namespace Donut float m_specular; float m_emission; - Material(glm::vec3 c, float s, float e); + Material(glm::vec3 c, float s, float e) + : m_color(c), + m_specular(s), + m_emission(e) { } }; class Object @@ -30,9 +35,37 @@ namespace Donut float m_radius; Material m_material; - Object(glm::vec3 c, float r, Material m); + Object(glm::vec3 c, float r, Material m) + : m_centre(c), + m_radius(r), + m_material(m) { } - bool intersect(Ray &ray, float &t); - glm::vec3 get_normal(glm::vec3 &point) const; + bool 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 get_normal(glm::vec3 &point) const + { + return glm::normalize(point - m_centre); + } }; }; diff --git a/src/engine/scene.cpp b/src/engine/scene.cpp deleted file mode 100644 index bfac1aa..0000000 --- a/src/engine/scene.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "scene.h" - -namespace Donut -{ - Scene::Scene() - : m_light_pos(5.0f, 5.0f, 5.0f) { } - - glm::vec3 Scene::trace(Ray &ray) - { - float closest = std::numeric_limits<float>::infinity(); - const Object* hit_obj = nullptr; - - for(auto& obj : objs) - { - float t; - - if(obj.intersect(ray, t)) - if(t < closest) - { - closest = t; - hit_obj = &obj; - } - } - - if(hit_obj) - { - glm::vec3 hit_point = ray.m_origin + ray.m_direction * closest; - glm::vec3 normal = hit_obj->get_normal(hit_point); - glm::vec3 light_dir = glm::normalize(m_light_pos - hit_point); - - float diff = std::max(glm::dot(normal, light_dir), 0.0f); - - Ray shadow_ray(hit_point + normal * 0.001f, light_dir); - bool in_shadow = false; - - for(auto& obj : objs) - { - float t; - - if(obj.intersect(shadow_ray, t)) - { - in_shadow = true; - break; - } - } - - glm::vec3 color = hit_obj->m_material.m_color; - float ambient = 0.1f; - - if (in_shadow) - 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 index abe582e..2ac9cd8 100644 --- a/src/engine/scene.h +++ b/src/engine/scene.h @@ -2,7 +2,6 @@ #include <vector> #include <limits> -#include <glm/glm.hpp> #include "object.h" @@ -14,7 +13,57 @@ namespace Donut std::vector<Object> objs; glm::vec3 m_light_pos; - Scene(); - glm::vec3 trace(Ray &ray); + Scene() + : m_light_pos(5.0f, 5.0f, 5.0f) { } + + glm::vec3 trace(Ray &ray) + { + float closest = std::numeric_limits<float>::infinity(); + const Object* hit_obj = nullptr; + + for(auto& obj : objs) + { + float t; + + if(obj.intersect(ray, t)) + if(t < closest) + { + closest = t; + hit_obj = &obj; + } + } + + if(hit_obj) + { + glm::vec3 hit_point = ray.m_origin + ray.m_direction * closest; + glm::vec3 normal = hit_obj->get_normal(hit_point); + glm::vec3 light_dir = glm::normalize(m_light_pos - hit_point); + + float diff = std::max(glm::dot(normal, light_dir), 0.0f); + + Ray shadow_ray(hit_point + normal * 0.001f, light_dir); + bool in_shadow = false; + + for(auto& obj : objs) + { + float t; + + if(obj.intersect(shadow_ray, t)) + { + in_shadow = true; + break; + } + } + + glm::vec3 color = hit_obj->m_material.m_color; + float ambient = 0.1f; + + if (in_shadow) + return color * ambient; + return color * (ambient + diff * 0.9f); + } + + return glm::vec3(0.0f, 0.0f, 0.1f); + } }; }; diff --git a/src/platform/opengl/opengl_renderer_api.cpp b/src/platform/opengl/opengl_renderer_api.cpp index 628c0af..bfb79ac 100644 --- a/src/platform/opengl/opengl_renderer_api.cpp +++ b/src/platform/opengl/opengl_renderer_api.cpp @@ -83,4 +83,27 @@ namespace Donut glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr); glBindTexture(GL_TEXTURE_2D, 0); } + + void OpenGLRendererAPI::draw_arrays(uint32_t vertex_count, uint32_t first) + { + glDrawArrays(GL_TRIANGLES, first, vertex_count); + } + + void OpenGLRendererAPI::draw_lines(const Ref<VertexArray>& vertex_array, uint32_t index_count) + { + uint32_t count = index_count ? index_count : vertex_array->get_index_buffer()->get_count(); + glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, nullptr); + } + + void OpenGLRendererAPI::bind_texture(uint32_t texture_id, uint32_t slot) + { + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_2D, texture_id); + } + + void OpenGLRendererAPI::bind_image_texture(uint32_t texture_id, uint32_t slot, bool read_only) + { + glBindImageTexture(slot, texture_id, 0, GL_FALSE, 0, + read_only ? GL_READ_ONLY : GL_WRITE_ONLY, GL_RGBA8); + } }; diff --git a/src/platform/opengl/opengl_renderer_api.h b/src/platform/opengl/opengl_renderer_api.h index fd446c6..45e6a7b 100644 --- a/src/platform/opengl/opengl_renderer_api.h +++ b/src/platform/opengl/opengl_renderer_api.h @@ -26,5 +26,15 @@ namespace Donut virtual void draw_indexed(const Ref<VertexArray>& vertex_array, uint32_t index_count = 0) override; + + virtual void draw_arrays(uint32_t vertex_count, + uint32_t first = 0) override; + virtual void draw_lines(const Ref<VertexArray>& vertex_array, + uint32_t index_count = 0) override; + virtual void bind_texture(uint32_t texture_id, + uint32_t slot = 0) override; + virtual void bind_image_texture(uint32_t texture_id, + uint32_t slot = 0, + bool read_only = false) override; }; }; diff --git a/src/platform/opengl/opengl_uniform_buffer.h b/src/platform/opengl/opengl_uniform_buffer.h index 2a9131f..ae99a56 100644 --- a/src/platform/opengl/opengl_uniform_buffer.h +++ b/src/platform/opengl/opengl_uniform_buffer.h @@ -12,11 +12,10 @@ namespace Donut virtual ~OpenGLUniformBuffer(); virtual void set_data(const void* data, uint32_t size, uint32_t offset = 0) override; - virtual void bind(uint32_t binding) override; - + virtual void bind(uint32_t binding) override; private: uint32_t m_renderer_id = 0; - uint32_t m_size = 0; - uint32_t m_binding = 0; + uint32_t m_size = 0; + uint32_t m_binding = 0; }; }; diff --git a/src/platform/vulkan/vulkan_renderer_api.cpp b/src/platform/vulkan/vulkan_renderer_api.cpp index 6273d31..8a3069e 100644 --- a/src/platform/vulkan/vulkan_renderer_api.cpp +++ b/src/platform/vulkan/vulkan_renderer_api.cpp @@ -2,43 +2,59 @@ namespace Donut { - void VulkanRendererAPI::init() - { - } + void VulkanRendererAPI::init() + { + } - void VulkanRendererAPI::set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) - { - } + void VulkanRendererAPI::set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) + { + } - void VulkanRendererAPI::set_clear_color(const glm::vec4& color) - { - } + void VulkanRendererAPI::set_clear_color(const glm::vec4& color) + { + } - void VulkanRendererAPI::clear() - { - } + void VulkanRendererAPI::clear() + { + } - void VulkanRendererAPI::enable_depth_test() - { - } + void VulkanRendererAPI::enable_depth_test() + { + } - void VulkanRendererAPI::disable_depth_test() - { - } + void VulkanRendererAPI::disable_depth_test() + { + } - void VulkanRendererAPI::set_face_culling(bool enabled) - { - } + void VulkanRendererAPI::set_face_culling(bool enabled) + { + } - void VulkanRendererAPI::enable_blending() - { - } + void VulkanRendererAPI::enable_blending() + { + } - void VulkanRendererAPI::disable_blending() - { - } + void VulkanRendererAPI::disable_blending() + { + } - void VulkanRendererAPI::draw_indexed(const Ref<VertexArray>& vertex_array, uint32_t index_count) - { - } + void VulkanRendererAPI::draw_indexed(const Ref<VertexArray>& vertex_array, uint32_t index_count) + { + } + + void VulkanRendererAPI::draw_arrays(uint32_t vertex_count, uint32_t first) + { + } + + void VulkanRendererAPI::draw_lines(const Ref<VertexArray>& vertex_array, uint32_t index_count) + { + } + + void VulkanRendererAPI::bind_texture(uint32_t texture_id, uint32_t slot) + { + } + + void VulkanRendererAPI::bind_image_texture(uint32_t texture_id, uint32_t slot, bool read_only) + { + } }; diff --git a/src/platform/vulkan/vulkan_renderer_api.h b/src/platform/vulkan/vulkan_renderer_api.h index c0075a2..e1d4566 100644 --- a/src/platform/vulkan/vulkan_renderer_api.h +++ b/src/platform/vulkan/vulkan_renderer_api.h @@ -5,22 +5,32 @@ namespace Donut { - class VulkanRendererAPI - : public RendererAPI - { - public: - virtual void init() override; - virtual void set_viewport(uint32_t x, uint32_t y, - uint32_t width, uint32_t height) override; - virtual void set_clear_color(const glm::vec4& color) override; - virtual void clear() override; - virtual void enable_depth_test() override; - virtual void disable_depth_test() override; - virtual void set_face_culling(bool enabled) override; - virtual void enable_blending() override; - virtual void disable_blending() override; + class VulkanRendererAPI + : public RendererAPI + { + public: + virtual void init() override; + virtual void set_viewport(uint32_t x, uint32_t y, + uint32_t width, uint32_t height) override; + virtual void set_clear_color(const glm::vec4& color) override; + virtual void clear() override; + virtual void enable_depth_test() override; + virtual void disable_depth_test() override; + virtual void set_face_culling(bool enabled) override; + virtual void enable_blending() override; + virtual void disable_blending() override; - virtual void draw_indexed(const Ref<VertexArray>& vertex_array, - uint32_t index_count = 0) override; - }; + virtual void draw_indexed(const Ref<VertexArray>& vertex_array, + uint32_t index_count = 0) override; + + virtual void draw_arrays(uint32_t vertex_count, + uint32_t first = 0) override; + virtual void draw_lines(const Ref<VertexArray>& vertex_array, + uint32_t index_count = 0) override; + virtual void bind_texture(uint32_t texture_id, + uint32_t slot = 0) override; + virtual void bind_image_texture(uint32_t texture_id, + uint32_t slot = 0, + bool read_only = false) override; + }; }; diff --git a/src/platform/vulkan/vulkan_uniform_buffer.h b/src/platform/vulkan/vulkan_uniform_buffer.h index e3c9196..8dd7686 100644 --- a/src/platform/vulkan/vulkan_uniform_buffer.h +++ b/src/platform/vulkan/vulkan_uniform_buffer.h @@ -11,10 +11,9 @@ namespace Donut virtual ~VulkanUniformBuffer(); virtual void set_data(const void* data, uint32_t size, uint32_t offset = 0) override; - virtual void bind(uint32_t binding) override; - + virtual void bind(uint32_t binding) override; private: - uint32_t m_size = 0; - uint32_t m_binding = 0; + uint32_t m_size; + uint32_t m_binding; }; }; diff --git a/src/rendering/index_buffer.cpp b/src/rendering/index_buffer.cpp index 3271a5a..1095e3b 100644 --- a/src/rendering/index_buffer.cpp +++ b/src/rendering/index_buffer.cpp @@ -6,14 +6,14 @@ namespace Donut { - Ref<IndexBuffer> IndexBuffer::create(const uint32_t* indices, uint32_t count) + IndexBuffer* IndexBuffer::create(const uint32_t* indices, uint32_t count) { switch (Renderer::get_api()) { case RendererAPI::API::OpenGL: - return create_ref<OpenGLIndexBuffer>(indices, count); + return new OpenGLIndexBuffer(indices, count); case RendererAPI::API::Vulkan: - return create_ref<VulkanIndexBuffer>((uint32_t*)indices, count); + return new VulkanIndexBuffer((uint32_t*)indices, count); default: return nullptr; } diff --git a/src/rendering/index_buffer.h b/src/rendering/index_buffer.h index 9859c20..856559a 100644 --- a/src/rendering/index_buffer.h +++ b/src/rendering/index_buffer.h @@ -1,6 +1,5 @@ #pragma once -#include "core/memory.h" #include <cstdint> namespace Donut @@ -14,6 +13,6 @@ namespace Donut virtual void unbind() const = 0; virtual uint32_t get_count() const = 0; - static Ref<IndexBuffer> create(const uint32_t* indices, uint32_t count); + static IndexBuffer* create(const uint32_t* indices, uint32_t count); }; }; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index f34e2b0..5e4682c 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -7,14 +7,14 @@ namespace Donut { - Ref<RendererAPI> RendererAPI::create() + Scope<RendererAPI> RendererAPI::create() { switch (s_api) { case API::OpenGL: - return create_ref<OpenGLRendererAPI>(); + return create_scope<OpenGLRendererAPI>(); case API::Vulkan: - return create_ref<VulkanRendererAPI>(); + return create_scope<VulkanRendererAPI>(); default: return nullptr; } @@ -50,7 +50,7 @@ namespace Donut RenderCommand::draw_indexed(vertex_array); } - Ref<RendererAPI> RenderCommand::s_renderer_api = RendererAPI::create(); + Scope<RendererAPI> RenderCommand::s_renderer_api = RendererAPI::create(); void Renderer::set_clear_color(const glm::vec4& color) { diff --git a/src/rendering/renderer.h b/src/rendering/renderer.h index 4a028e5..67ad998 100644 --- a/src/rendering/renderer.h +++ b/src/rendering/renderer.h @@ -20,23 +20,31 @@ namespace Donut public: virtual ~RendererAPI() = default; - virtual void init() = 0; + virtual void init() = 0; virtual void set_viewport(uint32_t x, uint32_t y, - uint32_t width, uint32_t height) = 0; - virtual void set_clear_color(const glm::vec4& color) = 0; - virtual void clear() = 0; - virtual void enable_depth_test() = 0; - virtual void disable_depth_test() = 0; - virtual void set_face_culling(bool enabled) = 0; - virtual void enable_blending() = 0; - virtual void disable_blending() = 0; + uint32_t width, uint32_t height) = 0; + virtual void set_clear_color(const glm::vec4& color) = 0; + virtual void clear() = 0; + virtual void enable_depth_test() = 0; + virtual void disable_depth_test() = 0; + virtual void set_face_culling(bool enabled) = 0; + virtual void enable_blending() = 0; + virtual void disable_blending() = 0; virtual void draw_indexed(const Ref<VertexArray>& vertex_array, - uint32_t index_count = 0) = 0; + uint32_t index_count = 0) = 0; + + virtual void draw_arrays(uint32_t vertex_count, uint32_t first = 0) = 0; + virtual void draw_lines(const Ref<VertexArray>& vertex_array, + uint32_t index_count = 0) = 0; + virtual void bind_texture(uint32_t texture_id, uint32_t slot = 0) = 0; + virtual void bind_image_texture(uint32_t texture_id, + uint32_t slot = 0, + bool read_only = false) = 0; inline static API get_api() { return s_api; } inline static void set_api(API api) { s_api = api; } - static Ref<RendererAPI> create(); + static Scope<RendererAPI> create(); private: static API s_api; }; @@ -94,8 +102,28 @@ namespace Donut s_renderer_api->draw_indexed(vertex_array, index_count); } + inline static void draw_arrays(uint32_t vertex_count, uint32_t first = 0) + { + s_renderer_api->draw_arrays(vertex_count, first); + } + + inline static void draw_lines(const Ref<VertexArray>& vertex_array, uint32_t index_count = 0) + { + s_renderer_api->draw_lines(vertex_array, index_count); + } + + inline static void bind_texture(uint32_t texture_id, uint32_t slot = 0) + { + s_renderer_api->bind_texture(texture_id, slot); + } + + inline static void bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) + { + s_renderer_api->bind_image_texture(texture_id, slot, read_only); + } + private: - static Ref<RendererAPI> s_renderer_api; + static Scope<RendererAPI> s_renderer_api; }; class Renderer diff --git a/src/rendering/shader.cpp b/src/rendering/shader.cpp index 833b719..1bbd0fc 100644 --- a/src/rendering/shader.cpp +++ b/src/rendering/shader.cpp @@ -6,40 +6,40 @@ namespace Donut { - Ref<Shader> Shader::create(const std::string& filepath) + Shader* Shader::create(const std::string& filepath) { switch (Renderer::get_api()) { case RendererAPI::API::OpenGL: - return create_ref<OpenGLShader>(filepath); + return new OpenGLShader(filepath); case RendererAPI::API::Vulkan: - return create_ref<VulkanShader>(filepath); + return new VulkanShader(filepath); default: return nullptr; } } - Ref<Shader> Shader::create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) + Shader* Shader::create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) { switch (Renderer::get_api()) { case RendererAPI::API::OpenGL: - return create_ref<OpenGLShader>(name, vertex_src, fragment_src); + return new OpenGLShader(name, vertex_src, fragment_src); case RendererAPI::API::Vulkan: - return create_ref<VulkanShader>(name, vertex_src, fragment_src); + return new VulkanShader(name, vertex_src, fragment_src); default: return nullptr; } } - Ref<Shader> Shader::create_compute(const std::string& name, const std::string& compute_src) + Shader* Shader::create_compute(const std::string& name, const std::string& compute_src) { switch (Renderer::get_api()) { case RendererAPI::API::OpenGL: - return create_ref<OpenGLShader>(name, compute_src); + return new OpenGLShader(name, compute_src); case RendererAPI::API::Vulkan: - return create_ref<VulkanShader>(name, compute_src); + return new VulkanShader(name, compute_src); default: return nullptr; } @@ -58,14 +58,14 @@ namespace Donut Ref<Shader> ShaderLibrary::load(const std::string& filepath) { - auto shader = Shader::create(filepath); + auto shader = Ref<Shader>(Shader::create(filepath)); add(shader); return shader; } Ref<Shader> ShaderLibrary::load(const std::string& name, const std::string& filepath) { - auto shader = Shader::create(filepath); + auto shader = Ref<Shader>(Shader::create(filepath)); add(name, shader); return shader; } diff --git a/src/rendering/shader.h b/src/rendering/shader.h index 7f024bd..814f0cf 100644 --- a/src/rendering/shader.h +++ b/src/rendering/shader.h @@ -35,9 +35,9 @@ namespace Donut virtual const std::string& get_name() const = 0; - static Ref<Shader> create(const std::string& filepath); - static Ref<Shader> create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src); - static Ref<Shader> create_compute(const std::string& name, const std::string& compute_src); + static Shader* create(const std::string& filepath); + static Shader* create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src); + static Shader* create_compute(const std::string& name, const std::string& compute_src); }; class ShaderLibrary diff --git a/src/rendering/texture_manager.cpp b/src/rendering/texture_manager.cpp new file mode 100644 index 0000000..fff5dda --- /dev/null +++ b/src/rendering/texture_manager.cpp @@ -0,0 +1,34 @@ +#include "texture_manager.h" +#include "platform/opengl/opengl_texture.h" +#include "platform/opengl/opengl_renderer_api.h" +#include <glad/glad.h> + +namespace Donut +{ + Ref<Texture2D> TextureManager::create_texture(uint32_t width, uint32_t height) + { + return create_ref<OpenGLTexture2D>(width, height); + } + + void TextureManager::bind_texture(uint32_t texture_id, uint32_t slot) + { + RenderCommand::bind_texture(texture_id, slot); + } + + void TextureManager::bind_image_texture(uint32_t texture_id, uint32_t slot, bool read_only) + { + RenderCommand::bind_image_texture(texture_id, slot, read_only); + } + + void TextureManager::set_texture_data(uint32_t texture_id, void* data, uint32_t width, uint32_t height) + { + glBindTexture(GL_TEXTURE_2D, texture_id); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); + } + + void TextureManager::resize_texture(uint32_t texture_id, uint32_t width, uint32_t height) + { + glBindTexture(GL_TEXTURE_2D, texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + } +}; diff --git a/src/rendering/texture_manager.h b/src/rendering/texture_manager.h new file mode 100644 index 0000000..902a27d --- /dev/null +++ b/src/rendering/texture_manager.h @@ -0,0 +1,19 @@ +#pragma once + +#include "core/memory.h" +#include "rendering/texture.h" +#include <cstdint> + +namespace Donut +{ + class TextureManager + { + public: + static Ref<Texture2D> create_texture(uint32_t width, uint32_t height); + + static void bind_texture(uint32_t texture_id, uint32_t slot = 0); + static void bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false); + static void set_texture_data(uint32_t texture_id, void* data, uint32_t width, uint32_t height); + static void resize_texture(uint32_t texture_id, uint32_t width, uint32_t height); + }; +}; diff --git a/src/rendering/vertex_array.cpp b/src/rendering/vertex_array.cpp index d0cd4b0..bb92ff3 100644 --- a/src/rendering/vertex_array.cpp +++ b/src/rendering/vertex_array.cpp @@ -17,14 +17,14 @@ namespace Donut } } - Ref<VertexArray> VertexArray::create() + VertexArray* VertexArray::create() { switch (Renderer::get_api()) { case RendererAPI::API::OpenGL: - return create_ref<OpenGLVertexArray>(); + return new OpenGLVertexArray(); case RendererAPI::API::Vulkan: - return create_ref<VulkanVertexArray>(); + return new VulkanVertexArray(); default: return nullptr; } diff --git a/src/rendering/vertex_array.h b/src/rendering/vertex_array.h index 3729167..a39849f 100644 --- a/src/rendering/vertex_array.h +++ b/src/rendering/vertex_array.h @@ -23,6 +23,6 @@ namespace Donut virtual const std::vector<Ref<VertexBuffer>>& get_vertex_buffers() const = 0; virtual const Ref<IndexBuffer>& get_index_buffer() const = 0; - static Ref<VertexArray> create(); + static VertexArray* create(); }; }; diff --git a/src/rendering/vertex_buffer.cpp b/src/rendering/vertex_buffer.cpp index ef2b288..4929711 100644 --- a/src/rendering/vertex_buffer.cpp +++ b/src/rendering/vertex_buffer.cpp @@ -6,14 +6,14 @@ namespace Donut { - Ref<VertexBuffer> VertexBuffer::create(const void* data, uint32_t size) + VertexBuffer* VertexBuffer::create(const void* data, uint32_t size) { switch (Renderer::get_api()) { case RendererAPI::API::OpenGL: - return create_ref<OpenGLVertexBuffer>(data, size); + return new OpenGLVertexBuffer(data, size); case RendererAPI::API::Vulkan: - return create_ref<VulkanVertexBuffer>((float*)data, size); + return new VulkanVertexBuffer((float*)data, size); default: return nullptr; } diff --git a/src/rendering/vertex_buffer.h b/src/rendering/vertex_buffer.h index 39f43ba..77a76c9 100644 --- a/src/rendering/vertex_buffer.h +++ b/src/rendering/vertex_buffer.h @@ -1,7 +1,5 @@ #pragma once -#include "core/memory.h" - #include <cstdint> #include <vector> @@ -24,7 +22,7 @@ namespace Donut ~VertexBufferLayout() = default; template<typename T> - void push(uint32_t count) + void push(uint32_t count) { static_assert(false); } @@ -70,6 +68,6 @@ namespace Donut virtual const VertexBufferLayout& get_layout() const = 0; virtual void set_layout(const VertexBufferLayout& layout) = 0; - static Ref<VertexBuffer> create(const void* data, uint32_t size); + static VertexBuffer* create(const void* data, uint32_t size); }; }; diff --git a/src/states/config_state.cpp b/src/states/config_state.cpp index 403f667..d29408b 100644 --- a/src/states/config_state.cpp +++ b/src/states/config_state.cpp @@ -22,7 +22,7 @@ namespace Donut void ConfigState::on_render() { - Renderer::set_clear_color({ 0.1f, 0.1f, 0.2f, 1.0f }); + Renderer::set_clear_color({ 0.1f, 0.1f, 0.1f, 1.0f }); Renderer::clear(); } diff --git a/src/states/simulation_state.cpp b/src/states/simulation_state.cpp index fc235ff..e59f1fa 100644 --- a/src/states/simulation_state.cpp +++ b/src/states/simulation_state.cpp @@ -22,11 +22,11 @@ namespace Donut void SimulationState::on_update(float delta_time) { - + m_engine.update_performance(delta_time); m_engine.update_window_dimensions(); m_engine.update_physics(delta_time); - - if (m_engine.get_camera().is_dragging()) + + if (m_engine.get_camera().is_dragging()) { GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); double xpos, ypos; @@ -37,34 +37,28 @@ namespace Donut void SimulationState::on_render() { - if (!m_initialized) return; - RenderCommand::set_clear_color(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); RenderCommand::clear(); - - m_engine.generate_grid(m_engine.get_objects()); - - glm::mat4 view = glm::lookAt(m_engine.get_camera().get_orbital_position(), m_engine.get_camera().get_target(), glm::vec3(0,1,0)); - glm::mat4 proj = glm::perspective(glm::radians(60.0f), float(m_engine.get_width())/m_engine.get_height(), 1e9f, 1e14f); - glm::mat4 view_proj = proj * view; - - m_engine.draw_grid(view_proj); - RenderCommand::set_viewport(0, 0, m_engine.get_width(), m_engine.get_height()); + m_engine.dispatch_compute(m_engine.get_camera()); m_engine.draw_full_screen_quad(); } void SimulationState::on_event(Event& event) { - if (!m_initialized) return; - if (event.get_event_type() == EventType::MouseButtonPressed) { MouseButtonPressedEvent& e = (MouseButtonPressedEvent&)event; int button = e.get_mouse_button(); - m_engine.get_camera().process_orbital_mouse_button(button, GLFW_PRESS, 0); + GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); + Camera& camera = m_engine.get_camera(); + double last_x = camera.get_last_x(); + double last_y = camera.get_last_y(); + glfwGetCursorPos(window, &last_x, &last_y); + + camera.process_orbital_mouse_button(button, GLFW_PRESS, 0); } else if (event.get_event_type() == EventType::MouseButtonReleased) { @@ -84,7 +78,7 @@ namespace Donut KeyPressedEvent& e = (KeyPressedEvent&)event; if (e.get_key_code() == GLFW_KEY_G) { - m_engine.set_gravity(!m_engine.get_gravity()); + m_engine.get_gravity() = !m_engine.get_gravity(); DONUT_INFO("Gravity turned {}", m_engine.get_gravity() ? "ON" : "OFF"); } } @@ -109,6 +103,27 @@ namespace Donut ImGui::Separator(); + ImGui::Text("Performance:"); + ImGui::Text("Engine FPS: %.1f", m_engine.get_current_fps()); + ImGui::Text("Target FPS: %d", m_engine.get_target_fps()); + + int target_fps = m_engine.get_target_fps(); + if (ImGui::SliderInt("Target FPS", &target_fps, 30, 120)) + { + m_engine.set_target_fps(target_fps); + } + + int compute_height = m_engine.get_compute_height(); + if (ImGui::SliderInt("Compute Height", &compute_height, 64, 2048)) + { + m_engine.set_compute_height(compute_height); + m_engine.update_compute_dimensions(); + } + + ImGui::Text("Compute Width: %d (auto-calculated)", m_engine.get_compute_width()); + + ImGui::Separator(); + ImGui::Text("Controls:"); ImGui::Text("Left Mouse: Orbit camera"); ImGui::Text("Scroll: Zoom in/out"); @@ -118,16 +133,15 @@ namespace Donut ImGui::Separator(); ImGui::Text("Physics:"); - bool gravity = m_engine.get_gravity(); - if (ImGui::Checkbox("Gravity Enabled", &gravity)) - m_engine.set_gravity(gravity); + bool& gravity = m_engine.get_gravity(); + ImGui::Checkbox("Gravity Enabled", &gravity); ImGui::Text("Camera:"); ImGui::Text("Position: (%.2e, %.2e, %.2e)", m_engine.get_camera().get_orbital_position().x, m_engine.get_camera().get_orbital_position().y, m_engine.get_camera().get_orbital_position().z); - ImGui::Text("Radius: %.2e", m_engine.get_camera().get_radius()); + ImGui::Text("Radius: %.2e", m_engine.get_camera().get_orbital_radius()); ImGui::Text("Azimuth: %.2f", m_engine.get_camera().get_azimuth()); ImGui::Text("Elevation: %.2f", m_engine.get_camera().get_elevation()); diff --git a/src/states/simulation_state.h b/src/states/simulation_state.h index 68788e8..cc55901 100644 --- a/src/states/simulation_state.h +++ b/src/states/simulation_state.h @@ -23,6 +23,6 @@ namespace Donut private: Engine m_engine; - bool m_initialized = false; + bool m_initialized = false; }; }; |
