diff options
39 files changed, 1427 insertions, 302 deletions
diff --git a/Assets/Shaders/Basic.glsl b/Assets/Shaders/Basic.glsl deleted file mode 100644 index f6016f7..0000000 --- a/Assets/Shaders/Basic.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#type vertex -#version 330 core - -layout(location = 0) in vec3 a_Position; -layout(location = 1) in vec4 a_Color; - -uniform mat4 u_ViewProjection; -uniform mat4 u_Transform; - -out vec3 v_Position; -out vec4 v_Color; - -void main() -{ - v_Position = a_Position; - v_Color = a_Color; - gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0); -} - -#type fragment -#version 330 core - -layout(location = 0) out vec4 color; - -in vec3 v_Position; -in vec4 v_Color; - -void main() -{ - color = v_Color; -} diff --git a/Assets/Shaders/Compute.glsl b/Assets/Shaders/Compute.glsl deleted file mode 100644 index 9a36a84..0000000 --- a/Assets/Shaders/Compute.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#type compute -#version 430 core - -layout(local_size_x = 256) in; - -layout(std430, binding = 0) buffer InputBuffer -{ - float data[]; -} inputBuffer; - -layout(std430, binding = 1) buffer OutputBuffer -{ - float data[]; -} outputBuffer; - -uniform float u_Scale; -uniform float u_Offset; - -void main() -{ - uint index = gl_GlobalInvocationID.x; - float inputValue = inputBuffer.data[index]; - outputBuffer.data[index] = inputValue * u_Scale + u_Offset; -} diff --git a/Assets/Shaders/Geodesic.glsl b/Assets/Shaders/Geodesic.glsl new file mode 100644 index 0000000..c44b58d --- /dev/null +++ b/Assets/Shaders/Geodesic.glsl @@ -0,0 +1,215 @@ +#version 430 +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; + float tanHalfFov; + float aspect; + bool moving; + int _pad4; +} cam; + +layout(std140, binding = 2) uniform Disk +{ + float disk_r1; + float disk_r2; + float disk_num; + float thickness; +}; + +layout(std140, binding = 3) uniform Objects +{ + int numObjects; + vec4 objPosRadius[16]; + vec4 objColor[16]; + float mass[16]; +}; + +const float SagA_rs = 1.269e10; +const float D_LAMBDA = 1e7; +const double ESCAPE_R = 1e30; + +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; +}; + +Ray InitRay(vec3 position, vec3 direction) +{ + 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); + + 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.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; + + return ray; +} + +bool Intercept(Ray ray, float schwarzschildRadius) +{ + return ray.radius <= schwarzschildRadius; +} + +bool InterceptObject(Ray ray) +{ + vec3 position = vec3(ray.x, ray.y, ray.z); + + for (int i = 0; i < numObjects; ++i) + { + vec3 center = objPosRadius[i].xyz; + float radius = objPosRadius[i].w; + + if (distance(position, center) <= radius) + { + objectColor = objColor[i]; + hitCenter = center; + hitRadius = radius; + return true; + } + } + + return false; +} + +void GeodesicRHS(Ray ray, out vec3 derivatives1, out vec3 derivatives2) +{ + 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; + + 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; +} + +void RK4Step(inout Ray ray, float deltaLambda) +{ + 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.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); +} + +bool CrossesEquatorialPlane(vec3 oldPosition, vec3 newPosition) +{ + bool crossed = (oldPosition.y * newPosition.y < 0.0); + float radius = length(vec2(newPosition.x, newPosition.z)); + return crossed && (radius >= disk_r1 && radius <= 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) + 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); + + vec4 color = vec4(0.0); + vec3 prevPosition = vec3(ray.x, ray.y, ray.z); + float lambda = 0.0; + + bool hitBlackHole = false; + bool hitDisk = false; + bool hitObject = false; + + int steps = cam.moving ? 60000 : 60000; + + for (int i = 0; i < steps; ++i) + { + if (Intercept(ray, SagA_rs)) + { + hitBlackHole = true; + break; + } + + RK4Step(ray, D_LAMBDA); + lambda += D_LAMBDA; + + vec3 newPosition = vec3(ray.x, ray.y, ray.z); + + if (CrossesEquatorialPlane(prevPosition, newPosition)) + { + hitDisk = true; + break; + } + + if (InterceptObject(ray)) + { + hitObject = true; + break; + } + + prevPosition = newPosition; + + if (ray.radius > ESCAPE_R) + break; + } + + 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) + 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; + color = vec4(shaded, objectColor.a); + } + else + color = vec4(0.0); + + imageStore(outImage, pixel, color); +}
\ No newline at end of file diff --git a/Assets/Shaders/Grid.glsl b/Assets/Shaders/Grid.glsl new file mode 100644 index 0000000..66096c4 --- /dev/null +++ b/Assets/Shaders/Grid.glsl @@ -0,0 +1,19 @@ +#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/ImageProcessing.glsl b/Assets/Shaders/ImageProcessing.glsl deleted file mode 100644 index 3a05425..0000000 --- a/Assets/Shaders/ImageProcessing.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#type compute -#version 430 core - -layout(local_size_x = 16, local_size_y = 16) in; - -layout(binding = 0) uniform sampler2D u_InputTexture; -layout(binding = 1, rgba8) uniform image2D u_OutputTexture; - -uniform vec2 u_TextureSize; -uniform float u_Brightness; -uniform float u_Contrast; -uniform float u_Saturation; - -void main() -{ - ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); - - if (pixelCoord.x >= int(u_TextureSize.x) || pixelCoord.y >= int(u_TextureSize.y)) - return; - - vec2 texCoord = (vec2(pixelCoord) + 0.5) / u_TextureSize; - vec4 color = texture(u_InputTexture, texCoord); - - color.rgb = (color.rgb - 0.5) * u_Contrast + 0.5 + u_Brightness; - - float luminance = dot(color.rgb, vec3(0.299, 0.587, 0.114)); - color.rgb = mix(vec3(luminance), color.rgb, u_Saturation); - color.rgb = clamp(color.rgb, 0.0, 1.0); - - imageStore(u_OutputTexture, pixelCoord, color); -} diff --git a/Assets/Shaders/ParticleSystem.glsl b/Assets/Shaders/ParticleSystem.glsl deleted file mode 100644 index d40726d..0000000 --- a/Assets/Shaders/ParticleSystem.glsl +++ /dev/null @@ -1,58 +0,0 @@ -#type compute -#version 430 core - -layout(local_size_x = 256) in; - -struct Particle -{ - vec4 position; // xyz = position, w = lifetime - vec4 velocity; // xyz = velocity, w = mass - vec4 color; // rgba = color -}; - -layout(std430, binding = 0) buffer ParticleBuffer -{ - Particle particles[]; -} particleBuffer; - -uniform float u_DeltaTime; -uniform vec3 u_Gravity; -uniform vec3 u_EmitterPosition; -uniform float u_EmissionRate; -uniform float u_ParticleLifetime; -uniform float u_Time; - -void main() -{ - uint index = gl_GlobalInvocationID.x; - - if (index >= particles.length()) - return; - - Particle particle = particleBuffer.particles[index]; - - particle.position.w -= u_DeltaTime; - - if (particle.position.w <= 0.0) - { - particle.position.xyz = u_EmitterPosition; - particle.position.w = u_ParticleLifetime; - - float angle = fract(sin(dot(vec2(index, u_Time), vec2(12.9898, 78.233))) * 43758.5453) * 2.0 * 3.14159; - float speed = 2.0 + fract(sin(dot(vec2(index + 1, u_Time), vec2(12.9898, 78.233))) * 43758.5453) * 3.0; - particle.velocity.xyz = vec3(cos(angle) * speed, 5.0, sin(angle) * speed); - particle.velocity.w = 1.0; - - particle.color = vec4(1.0, 0.5 + 0.5 * fract(sin(index * 123.456) * 43758.5453), 0.2, 1.0); - } - else - { - particle.velocity.xyz += u_Gravity * u_DeltaTime; - particle.position.xyz += particle.velocity.xyz * u_DeltaTime; - - float lifeRatio = particle.position.w / u_ParticleLifetime; - particle.color.a = lifeRatio; - } - - particleBuffer.particles[index] = particle; -} diff --git a/Assets/Shaders/Quad.glsl b/Assets/Shaders/Quad.glsl new file mode 100644 index 0000000..57693a6 --- /dev/null +++ b/Assets/Shaders/Quad.glsl @@ -0,0 +1,25 @@ +#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/Assets/Shaders/TextureProcessor.glsl b/Assets/Shaders/TextureProcessor.glsl deleted file mode 100644 index a234ac8..0000000 --- a/Assets/Shaders/TextureProcessor.glsl +++ /dev/null @@ -1,43 +0,0 @@ -#type compute -#version 430 core - -layout(local_size_x = 16, local_size_y = 16) in; - -layout(binding = 0) uniform sampler2D u_InputTexture; -layout(binding = 1, rgba8) uniform image2D u_OutputTexture; - -uniform vec2 u_TextureSize; -uniform float u_Time; -uniform float u_Brightness; -uniform float u_Contrast; -uniform float u_Saturation; - -void main() -{ - ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); - - if (pixelCoord.x >= int(u_TextureSize.x) || pixelCoord.y >= int(u_TextureSize.y)) - return; - - vec2 texCoord = (vec2(pixelCoord) + 0.5) / u_TextureSize; - vec4 color = texture(u_InputTexture, texCoord); - - float time = u_Time * 2.0f; - float u = texCoord.x; - float v = texCoord.y; - - float wave = sin(u * 10.0f + time) * cos(v * 10.0f + time * 0.5f); - wave = (wave + 1.0f) * 0.5f; - - vec4 animatedColor = vec4(wave, 1.0f - wave, (u + v) * 0.5f, 1.0f); - color = mix(color, animatedColor, 0.3f); - - color.rgb = (color.rgb - 0.5) * u_Contrast + 0.5 + u_Brightness; - - float luminance = dot(color.rgb, vec3(0.299, 0.587, 0.114)); - color.rgb = mix(vec3(luminance), color.rgb, u_Saturation); - - color.rgb = clamp(color.rgb, 0.0, 1.0); - - imageStore(u_OutputTexture, pixelCoord, color); -} diff --git a/Assets/Shaders/Textured.glsl b/Assets/Shaders/Textured.glsl deleted file mode 100644 index ad135fe..0000000 --- a/Assets/Shaders/Textured.glsl +++ /dev/null @@ -1,41 +0,0 @@ -#type vertex -#version 330 core - -layout(location = 0) in vec3 a_Position; -layout(location = 1) in vec4 a_Color; -layout(location = 2) in vec2 a_TexCoord; - -uniform mat4 u_ViewProjection; -uniform mat4 u_Transform; - -out vec3 v_Position; -out vec4 v_Color; -out vec2 v_TexCoord; - -void main() -{ - v_Position = a_Position; - v_Color = a_Color; - v_TexCoord = a_TexCoord; - gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0); -} - -#type fragment -#version 330 core - -layout(location = 0) out vec4 color; - -in vec3 v_Position; -in vec4 v_Color; -in vec2 v_TexCoord; - -uniform sampler2D u_Texture; - -void main() -{ - vec4 texColor = texture(u_Texture, v_TexCoord); - if (texColor.rgb == vec3(0.0)) - color = v_Color; - else - color = v_Color * texColor; -} 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; }; }; |
