diff options
| -rw-r--r-- | src/core/state.h | 19 | ||||
| -rw-r--r-- | src/core/state_manager.cpp | 88 | ||||
| -rw-r--r-- | src/core/state_manager.h | 41 | ||||
| -rw-r--r-- | src/engine/engine.cpp | 599 | ||||
| -rw-r--r-- | src/engine/engine.h | 180 | ||||
| -rw-r--r-- | src/engine/object.h | 76 | ||||
| -rw-r--r-- | src/engine/scene.h | 70 | ||||
| -rw-r--r-- | src/platform/metal/metal_context.h | 8 | ||||
| -rw-r--r-- | src/platform/metal/metal_context.mm | 119 | ||||
| -rw-r--r-- | src/states/config_state.cpp | 307 | ||||
| -rw-r--r-- | src/states/config_state.h | 47 | ||||
| -rw-r--r-- | src/states/simulation_state.cpp | 386 | ||||
| -rw-r--r-- | src/states/simulation_state.h | 27 | ||||
| -rw-r--r-- | src/states/world_builder_state.cpp | 1110 | ||||
| -rw-r--r-- | src/states/world_builder_state.h | 96 |
15 files changed, 0 insertions, 3173 deletions
diff --git a/src/core/state.h b/src/core/state.h deleted file mode 100644 index 623f1c2..0000000 --- a/src/core/state.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "event.h" - -namespace Donut -{ - class State - { - public: - virtual ~State() = default; - - virtual auto on_enter() -> void = 0; - virtual auto on_exit() -> void = 0; - virtual auto on_update(float delta_time) -> void = 0; - virtual auto on_render() -> void = 0; - virtual auto on_im_ui_render() -> void = 0; - virtual auto on_event(Event& event) -> void = 0; - }; -}; diff --git a/src/core/state_manager.cpp b/src/core/state_manager.cpp deleted file mode 100644 index 8018401..0000000 --- a/src/core/state_manager.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "state_manager.h" -#include "log.h" - -namespace Donut -{ - auto StateManager::shutdown() -> void - { - if (m_current_state) - m_current_state->on_exit(); - - destroy_states(); - DONUT_INFO("StateManager shutdown"); - } - - auto StateManager::destroy_states() -> void - { - m_states.clear(); - m_current_state = nullptr; - m_current_state_name = ""; - } - - auto StateManager::register_state(const std::string& state_name, Scope<State> state) -> void - { - if (m_states.find(state_name) != m_states.end()) - DONUT_WARN("State '{}' already exists, overwriting", state_name); - m_states[state_name] = std::move(state); - DONUT_INFO("Registered state: {}", state_name); - } - - auto StateManager::switch_to_state(const std::string& state_name) -> void - { - auto it = m_states.find(state_name); - if (it == m_states.end()) - { - DONUT_ERROR("Attempted to switch to unknown state: {}", state_name); - return; - } - - State* new_state = it->second.get(); - if (new_state == m_current_state) - return; - - if (m_current_state) - m_current_state->on_exit(); - - m_current_state = new_state; - m_current_state_name = state_name; - m_current_state->on_enter(); - DONUT_INFO("Switched to state: {}", state_name); - } - - auto StateManager::get_state(const std::string& state_name) -> State* - { - auto it = m_states.find(state_name); - if (it != m_states.end()) - return it->second.get(); - return nullptr; - } - - auto StateManager::has_state(const std::string& state_name) const -> bool - { - return m_states.find(state_name) != m_states.end(); - } - - auto StateManager::update(float delta_time) -> void - { - if (m_current_state) - m_current_state->on_update(delta_time); - } - - auto StateManager::render() -> void - { - if (m_current_state) - m_current_state->on_render(); - } - - auto StateManager::on_im_ui_render() -> void - { - if (m_current_state) - m_current_state->on_im_ui_render(); - } - - auto StateManager::on_event(Event& event) -> void - { - if (m_current_state) - m_current_state->on_event(event); - } -} diff --git a/src/core/state_manager.h b/src/core/state_manager.h deleted file mode 100644 index 446841e..0000000 --- a/src/core/state_manager.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "memory.h" -#include "state.h" - -#include <string> -#include <unordered_map> - -namespace Donut -{ - class StateManager - { - public: - ~StateManager() = default; - auto shutdown() -> void; - - auto update(float delta_time) -> void; - auto render() -> void; - auto on_im_ui_render() -> void; - auto on_event(Event& event) -> void; - - auto register_state(const std::string& state_name, Scope<State> state) -> void; - auto switch_to_state(const std::string& state_name) -> void; - - auto get_current_state_name() const -> std::string { return m_current_state_name; } - auto get_current_state() const -> State* { return m_current_state; } - - auto get_state(const std::string& state_name) -> State*; - auto has_state(const std::string& state_name) const -> bool; - - private: - auto create_states() -> void; - auto destroy_states() -> void; - - private: - State* m_current_state = nullptr; - std::string m_current_state_name = ""; - - std::unordered_map<std::string, Scope<State>> m_states; - }; -} diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp deleted file mode 100644 index 496dd56..0000000 --- a/src/engine/engine.cpp +++ /dev/null @@ -1,599 +0,0 @@ -#include <iostream> -#include <fstream> -#include <sstream> - -#include <GLFW/glfw3.h> -#include <glad/glad.h> - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" - -#include "engine.h" -#include "core/log.h" -#include "core/hdri_manager.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), 8.54e36f) - { - m_width = 1280; - m_height = 720; - - m_camera.set_camera_mode(CameraMode::Orbital); - m_camera.set_orbital_radius(1e11); - m_camera.set_orbital_limits(1e9, 1e13); - m_camera.set_orbital_speed(0.01f); - m_camera.set_zoom_speed(1e10f); - - m_objects = - { - { 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_compute_program = Ref<Shader>(Shader::create("assets/shaders/geodesic.glsl")); - m_shader_program = Ref<Shader>(Shader::create("assets/shaders/textured_quad.glsl")); - m_blur_shader = Ref<Shader>(Shader::create("assets/shaders/blur.glsl")); - - auto& hdri_manager = HDRIManager::get(); - m_hdri_environment = hdri_manager.get_current_hdri(); - if (!m_hdri_environment) - { - hdri_manager.set_current_hdri("assets/hdri/hdr_blue_nebulae_1.hdr"); - m_hdri_environment = hdri_manager.get_current_hdri(); - if (!m_hdri_environment) - DONUT_WARN("Failed to load default HDRI, using fallback"); - } - - m_camera_ubo = UniformBuffer::create(128, 1); - m_disk_ubo = UniformBuffer::create(sizeof(float) * 6, 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); - - m_simulation_ubo = UniformBuffer::create(sizeof(int) * 2 + sizeof(float) * 2, 4); - - auto result = quad_vao(); - m_quad_vao = result.first; - m_texture = result.second; - - if (m_compute_program) - { - uint32_t prog = m_compute_program->get_renderer_id(); - struct { const char* name; uint32_t point; } blocks[] = - { - { "Camera", 1 }, { "Disk", 2 }, { "Objects", 3 }, { "Simulation", 4 } - }; - for (const auto& b : blocks) - { - uint32_t idx = glGetUniformBlockIndex(prog, b.name); - if (idx != GL_INVALID_INDEX) - glUniformBlockBinding(prog, idx, b.point); - } - } - - glGenFramebuffers(1, &m_geodesic_fbo); - } - - auto Engine::update_window_dimensions() -> void - { - update_compute_dimensions(); - } - - auto Engine::set_window_dimensions(int width, int height) -> void - { - int old_width = m_width; - int old_height = m_height; - int old_compute_height = m_compute_height; - - m_width = width; - m_height = height; - - if (old_width != m_width || - old_height != m_height || - old_compute_height != m_compute_height) - update_compute_dimensions(); - } - - auto Engine::update_performance(float delta_time) -> void - { - if (delta_time > 0.0f) - m_current_fps = 1.0f / delta_time; - } - - auto Engine::update_compute_dimensions() -> void - { - m_texture = Texture2D::create(get_compute_width(), m_compute_height); - } - - auto Engine::draw_full_screen_quad() -> void - { - RenderCommand::set_viewport(0, 0, m_width, m_height); - - m_shader_program->bind(); - m_quad_vao->bind(); - - m_texture->bind(0); - m_shader_program->set_int("u_ScreenTexture", 0); - - RenderCommand::disable_depth_test(); - RenderCommand::draw_arrays(6); - RenderCommand::enable_depth_test(); - } - - auto Engine::draw_blur_pass() -> void - { - RenderCommand::set_viewport(0, 0, m_width, m_height); - - m_blur_shader->bind(); - m_quad_vao->bind(); - - m_texture->bind(0); - m_blur_shader->set_int("u_ScreenTexture", 0); - m_blur_shader->set_float2("u_Resolution", glm::vec2(m_width, m_height)); - m_blur_shader->set_float("u_BlurStrength", m_blur_strength); - m_blur_shader->set_float("u_GlowIntensity", m_glow_intensity); - - RenderCommand::disable_depth_test(); - RenderCommand::draw_arrays(6); - RenderCommand::enable_depth_test(); - } - - auto Engine::draw_geodesic_pass(int cw, int ch) -> void - { - m_quad_vao->bind(); - RenderCommand::disable_depth_test(); - -#ifdef __APPLE__ - const int tile = 64; - glEnable(GL_SCISSOR_TEST); - for (int y = 0; y < ch; y += tile) - { - int th = std::min(tile, ch - y); - for (int x = 0; x < cw; x += tile) - { - int tw = std::min(tile, cw - x); - glScissor(x, y, tw, th); - RenderCommand::draw_arrays(6); - glFinish(); - } - } - glDisable(GL_SCISSOR_TEST); -#else - RenderCommand::draw_arrays(6); -#endif - - RenderCommand::enable_depth_test(); - } - - auto Engine::dispatch_compute(const Camera& cam) -> void - { - auto& hdri_manager = HDRIManager::get(); - m_hdri_environment = hdri_manager.get_current_hdri(); - - int cw = get_compute_width(); - int ch = m_compute_height; - - glBindFramebuffer(GL_FRAMEBUFFER, m_geodesic_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture->get_renderer_id(), 0); - glViewport(0, 0, cw, ch); - - m_compute_program->bind(); - upload_camera_ubo(cam); - upload_disk_ubo(); - upload_objects_ubo(m_objects); - upload_simulation_ubo(); - m_compute_program->set_float2("u_Resolution", glm::vec2(static_cast<float>(cw), static_cast<float>(ch))); - - if (m_hdri_environment) - { - m_hdri_environment->bind(5); - m_compute_program->set_int("u_HDRIEnvironment", 5); - } - - draw_geodesic_pass(cw, ch); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - auto Engine::upload_camera_ubo(const Camera& cam) -> void - { - struct UBOData - { - 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; - } data; - - glm::vec3 pos, fwd; - if (cam.get_camera_mode() == CameraMode::FPS) - { - pos = cam.get_position(); - fwd = cam.get_forward_direction(); - } - else - { - pos = cam.get_orbital_position(); - fwd = glm::normalize(cam.get_orbital_target() - pos); - } - glm::vec3 right = glm::normalize(glm::cross(fwd, glm::vec3(0, 1, 0))); - glm::vec3 up = glm::cross(right, fwd); - - data.pos = pos; - data.right = right; - data.up = up; - data.forward = fwd; - data.tan_half_fov = static_cast<float>(tan(glm::radians(m_bh.fov_degrees * 0.5f))); - 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); - } - - auto Engine::upload_objects_ubo(const std::vector<ObjectData>& objs) -> void - { - struct UBOData - { - int num_objects; - float _pad0, _pad1, _pad2; - glm::vec4 pos_radius[16]; - glm::vec4 color[16]; - float mass[16]; - } data; - - 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) - { - data.pos_radius[i] = objs[i].m_pos_radius; - data.color[i] = objs[i].m_color; - data.mass[i] = objs[i].m_mass; - } - - m_objects_ubo->set_data(&data, sizeof(data)); - m_objects_ubo->bind(3); - } - - auto Engine::upload_disk_ubo() -> void - { - const float rs = 1.269e10f; - float disk_data[6] = { - std::max(m_bh.disk_inner_rs, 3.0f) * rs, - std::max(m_bh.disk_outer_rs, m_bh.disk_inner_rs + 0.5f) * rs, - std::max(m_bh.turbulence, 0.0f), - rs * 0.1f, - std::max(m_bh.brightness, 0.0f), - std::max(m_bh.temperature, 1000.0f), - }; - m_disk_ubo->set_data(disk_data, sizeof(disk_data)); - m_disk_ubo->bind(2); - } - - auto Engine::upload_simulation_ubo() -> void - { - struct UBOData - { - int max_steps_moving; - int max_steps_static; - float early_exit_distance; - float time; - } data; - - data.max_steps_moving = m_bh.quality_steps; - data.max_steps_static = m_bh.quality_steps; - data.early_exit_distance = m_early_exit_distance; - data.time = static_cast<float>(glfwGetTime()) * m_rotation_speed; - -#ifdef __APPLE__ - data.max_steps_moving = std::min(data.max_steps_moving, 6000); - data.max_steps_static = std::min(data.max_steps_static, 6000); -#endif - - m_simulation_ubo->set_data(&data, sizeof(data)); - m_simulation_ubo->bind(4); - } - - auto Engine::update_physics(float delta_time) -> void - { - for (auto& obj : 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) - { - 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_pos_radius.x += static_cast<float>(obj.m_velocity.x); - obj.m_pos_radius.y += static_cast<float>(obj.m_velocity.y); - obj.m_pos_radius.z += static_cast<float>(obj.m_velocity.z); - } - } - } - } - } - - auto Engine::render_scene() -> void - { - RenderCommand::clear(); - m_shader_program->bind(); - m_quad_vao->bind(); - m_texture->bind(0); - RenderCommand::draw_arrays(6); - } - - auto Engine::create_compute_program(const char* path) -> Ref<Shader> - { - std::ifstream in(path); - if(!in.is_open()) - { - std::cerr << "Failed to open compute shader: " << path << "\n"; - return nullptr; - } - std::stringstream ss; - ss << in.rdbuf(); - std::string src_str = ss.str(); - return Ref<Shader>(Shader::create_compute("ComputeShader", src_str)); - } - - auto Engine::quad_vao() -> std::pair<Ref<VertexArray>, Ref<Texture2D>> - { - 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 }; - } - - auto Engine::load_objects_from_scene(const std::vector<Donut::Object>& objects) -> void - { - m_objects.clear(); - m_objects.push_back( - { - 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) - }); - - for (const auto& obj : objects) - { - ObjectData engine_obj; - - float scale_factor = 1e10f; - engine_obj.m_pos_radius = glm::vec4 - ( - obj.m_centre.x * scale_factor, - obj.m_centre.y * scale_factor, - obj.m_centre.z * scale_factor, - obj.m_radius * scale_factor - ); - - engine_obj.m_color = glm::vec4(obj.m_material.m_color, 1.0f); - - float volume = (4.0f / 3.0f) * 3.14159f * engine_obj.m_pos_radius.w * engine_obj.m_pos_radius.w * engine_obj.m_pos_radius.w; - float density = 1e12f; - engine_obj.m_mass = volume * density; - engine_obj.m_velocity = glm::vec3(0.0f, 0.0f, 0.0f); - - m_objects.push_back(engine_obj); - } - - DONUT_INFO("Loaded {} objects from WorldBuilder scene (scaled up by {})", objects.size(), 1e10f); - print_object_info(); - } - - auto Engine::print_object_info() const -> void - { - DONUT_INFO("=== Object Information ==="); - DONUT_INFO("Total objects: {}", m_objects.size()); - - for (size_t i = 0; i < m_objects.size(); ++i) - { - const auto& obj = m_objects[i]; - DONUT_INFO("Object {}: Pos=({}, {}, {}), Radius={}, Mass={}, Color=({}, {}, {})", - i, - obj.m_pos_radius.x, obj.m_pos_radius.y, obj.m_pos_radius.z, - obj.m_pos_radius.w, - obj.m_mass, - obj.m_color.x, obj.m_color.y, obj.m_color.z - ); - } - DONUT_INFO("Camera position: ({}, {}, {})", - m_camera.get_orbital_position().x, - m_camera.get_orbital_position().y, - m_camera.get_orbital_position().z - ); - DONUT_INFO("Camera radius: {}", m_camera.get_orbital_radius()); - DONUT_INFO("========================"); - } - - auto Engine::export_high_res_frame(const std::string& filename, int width, int height) -> void - { - DONUT_INFO("Exporting high-resolution frame: {}x{} to {}", width, height, filename); - - if (width <= 0 || height <= 0) - { - DONUT_ERROR("Invalid dimensions for export: {}x{}", width, height); - return; - } - - if (filename.empty()) - { - DONUT_ERROR("Invalid filename for export"); - return; - } - - int original_width = m_width; - int original_height = m_height; - int original_compute_height = m_compute_height; - - m_width = width; - m_height = height; - m_compute_height = height; - - int compute_height = height; - int compute_width = (width * compute_height) / height; - - if (compute_width <= 0 || compute_height <= 0) - { - DONUT_ERROR("Invalid compute dimensions: {}x{}", compute_width, compute_height); - return; - } - - FramebufferSpecification fb_spec; - fb_spec.Width = width; - fb_spec.Height = height; - fb_spec.attachments = { FramebufferTextureFormat::RGBA8 }; - - auto high_res_framebuffer = Framebuffer::create(fb_spec); - if (!high_res_framebuffer) - { - DONUT_ERROR("Failed to create high-resolution framebuffer"); - return; - } - - auto high_res_texture = Texture2D::create(compute_width, compute_height); - if (!high_res_texture) - { - DONUT_ERROR("Failed to create high-resolution texture"); - return; - } - - glBindFramebuffer(GL_FRAMEBUFFER, m_geodesic_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, high_res_texture->get_renderer_id(), 0); - glViewport(0, 0, compute_width, compute_height); - - m_compute_program->bind(); - - struct UBOData - { - 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; - } data; - - glm::vec3 fwd = glm::normalize(m_camera.get_orbital_target() - m_camera.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 = m_camera.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>(compute_width) / static_cast<float>(compute_height); - data.moving = m_camera.is_dragging() || m_camera.is_panning(); - - m_camera_ubo->set_data(&data, sizeof(UBOData)); - m_camera_ubo->bind(1); - - upload_disk_ubo(); - upload_objects_ubo(m_objects); - upload_simulation_ubo(); - m_compute_program->set_float2("u_Resolution", glm::vec2(static_cast<float>(compute_width), static_cast<float>(compute_height))); - - if (m_hdri_environment) - { - m_hdri_environment->bind(5); - m_compute_program->set_int("u_HDRIEnvironment", 5); - } - - draw_geodesic_pass(compute_width, compute_height); - - high_res_framebuffer->bind(); - RenderCommand::set_viewport(0, 0, width, height); - RenderCommand::clear(); - - m_shader_program->bind(); - m_quad_vao->bind(); - - high_res_texture->bind(0); - m_shader_program->set_int("u_ScreenTexture", 0); - - RenderCommand::disable_depth_test(); - RenderCommand::draw_arrays(6); - RenderCommand::enable_depth_test(); - - std::vector<unsigned char> pixels(width * height * 4); - DONUT_INFO("Reading {} pixels from framebuffer...", width * height); - RenderCommand::read_pixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); - - DONUT_INFO("Flipping image vertically..."); - std::vector<unsigned char> flipped_pixels(width * height * 4); - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - int src_index = (y * width + x) * 4; - int dst_index = ((height - 1 - y) * width + x) * 4; - flipped_pixels[dst_index + 0] = pixels[src_index + 0]; - flipped_pixels[dst_index + 1] = pixels[src_index + 1]; - flipped_pixels[dst_index + 2] = pixels[src_index + 2]; - flipped_pixels[dst_index + 3] = pixels[src_index + 3]; - } - } - - DONUT_INFO("Saving PNG file: {}...", filename); - int result = stbi_write_png(filename.c_str(), width, height, 4, flipped_pixels.data(), width * 4); - - if (result) - DONUT_INFO("Successfully exported high-resolution frame to: {}", filename); - else - DONUT_ERROR("Failed to export high-resolution frame to: {}", filename); - - high_res_framebuffer->unbind(); - - m_width = original_width; - m_height = original_height; - m_compute_height = original_compute_height; - - RenderCommand::set_viewport(0, 0, original_width, original_height); - } - -} diff --git a/src/engine/engine.h b/src/engine/engine.h deleted file mode 100644 index 7bab179..0000000 --- a/src/engine/engine.h +++ /dev/null @@ -1,180 +0,0 @@ -#pragma once - -#include <vector> -#include <numbers> -#include <iostream> -#include <fstream> -#include <sstream> -#include <chrono> -#include <cmath> - -#include "core/camera.h" -#include "object.h" - -#include "rendering/renderer.h" -#include "rendering/renderer_backend.h" -#include "rendering/shader.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> - -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_pos_radius; - 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; - - auto draw_full_screen_quad() -> void; - auto draw_blur_pass() -> void; - auto dispatch_compute(const Camera& cam) -> void; - auto upload_camera_ubo(const Camera& cam) -> void; - auto upload_objects_ubo(const std::vector<ObjectData>& objs) -> void; - auto upload_disk_ubo() -> void; - auto upload_simulation_ubo() -> void; - auto render_scene() -> void; - auto update_physics(float delta_time) -> void; - auto update_window_dimensions() -> void; - auto set_window_dimensions(int width, int height) -> void; - - auto get_width() const -> int { return m_width; } - auto get_height() const -> int { return m_height; } - - auto get_objects() -> std::vector<ObjectData>& { return m_objects; } - auto get_sag_a() -> BlackHole& { return m_sag_a; } - auto get_camera() -> Camera& { return m_camera; } - auto get_gravity() -> bool& { return m_gravity; } - - auto update_performance(float delta_time) -> void; - auto set_target_fps(int fps) -> void { m_target_fps = fps; } - auto get_target_fps() const -> int { return m_target_fps; } - auto get_current_fps() const -> float { return m_current_fps; } - void set_compute_height(int height) - { -#ifdef __APPLE__ - if (height > 256) height = 256; -#endif - m_compute_height = height; - } - auto get_compute_height() const -> int { return m_compute_height; } - auto get_compute_width() const -> int { return (m_width * m_compute_height) / m_height; } - auto update_compute_dimensions() -> void; - - auto get_max_steps_moving() const -> int { return m_max_steps_moving; } - auto get_max_steps_static() const -> int { return m_max_steps_static; } - auto get_early_exit_distance() const -> float { return m_early_exit_distance; } - auto set_max_steps_moving(int steps) -> void { m_max_steps_moving = steps; } - auto set_max_steps_static(int steps) -> void { m_max_steps_static = steps; } - auto set_early_exit_distance(float distance) -> void { m_early_exit_distance = distance; } - - auto get_disk_thickness() const -> float { return m_disk_thickness; } - auto set_disk_thickness(float thickness) -> void { m_disk_thickness = thickness; } - - auto get_disk_density() const -> float { return m_disk_density; } - auto set_disk_density(float density) -> void { m_disk_density = density; } - - auto get_rotation_speed() const -> float { return m_rotation_speed; } - auto set_rotation_speed(float speed) -> void { m_rotation_speed = speed; } - - auto get_blur_strength() const -> float { return m_blur_strength; } - auto set_blur_strength(float strength) -> void { m_blur_strength = strength; } - - auto get_glow_intensity() const -> float { return m_glow_intensity; } - auto set_glow_intensity(float intensity) -> void { m_glow_intensity = intensity; } - - auto load_objects_from_scene(const std::vector<Donut::Object>& objects) -> void; - auto export_high_res_frame(const std::string& filename, int width = 4096, int height = 3072) -> void; - auto print_object_info() const -> void; - - auto set_hdri_environment(Ref<CubemapTexture> hdri) -> void { m_hdri_environment = hdri; } - auto get_hdri_environment() const -> Ref<CubemapTexture> { return m_hdri_environment; } - - auto black_hole_params() -> BlackHoleParams& { return m_bh; } - private: - auto create_compute_program(const char* path) -> Ref<Shader>; - std::pair<Ref<VertexArray>, Ref<Texture2D>> quad_vao(); - - auto draw_geodesic_pass(int cw, int ch) -> void; - private: - Ref<VertexArray> m_quad_vao; - Ref<Texture2D> m_texture; - Ref<CubemapTexture> m_hdri_environment; - Ref<Shader> m_shader_program; - Ref<Shader> m_compute_program; - Ref<Shader> m_blur_shader; - Ref<UniformBuffer> m_camera_ubo; - Ref<UniformBuffer> m_disk_ubo; - Ref<UniformBuffer> m_objects_ubo; - Ref<UniformBuffer> m_simulation_ubo; - - uint32_t m_geodesic_fbo = 0; - - int m_width; - int m_height; - float m_width_f = 100.0f*1e10f; - float m_height_f = 75.0f*1e10f; - - int m_target_fps = 60; - float m_current_fps = 60.0f; - float m_last_frame_time = 0.0f; - int m_compute_height = 150; - - std::vector<ObjectData> m_objects; - BlackHole m_sag_a; - Camera m_camera; - bool m_gravity = false; - - int m_max_steps_moving = 60000; - int m_max_steps_static = 30000; - float m_early_exit_distance = 5.0e11f; - - BlackHoleParams m_bh; - - float m_disk_thickness = 0.1f; - float m_disk_density = 0.1f; - float m_rotation_speed = 1.0f; - float m_blur_strength = 2.0f; - float m_glow_intensity = 0.1f; - }; -}; diff --git a/src/engine/object.h b/src/engine/object.h deleted file mode 100644 index 8101540..0000000 --- a/src/engine/object.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include <glm/glm.hpp> - -namespace Donut -{ - class Ray - { - public: - Ray(glm::vec3 o, glm::vec3 d) - : m_origin(o), - m_direction(glm::normalize(d)) { } - - public: - glm::vec3 m_direction; - glm::vec3 m_origin; - }; - - class Material - { - public: - Material() : m_color(1.0f, 1.0f, 1.0f), m_specular(0.5f), m_emission(0.0f) { } - Material(glm::vec3 c, float s, float e) - : m_color(c), - m_specular(s), - m_emission(e) { } - - public: - glm::vec3 m_color; - float m_specular; - float m_emission; - }; - - class Object - { - public: - Object() : m_centre(0.0f, 0.0f, 0.0f), m_radius(1.0f), m_material() { } - Object(glm::vec3 c, float r, Material m) - : m_centre(c), - m_radius(r), - m_material(m) { } - - auto intersect(Ray& ray, float& t) -> bool - { - 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; - float discriminant = static_cast<float>(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; - } - - auto get_normal(glm::vec3& point) const -> glm::vec3 - { - return glm::normalize(point - m_centre); - } - - public: - glm::vec3 m_centre; - float m_radius; - Material m_material; - }; -}; diff --git a/src/engine/scene.h b/src/engine/scene.h deleted file mode 100644 index 4b41203..0000000 --- a/src/engine/scene.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include <vector> -#include <limits> - -#include "object.h" - -namespace Donut -{ - class Scene - { - public: - Scene() - : m_light_pos(5.0f, 5.0f, 5.0f) { } - - auto trace(Ray& ray) -> glm::vec3 - { - 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); - } - - public: - std::vector<Object> objs; - glm::vec3 m_light_pos; - }; -}; diff --git a/src/platform/metal/metal_context.h b/src/platform/metal/metal_context.h deleted file mode 100644 index 7a206ea..0000000 --- a/src/platform/metal/metal_context.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace Donut -{ - auto metal_probe() -> bool; - - auto metal_compute_self_test() -> bool; -} diff --git a/src/platform/metal/metal_context.mm b/src/platform/metal/metal_context.mm deleted file mode 100644 index a616865..0000000 --- a/src/platform/metal/metal_context.mm +++ /dev/null @@ -1,119 +0,0 @@ -#import <Metal/Metal.h> -#import <Foundation/Foundation.h> - -#include "metal_context.h" -#include "core/log.h" - -#include <vector> - -namespace Donut -{ - bool metal_probe() - { - @autoreleasepool - { - id<MTLDevice> device = MTLCreateSystemDefaultDevice(); - if (device == nil) - { - DONUT_ERROR("Metal: no default device available"); - return false; - } - - id<MTLCommandQueue> queue = [device newCommandQueue]; - const char* name = [[device name] UTF8String]; - - DONUT_INFO("Metal device: {}", name ? name : "(unknown)"); - DONUT_INFO("Metal: unified memory = {}, max threads/threadgroup = {}", - device.hasUnifiedMemory ? "yes" : "no", - (unsigned long)device.maxThreadsPerThreadgroup.width); - - if (queue == nil) - { - DONUT_WARN("Metal: failed to create command queue"); - return false; - } - - return true; - } - } - - bool metal_compute_self_test() - { - @autoreleasepool - { - id<MTLDevice> device = MTLCreateSystemDefaultDevice(); - id<MTLCommandQueue> queue = [device newCommandQueue]; - if (device == nil || queue == nil) - return false; - - NSString* src = - @"#include <metal_stdlib>\n" - "using namespace metal;\n" - "kernel void selfTest(texture2d<float, access::write> outTex [[texture(0)]],\n" - " uint2 gid [[thread_position_in_grid]])\n" - "{\n" - " uint w = outTex.get_width();\n" - " uint h = outTex.get_height();\n" - " if (gid.x >= w || gid.y >= h) return;\n" - " outTex.write(float4(float(gid.x) / float(w - 1),\n" - " float(gid.y) / float(h - 1), 0.5, 1.0), gid);\n" - "}\n"; - - NSError* err = nil; - id<MTLLibrary> lib = [device newLibraryWithSource:src options:nil error:&err]; - if (lib == nil) - { - DONUT_ERROR("Metal self-test: kernel compile failed: {}", - err ? [[err localizedDescription] UTF8String] : "unknown"); - return false; - } - - id<MTLFunction> fn = [lib newFunctionWithName:@"selfTest"]; - id<MTLComputePipelineState> pipeline = - [device newComputePipelineStateWithFunction:fn error:&err]; - if (pipeline == nil) - { - DONUT_ERROR("Metal self-test: pipeline creation failed"); - return false; - } - - const uint32_t W = 64, H = 64; - MTLTextureDescriptor* desc = - [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm - width:W - height:H - mipmapped:NO]; - desc.usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead; - desc.storageMode = MTLStorageModeShared; - id<MTLTexture> tex = [device newTextureWithDescriptor:desc]; - - id<MTLCommandBuffer> cb = [queue commandBuffer]; - id<MTLComputeCommandEncoder> enc = [cb computeCommandEncoder]; - [enc setComputePipelineState:pipeline]; - [enc setTexture:tex atIndex:0]; - - MTLSize tg = MTLSizeMake(16, 16, 1); - MTLSize grid = MTLSizeMake(W, H, 1); - [enc dispatchThreads:grid threadsPerThreadgroup:tg]; - [enc endEncoding]; - [cb commit]; - [cb waitUntilCompleted]; - - std::vector<uint8_t> px(W * H * 4); - [tex getBytes:px.data() - bytesPerRow:W * 4 - fromRegion:MTLRegionMake2D(0, 0, W, H) - mipmapLevel:0]; - - size_t corner = ((size_t)(H - 1) * W + (W - 1)) * 4; - DONUT_INFO("Metal compute self-test: corner pixel RGBA = ({}, {}, {}, {})", - (int)px[corner + 0], (int)px[corner + 1], - (int)px[corner + 2], (int)px[corner + 3]); - - bool ok = px[corner + 0] > 250 && px[corner + 1] > 250 && - px[corner + 3] == 255; - DONUT_INFO("Metal compute self-test: {}", ok ? "PASS" : "FAIL"); - return ok; - } - } -} diff --git a/src/states/config_state.cpp b/src/states/config_state.cpp deleted file mode 100644 index d5fca87..0000000 --- a/src/states/config_state.cpp +++ /dev/null @@ -1,307 +0,0 @@ -#include "config_state.h" -#include "rendering/renderer.h" -#include "core/application.h" -#include "core/theme_manager.h" -#include "core/settings_manager.h" - -#include <imgui.h> -#include <imgui_internal.h> -#include <glad/glad.h> - -namespace Donut -{ - auto ConfigState::on_enter() -> void - { - DONUT_INFO("Entering Config State"); - - const auto& settings = SettingsManager::get_settings_const(); - - m_selected_api = (settings.graphics.render_api == "Vulkan") ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL; - m_selected_theme = (settings.graphics.selected_theme == "Light") ? 1 : - (settings.graphics.selected_theme == "Blue") ? 2 : 0; - m_target_fps = settings.simulation.target_fps; - m_compute_height = settings.simulation.compute_height; - m_max_steps_moving = settings.simulation.max_steps_moving; - m_max_steps_static = settings.simulation.max_steps_static; - m_early_exit_distance = settings.simulation.early_exit_distance; - m_gravity_enabled = settings.simulation.gravity_enabled; - m_v_sync_enabled = settings.graphics.v_sync_enabled; - m_show_fps = settings.graphics.show_fps; - m_show_performance_metrics = settings.graphics.show_performance_metrics; - m_show_debug_info = settings.graphics.show_debug_info; - m_enable_anti_aliasing = settings.graphics.enable_anti_aliasing; - } - - auto ConfigState::on_exit() -> void - { - DONUT_INFO("Exiting Config State"); - } - - auto ConfigState::on_update(float delta_time) -> void - { - if (m_show_restart_message) - { - m_restart_message_timer += delta_time; - if (m_restart_message_timer > 3.0f) - { - m_show_restart_message = false; - m_restart_message_timer = 0.0f; - } - } - } - - auto ConfigState::on_render() -> void - { - Renderer::set_clear_color({ 0.1f, 0.1f, 0.1f, 1.0f }); - Renderer::clear(); - } - - auto ConfigState::on_event(Event& event) -> void - { - } - - auto ConfigState::on_im_ui_render() -> void - { - ImGui::SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f), - ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); - - ImGui::Begin("Donut Configuration", nullptr, ImGuiWindowFlags_NoCollapse); - - ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); - ImGui::TextColored(ImVec4(0.8f, 0.8f, 1.0f, 1.0f), "Donut Configuration"); - ImGui::PopFont(); - ImGui::Separator(); - - ImGui::Columns(2, "ConfigColumns", true); - - float available_height = ImGui::GetWindowHeight() - 140; - - ImGui::BeginChild("GraphicsSettings", ImVec2(0, available_height), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Graphics Settings"); - ImGui::Separator(); - - ImGui::Text("Render API:"); - ImGui::SameLine(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "(requires restart)"); - - const char* api_names[] = { "OpenGL", "Vulkan" }; - static int current_api = (int)m_selected_api - 1; - - if (ImGui::BeginCombo("##RenderAPI", api_names[current_api])) - { - for (int i = 0; i < IM_ARRAYSIZE(api_names); i++) - { - const bool is_selected = (current_api == i); - if (ImGui::Selectable(api_names[i], is_selected)) - { - current_api = i; - m_selected_api = (RendererAPI::API)(i + 1); - m_show_restart_message = true; - m_restart_message_timer = 0.0f; - } - - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - - ImGui::EndCombo(); - } - - ImGui::Text("Current API: "); - ImGui::SameLine(); - const char* current_api_name = (Renderer::get_api() == RendererAPI::API::OpenGL) ? "OpenGL" : "Vulkan"; - ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), current_api_name); - - ImGui::Spacing(); - - ImGui::Checkbox("Enable VSync", &m_v_sync_enabled); - ImGui::SameLine(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "(recommended)"); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Display"); - ImGui::Separator(); - - ImGui::Text("Window Size: 1280x720"); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Fullscreen: Not implemented yet"); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "System Info"); - ImGui::Separator(); - - ImGui::Text("OpenGL Version: %s", glGetString(GL_VERSION)); - ImGui::Text("GPU: %s", glGetString(GL_RENDERER)); - ImGui::Text("Vendor: %s", glGetString(GL_VENDOR)); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Performance"); - ImGui::Separator(); - - ImGui::SliderInt("Target FPS", &m_target_fps, 30, 120, "%d FPS"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Target frame rate for the simulation"); - - ImGui::Checkbox("Show FPS Counter", &m_show_fps); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Display current FPS in the simulation"); - - ImGui::Checkbox("Show Performance Metrics", &m_show_performance_metrics); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Show detailed performance information"); - - ImGui::Checkbox("Show Debug Info", &m_show_debug_info); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Display debug information and statistics"); - - ImGui::Checkbox("Enable Anti-Aliasing", &m_enable_anti_aliasing); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Enable anti-aliasing for smoother rendering"); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Theme"); - ImGui::Separator(); - - const char* theme_names[] = { "Dark", "Light", "Blue" }; - if (ImGui::Combo("UI Theme", &m_selected_theme, theme_names, IM_ARRAYSIZE(theme_names))) - ThemeManager::set_theme(static_cast<Theme>(m_selected_theme)); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Choose the application theme"); - - ImGui::EndChild(); - - ImGui::NextColumn(); - - ImGui::BeginChild("SimulationSettings", ImVec2(0, available_height), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Simulation Settings"); - ImGui::Separator(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Quality"); - ImGui::Separator(); - - ImGui::SliderInt("Compute Height", &m_compute_height, 64, 2048, "%d px"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Resolution of the compute shader. Higher values give better quality but lower performance."); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Higher = better quality, lower performance"); - - ImGui::SliderInt("Max Steps (Moving)", &m_max_steps_moving, 1000, 60000, "%d"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Maximum ray marching steps when camera is moving"); - - ImGui::SliderInt("Max Steps (Static)", &m_max_steps_static, 1000, 30000, "%d"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Maximum ray marching steps when camera is stationary"); - - ImGui::SliderFloat("Early Exit Distance", &m_early_exit_distance, 1e11f, 1e13f, "%.2e"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Distance at which ray marching stops to improve performance"); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Distance at which ray marching stops"); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Physics"); - ImGui::Separator(); - - ImGui::Checkbox("Enable Gravity", &m_gravity_enabled); - - ImGui::EndChild(); - - ImGui::Columns(1); - - ImGui::Spacing(); - ImGui::Separator(); - ImGui::Spacing(); - - float button_width = (ImGui::GetWindowWidth() - 120) / 5.0f; - - if (ImGui::Button("World Builder", ImVec2(button_width, 35))) - { - apply_settings(); - Application::get().get_state_manager().switch_to_state("WorldBuilder"); - } - - ImGui::SameLine(); - if (ImGui::Button("Reset to Defaults", ImVec2(button_width, 35))) - reset_to_defaults(); - - ImGui::SameLine(); - if (ImGui::Button("Apply Settings", ImVec2(button_width, 35))) - apply_settings(); - - ImGui::SameLine(); - if (ImGui::Button("Save Settings", ImVec2(button_width, 35))) - { - apply_settings(); - DONUT_INFO("Settings saved manually"); - } - - ImGui::SameLine(); - if (ImGui::Button("Exit", ImVec2(button_width, 35))) - Application::get().close(); - - if (m_show_restart_message) - { - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.2f, 1.0f)); - ImGui::TextWrapped("Warning: Render API changed! Please restart the application for changes to take effect."); - ImGui::PopStyleColor(); - } - - ImGui::Spacing(); - ImGui::Separator(); - ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Donut Engine v1.0.0 | Black Hole Simulation"); - - ImGui::End(); - } - - auto ConfigState::apply_settings() -> void - { - SimulationSettings sim_settings; - sim_settings.target_fps = m_target_fps; - sim_settings.compute_height = m_compute_height; - sim_settings.max_steps_moving = m_max_steps_moving; - sim_settings.max_steps_static = m_max_steps_static; - sim_settings.early_exit_distance = m_early_exit_distance; - sim_settings.gravity_enabled = m_gravity_enabled; - - GraphicsSettings gfx_settings; - gfx_settings.render_api = (m_selected_api == RendererAPI::API::Vulkan) ? "Vulkan" : "OpenGL"; - gfx_settings.v_sync_enabled = m_v_sync_enabled; - gfx_settings.show_fps = m_show_fps; - gfx_settings.show_performance_metrics = m_show_performance_metrics; - gfx_settings.show_debug_info = m_show_debug_info; - gfx_settings.enable_anti_aliasing = m_enable_anti_aliasing; - gfx_settings.selected_theme = (m_selected_theme == 1) ? "Light" : - (m_selected_theme == 2) ? "Blue" : "Dark"; - - SettingsManager::set_simulation_settings(sim_settings); - SettingsManager::set_graphics_settings(gfx_settings); - - RendererAPI::set_api(m_selected_api); - DONUT_INFO("Settings applied and saved"); - } - - auto ConfigState::reset_to_defaults() -> void - { - m_selected_api = RendererAPI::API::OpenGL; - m_target_fps = 60; - m_compute_height = 512; - m_max_steps_moving = 30000; - m_max_steps_static = 15000; - m_early_exit_distance = 5e12f; - m_gravity_enabled = true; - m_v_sync_enabled = true; - m_show_fps = true; - m_show_performance_metrics = true; - m_show_debug_info = false; - m_enable_anti_aliasing = true; - m_selected_theme = 0; - - apply_settings(); - DONUT_INFO("Settings reset to defaults and saved"); - } -}; diff --git a/src/states/config_state.h b/src/states/config_state.h deleted file mode 100644 index c723daa..0000000 --- a/src/states/config_state.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "core/state.h" -#include "core/event.h" -#include "core/log.h" -#include "rendering/renderer.h" - -namespace Donut -{ - class ConfigState - : public State - { - public: - ~ConfigState() = default; - - auto on_enter() -> void override; - auto on_exit() -> void override; - auto on_update(float delta_time) -> void override; - auto on_render() -> void override; - auto on_im_ui_render() -> void override; - auto on_event(Event& event) -> void override; - - private: - auto apply_settings() -> void; - auto reset_to_defaults() -> void; - - private: - RendererAPI::API m_selected_api = RendererAPI::API::OpenGL; - bool m_show_restart_message = false; - float m_restart_message_timer = 0.0f; - - int m_target_fps = 60; - int m_compute_height = 512; - int m_max_steps_moving = 30000; - int m_max_steps_static = 15000; - float m_early_exit_distance = 5e12f; - bool m_gravity_enabled = true; - - bool m_v_sync_enabled = true; - bool m_show_fps = true; - bool m_show_performance_metrics = true; - bool m_show_debug_info = false; - bool m_enable_anti_aliasing = true; - - int m_selected_theme = 0; - }; -}; diff --git a/src/states/simulation_state.cpp b/src/states/simulation_state.cpp deleted file mode 100644 index 06955ff..0000000 --- a/src/states/simulation_state.cpp +++ /dev/null @@ -1,386 +0,0 @@ -#include "simulation_state.h" -#include "rendering/renderer.h" -#include "core/application.h" -#include "core/hdri_manager.h" -#include "core/window.h" -#include "core/event.h" -#include "core/settings_manager.h" - -#include <imgui.h> -#include <GLFW/glfw3.h> -#include <chrono> -#include <iomanip> -#include <sstream> -#include <vector> - -namespace Donut -{ - auto SimulationState::on_enter() -> void - { - DONUT_INFO("Entering Simulation State"); - - const auto& settings = SettingsManager::get_settings_const(); - auto& engine = Application::get().get_engine(); - - engine.set_target_fps(settings.simulation.target_fps); - engine.set_compute_height(settings.simulation.compute_height); - engine.set_max_steps_moving(settings.simulation.max_steps_moving); - engine.set_max_steps_static(settings.simulation.max_steps_static); - engine.set_early_exit_distance(settings.simulation.early_exit_distance); - engine.get_gravity() = settings.simulation.gravity_enabled; - - engine.set_disk_thickness(settings.simulation.disk_thickness); - engine.set_disk_density(settings.simulation.disk_density); - engine.set_rotation_speed(settings.simulation.rotation_speed); - engine.set_blur_strength(settings.simulation.blur_strength); - engine.set_glow_intensity(settings.simulation.glow_intensity); - - engine.update_compute_dimensions(); - m_initialized = true; - } - - auto SimulationState::on_exit() -> void - { - DONUT_INFO("Exiting Simulation State"); - } - - auto SimulationState::on_update(float delta_time) -> void - { - auto& engine = Application::get().get_engine(); - engine.update_performance(delta_time); - engine.update_window_dimensions(); - engine.update_physics(delta_time); - - if (engine.get_camera().is_dragging()) - { - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - engine.get_camera().process_orbital_mouse_move(xpos, ypos); - } - } - - auto SimulationState::on_render() -> void - { - auto& engine = Application::get().get_engine(); - RenderCommand::set_clear_color(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - RenderCommand::clear(); - RenderCommand::set_viewport(0, 0, static_cast<uint32_t>(engine.get_width()), static_cast<uint32_t>(engine.get_height())); - - engine.dispatch_compute(engine.get_camera()); - engine.draw_blur_pass(); - } - - auto SimulationState::on_event(Event& event) -> void - { - auto& engine = Application::get().get_engine(); - - if (event.get_event_type() == EventType::MouseButtonPressed) - { - MouseButtonPressedEvent& e = (MouseButtonPressedEvent&)event; - int button = e.get_mouse_button(); - - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - Camera& camera = 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) - { - MouseButtonReleasedEvent& e = (MouseButtonReleasedEvent&)event; - int button = e.get_mouse_button(); - engine.get_camera().process_orbital_mouse_button(button, GLFW_RELEASE, 0); - } - - if (event.get_event_type() == EventType::MouseScrolled) - { - MouseScrolledEvent& e = (MouseScrolledEvent&)event; - engine.get_camera().process_orbital_scroll(e.get_x_offset(), e.get_y_offset()); - } - - if (event.get_event_type() == EventType::KeyPressed) - { - KeyPressedEvent& e = (KeyPressedEvent&)event; - if (e.get_key_code() == GLFW_KEY_G) - { - engine.get_gravity() = !engine.get_gravity(); - DONUT_INFO("Gravity turned {}", engine.get_gravity() ? "ON" : "OFF"); - } - } - } - - auto SimulationState::on_im_ui_render() -> void - { - auto& engine = Application::get().get_engine(); - - ImGui::SetNextWindowSize(ImVec2(400, 600), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - 420, 20), ImGuiCond_FirstUseEver); - - ImGui::Begin("Simulation Controls", nullptr, ImGuiWindowFlags_NoCollapse); - - ImGui::TextColored(ImVec4(0.8f, 0.8f, 1.0f, 1.0f), "Black Hole Simulation"); - ImGui::SameLine(); - if (ImGui::Button("Back to Config")) - Application::get().get_state_manager().switch_to_state("Config"); - ImGui::SameLine(); - if (ImGui::Button("Save Settings")) - { - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.target_fps = engine.get_target_fps(); - settings.compute_height = engine.get_compute_height(); - settings.max_steps_moving = engine.get_max_steps_moving(); - settings.max_steps_static = engine.get_max_steps_static(); - settings.early_exit_distance = engine.get_early_exit_distance(); - settings.gravity_enabled = engine.get_gravity(); - SettingsManager::set_simulation_settings(settings); - DONUT_INFO("Simulation settings saved manually"); - } - - ImGui::Separator(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Performance"); - ImGui::Separator(); - - ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate); - ImGui::Text("Frame Time: %.3f ms", 1000.0f / ImGui::GetIO().Framerate); - ImGui::Text("Engine FPS: %.1f", engine.get_current_fps()); - - int target_fps = engine.get_target_fps(); - if (ImGui::SliderInt("Target FPS", &target_fps, 30, 120)) - { - engine.set_target_fps(target_fps); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.target_fps = target_fps; - SettingsManager::set_simulation_settings(settings); - } - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Simulation Info"); - ImGui::Separator(); - - ImGui::Text("Resolution: %dx%d", engine.get_width(), engine.get_height()); - ImGui::Text("Compute Resolution: %dx%d", engine.get_compute_width(), engine.get_compute_height()); - ImGui::Text("Objects: %zu", engine.get_objects().size()); - - if (ImGui::Button("Print Object Info")) - engine.print_object_info(); - - int compute_height = engine.get_compute_height(); - if (ImGui::SliderInt("Compute Height", &compute_height, 64, 2048)) - { - engine.set_compute_height(compute_height); - engine.update_compute_dimensions(); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.compute_height = compute_height; - SettingsManager::set_simulation_settings(settings); - } - - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Compute Width: %d (auto-calculated)", engine.get_compute_width()); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Quality Settings"); - ImGui::Separator(); - - int max_steps_moving = engine.get_max_steps_moving(); - if (ImGui::SliderInt("Max Steps (Moving)", &max_steps_moving, 1000, 60000)) - { - engine.set_max_steps_moving(max_steps_moving); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.max_steps_moving = max_steps_moving; - SettingsManager::set_simulation_settings(settings); - } - int max_steps_static = engine.get_max_steps_static(); - if (ImGui::SliderInt("Max Steps (Static)", &max_steps_static, 1000, 30000)) - { - engine.set_max_steps_static(max_steps_static); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.max_steps_static = max_steps_static; - SettingsManager::set_simulation_settings(settings); - } - float early_exit_distance = engine.get_early_exit_distance(); - if (ImGui::SliderFloat("Early Exit Distance", &early_exit_distance, 1e11f, 1e13f, "%.2e")) - { - engine.set_early_exit_distance(early_exit_distance); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.early_exit_distance = early_exit_distance; - SettingsManager::set_simulation_settings(settings); - } - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Physics"); - ImGui::Separator(); - - bool& gravity = engine.get_gravity(); - if (ImGui::Checkbox("Gravity Enabled", &gravity)) - { - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.gravity_enabled = gravity; - SettingsManager::set_simulation_settings(settings); - } - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Accretion Disk"); - ImGui::Separator(); - - float disk_thickness = engine.get_disk_thickness(); - if (ImGui::SliderFloat("Cloud Thickness", &disk_thickness, 0.1f, 2.0f, "%.2f")) - { - engine.set_disk_thickness(disk_thickness); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.disk_thickness = disk_thickness; - SettingsManager::set_simulation_settings(settings); - } - ImGui::TextDisabled("Thickness relative to Schwarzschild radius"); - - float disk_density = engine.get_disk_density(); - if (ImGui::SliderFloat("Cloud Density", &disk_density, 0.1f, 3.0f, "%.2f")) - { - engine.set_disk_density(disk_density); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.disk_density = disk_density; - SettingsManager::set_simulation_settings(settings); - } - ImGui::TextDisabled("Overall density multiplier"); - - float rotation_speed = engine.get_rotation_speed(); - if (ImGui::SliderFloat("Rotation Speed", &rotation_speed, 0.0f, 3.0f, "%.2f")) - { - engine.set_rotation_speed(rotation_speed); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.rotation_speed = rotation_speed; - SettingsManager::set_simulation_settings(settings); - } - ImGui::TextDisabled("Rotation speed multiplier (0 = no rotation)"); - - float blur_strength = engine.get_blur_strength(); - if (ImGui::SliderFloat("Blur Strength", &blur_strength, 0.5f, 5.0f, "%.2f")) - { - engine.set_blur_strength(blur_strength); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.blur_strength = blur_strength; - SettingsManager::set_simulation_settings(settings); - } - ImGui::TextDisabled("Blur radius for glow effect"); - - float glow_intensity = engine.get_glow_intensity(); - if (ImGui::SliderFloat("Glow Intensity", &glow_intensity, 0.1f, 3.0f, "%.2f")) - { - engine.set_glow_intensity(glow_intensity); - SimulationSettings settings = SettingsManager::get_settings_const().simulation; - settings.glow_intensity = glow_intensity; - SettingsManager::set_simulation_settings(settings); - } - ImGui::TextDisabled("Intensity of the glow effect"); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "HDRI Environment"); - ImGui::Separator(); - - static int selected_hdri = 0; - ImGui::PushID("SimulationHDRI"); - auto& hdri_manager = HDRIManager::get(); - const auto& available_hdri = hdri_manager.get_available_hdri(); - - static std::vector<std::string> hdri_option_names; - static std::vector<const char*> hdri_options; - - if (hdri_option_names.size() != available_hdri.size()) - { - hdri_option_names.clear(); - hdri_options.clear(); - - for (const auto& path : available_hdri) - { - hdri_option_names.push_back(hdri_manager.get_hdri_name(path)); - hdri_options.push_back(hdri_option_names.back().c_str()); - } - } - - if (ImGui::Combo("HDRI Environment", &selected_hdri, hdri_options.data(), static_cast<int>(hdri_options.size()))) - { - auto& hdri_manager = HDRIManager::get(); - hdri_manager.set_current_hdri(available_hdri[selected_hdri]); - engine.set_hdri_environment(hdri_manager.get_current_hdri()); - } - ImGui::TextDisabled("HDRI provides background and lighting for the simulation"); - ImGui::PopID(); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Camera"); - ImGui::Separator(); - - ImGui::Text("Position: (%.2e, %.2e, %.2e)", - engine.get_camera().get_orbital_position().x, - engine.get_camera().get_orbital_position().y, - engine.get_camera().get_orbital_position().z); - ImGui::Text("Radius: %.2e", engine.get_camera().get_orbital_radius()); - ImGui::Text("Azimuth: %.2f", engine.get_camera().get_azimuth()); - ImGui::Text("Elevation: %.2f", engine.get_camera().get_elevation()); - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Export"); - ImGui::Separator(); - - if (ImGui::Button("Export Frame (1080p)", ImVec2(-1, 30))) - { - auto& engine = Application::get().get_engine(); - auto now = std::chrono::system_clock::now(); - auto time_t = std::chrono::system_clock::to_time_t(now); - std::stringstream ss; - ss << "frame_1080p_" << std::put_time(std::localtime(&time_t), "%Y-%m-%d_%H-%M-%S") << ".png"; - engine.export_high_res_frame(ss.str(), 1920, 1080); - } - - if (ImGui::Button("Export High-Res Frame (4K)", ImVec2(-1, 30))) - { - auto& engine = Application::get().get_engine(); - auto now = std::chrono::system_clock::now(); - auto time_t = std::chrono::system_clock::to_time_t(now); - std::stringstream ss; - ss << "high_res_frame_4k_" << std::put_time(std::localtime(&time_t), "%Y-%m-%d_%H-%M-%S") << ".png"; - engine.export_high_res_frame(ss.str(), 4096, 3072); - } - - if (ImGui::Button("Export High-Res Frame (8K)", ImVec2(-1, 30))) - { - auto& engine = Application::get().get_engine(); - auto now = std::chrono::system_clock::now(); - auto time_t = std::chrono::system_clock::to_time_t(now); - std::stringstream ss; - ss << "high_res_frame_8k_" << std::put_time(std::localtime(&time_t), "%Y-%m-%d_%H-%M-%S") << ".png"; - engine.export_high_res_frame(ss.str(), 8192, 6144); - } - - if (ImGui::Button("Export Ultra High-Res Frame (16K)", ImVec2(-1, 30))) - { - auto& engine = Application::get().get_engine(); - auto now = std::chrono::system_clock::now(); - auto time_t = std::chrono::system_clock::to_time_t(now); - std::stringstream ss; - ss << "high_res_frame_16k_" << std::put_time(std::localtime(&time_t), "%Y%m%d_%H%M%S") << ".png"; - engine.export_high_res_frame(ss.str(), 16384, 12288); - } - - ImGui::Spacing(); - - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Controls"); - ImGui::Separator(); - - 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::End(); - } -}; diff --git a/src/states/simulation_state.h b/src/states/simulation_state.h deleted file mode 100644 index 625d19e..0000000 --- a/src/states/simulation_state.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "core/state.h" -#include "core/event.h" -#include "core/log.h" -#include "engine/engine.h" -#include <vector> - -namespace Donut -{ - class SimulationState - : public State - { - public: - ~SimulationState() = default; - - auto on_enter() -> void override; - auto on_exit() -> void override; - auto on_update(float delta_time) -> void override; - auto on_render() -> void override; - auto on_im_ui_render() -> void override; - auto on_event(Event& event) -> void override; - - private: - bool m_initialized = false; - }; -}; diff --git a/src/states/world_builder_state.cpp b/src/states/world_builder_state.cpp deleted file mode 100644 index be74eb6..0000000 --- a/src/states/world_builder_state.cpp +++ /dev/null @@ -1,1110 +0,0 @@ -#include "world_builder_state.h" - -#include "core/application.h" -#include "core/window.h" -#include "core/hdri_manager.h" - -#include "rendering/renderer.h" -#include "rendering/shader.h" -#include "rendering/vertex_array.h" -#include "rendering/vertex_buffer.h" -#include "rendering/index_buffer.h" -#include "rendering/texture.h" - -#include <imgui.h> -#include <ImGuizmo.h> -#include <GLFW/glfw3.h> - -#include <glm/gtc/matrix_transform.hpp> -#include <glm/gtc/type_ptr.hpp> - -#include <nlohmann/json.hpp> - -#include <numbers> -#include <fstream> -#include <sstream> -#include <limits> -#include <vector> - -namespace Donut -{ - auto WorldBuilderState::on_enter() -> void - { - DONUT_INFO("Entering World Builder State"); - - ImGuizmo::Enable(true); - - m_camera.set_camera_mode(CameraMode::Orbital); - m_camera.set_orbital_target(glm::vec3(0.0f, 0.0f, 0.0f)); - m_camera.set_orbital_radius(15.0f); - m_camera.set_orbital_limits(2.0f, 200.0f); - m_camera.set_orbital_speed(0.01f); - m_camera.set_zoom_speed(2.0f); - m_camera.set_azimuth(0.0f); - m_camera.set_elevation(static_cast<float>(std::numbers::pi) / 3.0f); - m_camera.update_orbital(); - - m_sphere_shader = Ref<Shader>(Shader::create("assets/shaders/sphere.glsl")); - m_skybox_shader = Ref<Shader>(Shader::create("assets/shaders/skybox.glsl")); - m_grid_shader = Ref<Shader>(Shader::create("assets/shaders/grid.glsl")); - - if (!m_sphere_shader) - DONUT_ERROR("Failed to create sphere shader"); - if (!m_skybox_shader) - DONUT_ERROR("Failed to create skybox shader"); - if (!m_grid_shader) - DONUT_ERROR("Failed to create grid shader"); - - initialize_sphere_geometry(); - initialize_skybox_geometry(); - initialize_grid_geometry(); - - auto& hdri_manager = HDRIManager::get(); - m_hdri_environment = hdri_manager.get_current_hdri(); - if (!m_hdri_environment) - { - hdri_manager.set_current_hdri("assets/hdri/hdr_blue_nebulae_1.hdr"); - m_hdri_environment = hdri_manager.get_current_hdri(); - if (!m_hdri_environment) - DONUT_WARN("Failed to load default HDRI for WorldBuilder, using fallback"); - } - - Material black_hole_material(glm::vec3(0.0f, 0.0f, 0.0f), 0.0f, 0.0f); - m_black_hole = Object(glm::vec3(0.0f, 0.0f, 0.0f), 2.0f, black_hole_material); - m_black_hole_initialized = true; - - m_grid_size = 10.0f; - - m_initialized = true; - } - - auto WorldBuilderState::on_exit() -> void - { - DONUT_INFO("Exiting World Builder State"); - } - - auto WorldBuilderState::on_update(float delta_time) -> void - { - if (m_camera_dragging && - !ImGuizmo::IsUsing()) - { - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - - glm::vec2 current_mouse_pos(xpos, ypos); - glm::vec2 delta = current_mouse_pos - m_last_mouse_pos; - - float sensitivity = 0.005f; - float azimuth_delta = delta.x * sensitivity; - float elevation_delta = -delta.y * sensitivity; - - float new_azimuth = m_camera.get_azimuth() + azimuth_delta; - float new_elevation = m_camera.get_elevation() + elevation_delta; - - new_elevation = glm::clamp(new_elevation, 0.01f, static_cast<float>(std::numbers::pi) - 0.01f); - - m_camera.set_azimuth(new_azimuth); - m_camera.set_elevation(new_elevation); - m_camera.update_orbital(); - - m_last_mouse_pos = current_mouse_pos; - } - } - - auto WorldBuilderState::on_render() -> void - { - auto& hdri_manager = HDRIManager::get(); - m_hdri_environment = hdri_manager.get_current_hdri(); - - RenderCommand::set_clear_color(glm::vec4(0.1f, 0.1f, 0.1f, 1.0f)); - RenderCommand::clear(); - - if (m_hdri_environment) - render_skybox(); - - if (m_show_grid) - render_grid(); - - render_scene(); - } - - auto WorldBuilderState::on_event(Event& event) -> void - { - EventDispatcher dispatcher(event); - - dispatcher.dispatch<MouseButtonPressedEvent>([this](MouseButtonPressedEvent& e) - { - if (e.get_mouse_button() == GLFW_MOUSE_BUTTON_LEFT) - { - if (ImGuizmo::IsUsing() || - ImGuizmo::IsOver()) - return false; - - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - float ndc_x = (2.0f * static_cast<float>(xpos)) / static_cast<float>(width) - 1.0f; - float ndc_y = 1.0f - (2.0f * static_cast<float>(ypos)) / static_cast<float>(height); - - glm::vec4 ray_start_ndc(ndc_x, ndc_y, -1.0f, 1.0f); - glm::vec4 ray_end_ndc(ndc_x, ndc_y, 0.0f, 1.0f); - - glm::mat4 inv_vp = glm::inverse(m_camera.get_projection_matrix() * m_camera.get_view_matrix()); - glm::vec4 ray_start_world = inv_vp * ray_start_ndc; - glm::vec4 ray_end_world = inv_vp * ray_end_ndc; - - ray_start_world /= ray_start_world.w; - ray_end_world /= ray_end_world.w; - - glm::vec3 ray_dir = glm::normalize(glm::vec3(ray_end_world - ray_start_world)); - glm::vec3 ray_origin = glm::vec3(ray_start_world); - - float closest_distance = std::numeric_limits<float>::max(); - int closest_object_index = -1; - - if (m_black_hole_initialized) - { - glm::vec3 oc = ray_origin - m_black_hole.m_centre; - float a = glm::dot(ray_dir, ray_dir); - float b = 2.0f * glm::dot(oc, ray_dir); - float c = glm::dot(oc, oc) - m_black_hole.m_radius * m_black_hole.m_radius; - float discriminant = b * b - 4 * a * c; - - if (discriminant > 0) - { - float t1 = (-b - sqrt(discriminant)) / (2.0f * a); - float t2 = (-b + sqrt(discriminant)) / (2.0f * a); - - if (t1 > 0 && t1 < closest_distance) - { - closest_distance = t1; - closest_object_index = -2; - } - else if (t2 > 0 && t2 < closest_distance) - { - closest_distance = t2; - closest_object_index = -2; - } - } - } - - for (size_t i = 0; i < m_scene.objs.size(); ++i) - { - const Object& obj = m_scene.objs[i]; - - glm::vec3 oc = ray_origin - obj.m_centre; - float a = glm::dot(ray_dir, ray_dir); - float b = 2.0f * glm::dot(oc, ray_dir); - float c = glm::dot(oc, oc) - obj.m_radius * obj.m_radius; - float discriminant = b * b - 4 * a * c; - - if (discriminant > 0) - { - float t1 = (-b - sqrt(discriminant)) / (2.0f * a); - float t2 = (-b + sqrt(discriminant)) / (2.0f * a); - - if (t1 > 0 && t1 < closest_distance) - { - closest_distance = t1; - closest_object_index = static_cast<int>(i); - } - else if (t2 > 0 && t2 < closest_distance) - { - closest_distance = t2; - closest_object_index = static_cast<int>(i); - } - } - } - - if (closest_object_index >= 0) - { - m_selected_object_index = closest_object_index; - DONUT_INFO("Selected object {}", closest_object_index); - return true; - } - else if (closest_object_index == -2) - { - m_selected_object_index = -1; - DONUT_INFO("Black hole clicked (not selectable)"); - return true; - } - else - { - m_selected_object_index = -1; - m_camera_dragging = true; - m_last_mouse_pos = glm::vec2(xpos, ypos); - } - - return true; - } - return false; - }); - - dispatcher.dispatch<MouseButtonReleasedEvent>([this](MouseButtonReleasedEvent& e) - { - if (e.get_mouse_button() == GLFW_MOUSE_BUTTON_LEFT) - { - if (!ImGuizmo::IsUsing()) - m_camera_dragging = false; - return true; - } - - return false; - }); - - dispatcher.dispatch<WindowResizeEvent>([this](WindowResizeEvent& e) - { - int new_width = e.get_width(); - int new_height = e.get_height(); - if (new_width > 0 && new_height > 0) - { - float aspect = static_cast<float>(new_width) / static_cast<float>(new_height); - m_camera.set_projection(45.0f, aspect, 0.1f, 1000.0f); - } - return false; - }); - - dispatcher.dispatch<MouseScrolledEvent>([this](MouseScrolledEvent& e) - { - float zoom_speed = 0.1f; - float zoom_delta = e.get_y_offset() * zoom_speed; - - double current_radius = m_camera.get_orbital_radius(); - double new_radius = current_radius - zoom_delta * current_radius * 0.1f; - - double min_radius = 2.0f; - double max_radius = 200.0f; - new_radius = glm::clamp(new_radius, min_radius, max_radius); - - m_camera.set_orbital_radius(new_radius); - m_camera.update_orbital(); - - return true; - }); - - dispatcher.dispatch<KeyPressedEvent>([this](KeyPressedEvent& e) - { - if (m_selected_object_index >= 0 && - m_selected_object_index < static_cast<int>(m_scene.objs.size())) - { - switch (e.get_key_code()) - { - case GLFW_KEY_M: - m_gizmo_operation = ImGuizmo::TRANSLATE; - return true; - case GLFW_KEY_R: - m_gizmo_operation = ImGuizmo::ROTATE; - return true; - case GLFW_KEY_S: - m_gizmo_operation = ImGuizmo::SCALE; - return true; - } - } - return false; - }); - } - - auto WorldBuilderState::on_im_ui_render() -> void - { - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - ImGuiViewport* vp = ImGui::GetMainViewport(); - ImGuizmo::SetRect(vp->Pos.x, vp->Pos.y, vp->Size.x, vp->Size.y); - - ImGui::SetNextWindowSize(ImVec2(400, 600), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiCond_FirstUseEver); - - ImGui::Begin("World Builder", nullptr, ImGuiWindowFlags_NoCollapse); - - ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); - ImGui::TextColored(ImVec4(0.8f, 0.8f, 1.0f, 1.0f), "World Builder"); - ImGui::PopFont(); - ImGui::Separator(); - - if (ImGui::CollapsingHeader("Scene Info")) - { - ImGui::Text("Objects in scene: %zu/16 (+ 1 black hole)", m_scene.objs.size()); - - ImGui::Separator(); - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Camera Info:"); - - glm::vec3 camera_pos = m_camera.get_orbital_position(); - glm::vec3 target = m_camera.get_orbital_target(); - - ImGui::Text("Position: (%.2f, %.2f, %.2f)", camera_pos.x, camera_pos.y, camera_pos.z); - ImGui::Text("Target: (%.2f, %.2f, %.2f)", target.x, target.y, target.z); - ImGui::Text("Distance: %.2f", m_camera.get_orbital_radius()); - ImGui::Text("Azimuth: %.1f°", glm::degrees(m_camera.get_azimuth())); - ImGui::Text("Elevation: %.1f°", glm::degrees(m_camera.get_elevation())); - - ImGui::Separator(); - - if (ImGui::Button("Reset Camera")) - { - m_camera.set_orbital_radius(15.0f); - m_camera.set_azimuth(0.0f); - m_camera.set_elevation(static_cast<float>(std::numbers::pi) / 3.0f); - m_camera.set_orbital_target(glm::vec3(0.0f, 0.0f, 0.0f)); - m_camera.update_orbital(); - } - - ImGui::SameLine(); - if (ImGui::Button("Clear Scene")) - clear_scene(); - - ImGui::SameLine(); - if (ImGui::Button("Focus on Objects")) - { - if (!m_scene.objs.empty()) - { - glm::vec3 center(0.0f); - for (const auto& obj : m_scene.objs) - center += obj.m_centre; - center /= static_cast<float>(m_scene.objs.size()); - m_camera.set_orbital_target(center); - m_camera.update_orbital(); - } - } - } - - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("create Object")) - { - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "New Sphere"); - ImGui::Separator(); - - ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1.0f), "Objects: %zu/16", m_scene.objs.size()); - - ImGui::Text("Position:"); - ImGui::DragFloat3("##Position", &m_new_object_position.x, 0.1f); - - ImGui::Text("Radius:"); - ImGui::DragFloat("##Radius", &m_new_object_radius, 0.1f, 0.1f, 10.0f); - - ImGui::Text("Color:"); - ImGui::ColorEdit3("##Color", &m_new_object_color.x); - - ImGui::Text("Specular:"); - ImGui::SliderFloat("##Specular", &m_new_object_specular, 0.0f, 1.0f); - - ImGui::Text("Emission:"); - ImGui::SliderFloat("##Emission", &m_new_object_emission, 0.0f, 1.0f); - - ImGui::Spacing(); - - if (m_scene.objs.size() >= 16) - { - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); - ImGui::Button("add Sphere (Limit Reached)", ImVec2(ImGui::GetWindowWidth() - 20, 30)); - ImGui::PopStyleVar(); - } - else - { - if (ImGui::Button("add Sphere", ImVec2(ImGui::GetWindowWidth() - 20, 30))) - add_sphere(); - } - } - - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("Scene Objects")) - { - if (m_black_hole_initialized) - { - ImGui::PushID(-1); - - ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), "Black Hole (Center)"); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Position: (0.00, 0.00, 0.00)"); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Radius: %.2f", m_black_hole.m_radius); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Color: Black (with white outline)"); - ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Cannot be removed or modified"); - - ImGui::PopID(); - ImGui::Separator(); - } - - if (m_scene.objs.empty()) - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "No additional objects in scene"); - else - { - for (size_t i = 0; i < m_scene.objs.size(); ++i) - { - Object& obj = m_scene.objs[i]; - - ImGui::PushID(static_cast<int>(i)); - - bool is_selected = (m_selected_object_index == static_cast<int>(i)); - if (ImGui::Selectable(("Sphere " + std::to_string(i)).c_str(), is_selected)) - m_selected_object_index = static_cast<int>(i); - - if (is_selected) - { - ImGui::SameLine(); - if (ImGui::Button("Remove")) - { - remove_selected_object(); - } - - ImGui::Text("Position: (%.2f, %.2f, %.2f)", - obj.m_centre.x, obj.m_centre.y, obj.m_centre.z); - ImGui::Text("Radius: %.2f", obj.m_radius); - ImGui::Text("Color: (%.2f, %.2f, %.2f)", - obj.m_material.m_color.x, obj.m_material.m_color.y, obj.m_material.m_color.z); - } - - ImGui::PopID(); - } - } - } - - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("Gizmo Controls")) - { - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Gizmo Operation:"); - - if (ImGui::RadioButton("Translate", m_gizmo_operation == ImGuizmo::TRANSLATE)) - m_gizmo_operation = ImGuizmo::TRANSLATE; - ImGui::SameLine(); - if (ImGui::RadioButton("Rotate", m_gizmo_operation == ImGuizmo::ROTATE)) - m_gizmo_operation = ImGuizmo::ROTATE; - ImGui::SameLine(); - if (ImGui::RadioButton("Scale", m_gizmo_operation == ImGuizmo::SCALE)) - m_gizmo_operation = ImGuizmo::SCALE; - - ImGui::Spacing(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Hotkeys:"); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "M = Move, R = Rotate, S = Scale"); - } - - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("Selection Outline")) - { - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Outline Settings:"); - - ImGui::Text("Outline Color:"); - ImGui::ColorEdit3("##OutlineColor", &m_outline_color.x); - - ImGui::Text("Outline Width:"); - ImGui::SliderFloat("##OutlineWidth", &m_outline_width, 0.01f, 0.9f, "%.2f"); - - ImGui::Spacing(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "White rim around sphere silhouette"); - } - - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("Grid Settings")) - { - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Grid Settings:"); - - ImGui::Text("Show Grid:"); - ImGui::SameLine(); - ImGui::Checkbox("##ShowGrid", &m_show_grid); - - ImGui::Text("Grid Color:"); - ImGui::ColorEdit3("##GridColor", &m_grid_color.x); - - ImGui::Text("Grid Alpha:"); - ImGui::SliderFloat("##GridAlpha", &m_grid_alpha, 0.0f, 1.0f, "%.2f"); - - ImGui::Text("Grid Size:"); - ImGui::SliderFloat("##GridSize", &m_grid_size, 1.0f, 500.0f, "%.1f"); - - ImGui::Spacing(); - if (ImGui::Button("Regenerate Grid", ImVec2(ImGui::GetWindowWidth() - 20, 25))) - initialize_grid_geometry(); - - ImGui::Spacing(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Reference grid for spatial orientation"); - } - - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("HDRI Environment", nullptr)) - { - ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "HDRI Settings:"); - - static int selected_hdri = 0; - ImGui::PushID("WorldBuilderHDRI"); - auto& hdri_manager = HDRIManager::get(); - const auto& available_hdri = hdri_manager.get_available_hdri(); - - static std::vector<std::string> hdri_option_names; - static std::vector<const char*> hdri_options; - - if (hdri_option_names.size() != available_hdri.size()) - { - hdri_option_names.clear(); - hdri_options.clear(); - - for (const auto& path : available_hdri) - { - hdri_option_names.push_back(hdri_manager.get_hdri_name(path)); - hdri_options.push_back(hdri_option_names.back().c_str()); - } - } - - if (ImGui::Combo("HDRI Environment", &selected_hdri, hdri_options.data(), static_cast<int>(hdri_options.size()))) - { - auto& hdri_manager = HDRIManager::get(); - hdri_manager.set_current_hdri(available_hdri[selected_hdri]); - m_hdri_environment = hdri_manager.get_current_hdri(); - } - - ImGui::Spacing(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "HDRI provides background skybox and lighting for the scene"); - ImGui::PopID(); - } - - ImGui::Spacing(); - ImGui::Separator(); - ImGui::Spacing(); - - float button_width = (ImGui::GetWindowWidth() - 30) / 2.0f; - - if (ImGui::Button("Save Scene", ImVec2(button_width, 30))) - save_scene(); - - ImGui::SameLine(); - if (ImGui::Button("load Scene", ImVec2(button_width, 30))) - load_scene(); - - ImGui::Spacing(); - - if (ImGui::Button("Start Simulation", ImVec2(ImGui::GetWindowWidth() - 20, 30))) - { - auto& engine = Application::get().get_engine(); - engine.load_objects_from_scene(m_scene.objs); - Application::get().get_state_manager().switch_to_state("Simulation"); - } - - ImGui::Spacing(); - - if (ImGui::Button("Back to Config", ImVec2(ImGui::GetWindowWidth() - 20, 30))) - Application::get().get_state_manager().switch_to_state("Config"); - - ImGui::Spacing(); - ImGui::Separator(); - ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Camera: Left mouse = rotate, Scroll = zoom"); - ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Gizmo: M=Move, R=Rotate, S=Scale"); - - ImGui::End(); - - if (m_selected_object_index >= 0 && - m_selected_object_index < static_cast<int>(m_scene.objs.size()) && - m_selected_object_index != -2) - { - glm::mat4 view = m_camera.get_view_matrix(); - glm::mat4 projection = m_camera.get_projection_matrix(); - - Object& selected_obj = m_scene.objs[m_selected_object_index]; - - glm::mat4 object_transform = glm::mat4(1.0f); - object_transform = glm::translate(object_transform, selected_obj.m_centre); - object_transform = glm::scale(object_transform, glm::vec3(selected_obj.m_radius)); - - DONUT_INFO("Object position: ({}, {}, {})", selected_obj.m_centre.x, selected_obj.m_centre.y, selected_obj.m_centre.z); - glm::vec3 camera_pos = m_camera.get_orbital_position(); - DONUT_INFO("Camera position: ({}, {}, {})", camera_pos.x, camera_pos.y, camera_pos.z); - - glm::vec3 view_translation = glm::vec3(view[3][0], view[3][1], view[3][2]); - DONUT_INFO("View translation: ({}, {}, {})", view_translation.x, view_translation.y, view_translation.z); - - ImGuizmo::SetDrawlist(ImGui::GetForegroundDrawList()); - if (ImGuizmo::Manipulate(glm::value_ptr(view), glm::value_ptr(projection), - m_gizmo_operation, m_gizmo_mode, - glm::value_ptr(object_transform), - nullptr, nullptr)) - { - glm::vec3 new_position = glm::vec3(object_transform[3][0], object_transform[3][1], object_transform[3][2]); - selected_obj.m_centre = new_position; - - glm::vec3 scale = glm::vec3 - ( - glm::length(glm::vec3(object_transform[0])), - glm::length(glm::vec3(object_transform[1])), - glm::length(glm::vec3(object_transform[2])) - ); - selected_obj.m_radius = (scale.x + scale.y + scale.z) / 3.0f; - - DONUT_INFO("Matrix [3]: ({}, {}, {}, {})", object_transform[3][0], object_transform[3][1], object_transform[3][2], object_transform[3][3]); - DONUT_INFO("New position: ({}, {}, {})", new_position.x, new_position.y, new_position.z); - } - } - } - - auto WorldBuilderState::add_sphere() -> void - { - if (m_scene.objs.size() >= 16) - { - DONUT_WARN("Cannot add more objects. Maximum of 16 objects reached."); - return; - } - - Material material(m_new_object_color, m_new_object_specular, m_new_object_emission); - Object sphere(m_new_object_position, m_new_object_radius, material); - m_scene.objs.push_back(sphere); - - m_selected_object_index = static_cast<int>(m_scene.objs.size() - 1); - - m_new_object_position = glm::vec3(0.0f, 0.0f, 0.0f); - m_new_object_radius = 1.0f; - m_new_object_color = glm::vec3(1.0f, 1.0f, 1.0f); - m_new_object_specular = 0.5f; - m_new_object_emission = 0.0f; - - DONUT_INFO("Added sphere to scene and selected it"); - } - - auto WorldBuilderState::remove_selected_object() -> void - { - if (m_selected_object_index >= 0 && m_selected_object_index < static_cast<int>(m_scene.objs.size())) - { - m_scene.objs.erase(m_scene.objs.begin() + m_selected_object_index); - m_selected_object_index = -1; - DONUT_INFO("Removed object from scene"); - } - } - - auto WorldBuilderState::clear_scene() -> void - { - m_scene.objs.clear(); - m_selected_object_index = -1; - DONUT_INFO("Cleared scene (black hole remains at center)"); - } - - auto WorldBuilderState::save_scene() -> void - { - nlohmann::json scene_data; - scene_data["objects"] = nlohmann::json::array(); - - for (const auto& obj : m_scene.objs) - { - nlohmann::json sphere_data; - sphere_data["position"] = - { - obj.m_centre.x, - obj.m_centre.y, - obj.m_centre.z - }; - - sphere_data["color"] = - { - obj.m_material.m_color.x, - obj.m_material.m_color.y, - obj.m_material.m_color.z - }; - - sphere_data["radius"] = obj.m_radius; - sphere_data["specular"] = obj.m_material.m_specular; - sphere_data["emission"] = obj.m_material.m_emission; - scene_data["objects"].push_back(sphere_data); - } - - std::ofstream file("Scene.json"); - if (file.is_open()) - { - file << scene_data.dump(4); - file.close(); - DONUT_INFO("Scene saved to Scene.json (black hole always present at center)"); - } - else - DONUT_ERROR("Failed to save scene"); - } - - auto WorldBuilderState::load_scene() -> void - { - std::ifstream file("Scene.json"); - if (file.is_open()) - { - m_scene.objs.clear(); - m_selected_object_index = -1; - - nlohmann::json scene_data; - file >> scene_data; - - if (scene_data.contains("objects")) - { - for (const auto& sphere_data : scene_data["objects"]) - { - glm::vec3 position; - glm::vec3 color; - float radius; - float specular; - float emission; - - auto pos_array = sphere_data["position"]; - position.x = pos_array[0].get<float>(); - position.y = pos_array[1].get<float>(); - position.z = pos_array[2].get<float>(); - - auto color_array = sphere_data["color"]; - color.x = color_array[0].get<float>(); - color.y = color_array[1].get<float>(); - color.z = color_array[2].get<float>(); - - radius = sphere_data["radius"].get<float>(); - specular = sphere_data["specular"].get<float>(); - emission = sphere_data["emission"].get<float>(); - - Material material(color, specular, emission); - Object sphere(position, radius, material); - m_scene.objs.push_back(sphere); - } - } - - file.close(); - DONUT_INFO("Scene loaded from Scene.json (black hole remains at center)"); - } - else - DONUT_ERROR("Failed to load scene"); - } - - auto WorldBuilderState::initialize_sphere_geometry() -> void - { - std::vector<float> vertices; - std::vector<uint32_t> indices; - - const int segments = 32; - const int rings = 16; - - for (int ring = 0; ring <= rings; ++ring) - { - float phi = static_cast<float>(std::numbers::pi) * ring / rings; - float sin_phi = sin(phi); - float cos_phi = cos(phi); - - for (int segment = 0; segment <= segments; ++segment) - { - float theta = 2.0f * static_cast<float>(std::numbers::pi) * segment / segments; - float sin_theta = sin(theta); - float cos_theta = cos(theta); - - float x = cos_theta * sin_phi; - float y = cos_phi; - float z = sin_theta * sin_phi; - - float nx = x; - float ny = y; - float nz = z; - - vertices.push_back(x); - vertices.push_back(y); - vertices.push_back(z); - vertices.push_back(nx); - vertices.push_back(ny); - vertices.push_back(nz); - } - } - - for (int ring = 0; ring < rings; ++ring) - { - for (int segment = 0; segment < segments; ++segment) - { - uint32_t first = ring * (segments + 1) + segment; - uint32_t second = first + segments + 1; - - indices.push_back(first); - indices.push_back(second); - indices.push_back(first + 1); - - indices.push_back(second); - indices.push_back(second + 1); - indices.push_back(first + 1); - } - } - - auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); - VertexBufferLayout layout; - layout.push<float>(3); - layout.push<float>(3); - vertex_buffer->set_layout(layout); - - auto index_buffer = Ref<IndexBuffer>(IndexBuffer::create(indices.data(), static_cast<uint32_t>(indices.size()))); - - m_sphere_vao = Ref<VertexArray>(VertexArray::create()); - m_sphere_vao->add_vertex_buffer(vertex_buffer); - m_sphere_vao->set_index_buffer(index_buffer); - } - - auto WorldBuilderState::render_scene() -> void - { - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - RenderCommand::set_viewport(0, 0, width, height); - RenderCommand::enable_depth_test(); - - glm::mat4 view = m_camera.get_view_matrix(); - glm::mat4 projection = m_camera.get_projection_matrix(); - glm::mat4 view_projection = projection * view; - - glm::vec3 light_pos = m_scene.m_light_pos; - glm::vec3 camera_pos = m_camera.get_orbital_position(); - - m_sphere_shader->bind(); - m_sphere_shader->set_mat4("u_ViewProjection", view_projection); - m_sphere_shader->set_float3("u_LightPos", light_pos); - m_sphere_shader->set_float3("u_CameraPos", camera_pos); - - m_sphere_shader->set_float3("u_OutlineColor", m_outline_color); - m_sphere_shader->set_float("u_OutlineWidth", m_outline_width); - - if (m_hdri_environment) - { - m_hdri_environment->bind(1); - m_sphere_shader->set_int("u_HDRIEnvironment", 1); - } - - if (m_black_hole_initialized) - { - glm::mat4 black_hole_transform = glm::translate(glm::mat4(1.0f), m_black_hole.m_centre); - black_hole_transform = glm::scale(black_hole_transform, glm::vec3(m_black_hole.m_radius)); - - m_sphere_shader->set_mat4("u_Transform", black_hole_transform); - m_sphere_shader->set_int("u_IsSelected", 1); - m_sphere_shader->set_float3("u_Color", m_black_hole.m_material.m_color); - m_sphere_shader->set_float("u_Emission", m_black_hole.m_material.m_emission); - m_sphere_shader->set_float("u_Specular", m_black_hole.m_material.m_specular); - m_sphere_shader->set_float("u_OutlineWidth", 0.3f); - - m_sphere_vao->bind(); - RenderCommand::draw_indexed(m_sphere_vao); - - m_sphere_shader->set_float("u_OutlineWidth", m_outline_width); - } - - for (size_t i = 0; i < m_scene.objs.size(); ++i) - { - const auto& obj = m_scene.objs[i]; - - glm::mat4 transform = glm::translate(glm::mat4(1.0f), obj.m_centre); - transform = glm::scale(transform, glm::vec3(obj.m_radius)); - - m_sphere_shader->set_mat4("u_Transform", transform); - - bool is_selected = (m_selected_object_index == static_cast<int>(i)); - m_sphere_shader->set_int("u_IsSelected", is_selected ? 1 : 0); - if (is_selected) - { - glm::vec3 highlight_color = obj.m_material.m_color * 1.5f; - highlight_color = glm::clamp(highlight_color, 0.0f, 1.0f); - m_sphere_shader->set_float3("u_Color", highlight_color); - m_sphere_shader->set_float("u_Emission", 0.2f); - } - else - { - m_sphere_shader->set_float3("u_Color", obj.m_material.m_color); - m_sphere_shader->set_float("u_Emission", obj.m_material.m_emission); - } - - m_sphere_shader->set_float("u_Specular", obj.m_material.m_specular); - - m_sphere_vao->bind(); - RenderCommand::draw_indexed(m_sphere_vao); - } - - RenderCommand::disable_depth_test(); - } - - - - auto WorldBuilderState::initialize_skybox_geometry() -> void - { - float skybox_vertices[] = - { - -1.0f, 1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - - -1.0f, -1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, - - -1.0f, 1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - -1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, 1.0f - }; - - auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(skybox_vertices, sizeof(skybox_vertices))); - VertexBufferLayout layout; - layout.push<float>(3); - vertex_buffer->set_layout(layout); - - m_skybox_vao = Ref<VertexArray>(VertexArray::create()); - m_skybox_vao->add_vertex_buffer(vertex_buffer); - } - - auto WorldBuilderState::render_skybox() -> void - { - if (!m_skybox_shader || !m_skybox_vao || !m_hdri_environment) - return; - - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - RenderCommand::set_viewport(0, 0, width, height); - RenderCommand::disable_depth_test(); - - glm::mat4 view = m_camera.get_view_matrix(); - glm::mat4 projection = m_camera.get_projection_matrix(); - - view = glm::mat4(glm::mat3(view)); - - m_skybox_shader->bind(); - m_skybox_shader->set_mat4("u_View", view); - m_skybox_shader->set_mat4("u_Projection", projection); - - m_hdri_environment->bind(0); - m_skybox_shader->set_int("u_Skybox", 0); - - m_skybox_vao->bind(); - RenderCommand::draw_arrays(36); - - RenderCommand::enable_depth_test(); - } - - auto WorldBuilderState::initialize_grid_geometry() -> void - { - if (m_grid_vao) - { - m_grid_vao->unbind(); - m_grid_vao.reset(); - } - - const float grid_size = 50.0f; - const int grid_lines = 101; - const float half_size = grid_size * 0.5f; - const float step = grid_size / (grid_lines - 1); - - std::vector<float> vertices; - std::vector<uint32_t> indices; - - for (int i = 0; i < grid_lines; ++i) - { - float z = -half_size + i * step; - - vertices.push_back(-half_size); - vertices.push_back(0.0f); - vertices.push_back(z); - - vertices.push_back(half_size); - vertices.push_back(0.0f); - vertices.push_back(z); - - uint32_t base_index = static_cast<uint32_t>(vertices.size() / 3) - 2; - indices.push_back(base_index); - indices.push_back(base_index + 1); - } - - for (int i = 0; i < grid_lines; ++i) - { - float x = -half_size + i * step; - - vertices.push_back(x); - vertices.push_back(0.0f); - vertices.push_back(-half_size); - - vertices.push_back(x); - vertices.push_back(0.0f); - vertices.push_back(half_size); - - uint32_t base_index = static_cast<uint32_t>(vertices.size() / 3) - 2; - indices.push_back(base_index); - indices.push_back(base_index + 1); - } - - auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); - VertexBufferLayout layout; - layout.push<float>(3); - vertex_buffer->set_layout(layout); - - auto index_buffer = Ref<IndexBuffer>(IndexBuffer::create(indices.data(), static_cast<uint32_t>(indices.size()))); - - m_grid_vao = Ref<VertexArray>(VertexArray::create()); - m_grid_vao->add_vertex_buffer(vertex_buffer); - m_grid_vao->set_index_buffer(index_buffer); - - m_grid_vao->unbind(); - } - - auto WorldBuilderState::render_grid() -> void - { - if (!m_grid_shader || !m_grid_vao) - return; - - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - RenderCommand::set_viewport(0, 0, width, height); - RenderCommand::enable_depth_test(); - RenderCommand::enable_blending(); - - glm::mat4 view = m_camera.get_view_matrix(); - glm::mat4 projection = m_camera.get_projection_matrix(); - glm::mat4 view_projection = projection * view; - glm::mat4 transform = glm::mat4(1.0f); - - glm::vec3 camera_pos = m_camera.get_orbital_position(); - - m_grid_shader->bind(); - m_grid_shader->set_mat4("u_ViewProjection", view_projection); - m_grid_shader->set_mat4("u_Transform", transform); - m_grid_shader->set_float3("u_GridColor", m_grid_color); - m_grid_shader->set_float("u_GridAlpha", m_grid_alpha); - m_grid_shader->set_float("u_GridSize", m_grid_size); - m_grid_shader->set_float3("u_CameraPos", camera_pos); - - m_grid_vao->bind(); - RenderCommand::draw_lines(m_grid_vao); - - m_grid_vao->unbind(); - m_grid_shader->unbind(); - RenderCommand::disable_blending(); - - RenderCommand::enable_depth_test(); - } -}; diff --git a/src/states/world_builder_state.h b/src/states/world_builder_state.h deleted file mode 100644 index 8b4678a..0000000 --- a/src/states/world_builder_state.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "core/camera.h" -#include "core/state.h" -#include "core/event.h" -#include "core/log.h" - -#include "engine/scene.h" -#include "engine/object.h" - -#include "rendering/renderer.h" -#include "rendering/shader.h" -#include "rendering/vertex_array.h" - -#include <imgui.h> -#include <ImGuizmo.h> - -#include <vector> -#include <memory> - -namespace Donut -{ - class WorldBuilderState - : public State - { - public: - ~WorldBuilderState() = default; - - auto on_enter() -> void override; - auto on_exit() -> void override; - auto on_update(float delta_time) -> void override; - auto on_render() -> void override; - auto on_im_ui_render() -> void override; - auto on_event(Event& event) -> void override; - private: - auto add_sphere() -> void; - auto remove_selected_object() -> void; - auto clear_scene() -> void; - auto save_scene() -> void; - auto load_scene() -> void; - auto render_scene() -> void; - auto initialize_sphere_geometry() -> void; - auto initialize_grid_geometry() -> void; - auto render_grid() -> void; - private: - Scene m_scene; - Camera m_camera; - bool m_initialized = false; - - Ref<Shader> m_sphere_shader; - Ref<VertexArray> m_sphere_vao; - Ref<CubemapTexture> m_hdri_environment; - - Ref<Shader> m_skybox_shader; - Ref<VertexArray> m_skybox_vao; - - Ref<Shader> m_grid_shader; - Ref<VertexArray> m_grid_vao; - - glm::vec3 m_new_object_position = glm::vec3(0.0f, 0.0f, 0.0f); - float m_new_object_radius = 1.0f; - glm::vec3 m_new_object_color = glm::vec3(1.0f, 1.0f, 1.0f); - float m_new_object_specular = 0.5f; - float m_new_object_emission = 0.0f; - - int m_selected_object_index = -1; - bool m_camera_dragging = false; - glm::vec2 m_last_mouse_pos = glm::vec2(0.0f, 0.0f); - - ImGuizmo::OPERATION m_gizmo_operation = ImGuizmo::TRANSLATE; - ImGuizmo::MODE m_gizmo_mode = ImGuizmo::LOCAL; - - bool m_show_object_list = true; - bool m_show_object_creator = true; - bool m_show_scene_info = true; - bool m_show_gizmo_controls = true; - bool m_show_outline_controls = true; - bool m_show_grid = true; - - glm::vec3 m_outline_color = glm::vec3(1.0f, 1.0f, 1.0f); - float m_outline_width = 0.25f; - - glm::vec3 m_grid_color = glm::vec3(0.5f, 0.5f, 0.5f); - float m_grid_alpha = 0.5f; - float m_grid_size = 50.0f; - - Object m_black_hole; - bool m_black_hole_initialized = false; - - auto set_hdri_environment(Ref<CubemapTexture> hdri) -> void { m_hdri_environment = hdri; } - auto get_hdri_environment() const -> Ref<CubemapTexture> { return m_hdri_environment; } - - auto initialize_skybox_geometry() -> void; - auto render_skybox() -> void; - }; -}; |
