From 3d8d3259e1cf5a7d88e5d1e530cc8c9bf9140734 Mon Sep 17 00:00:00 2001 From: hachem Date: Thu, 14 Aug 2025 18:21:00 +0200 Subject: feat: I am going to throw my computer out a window --- src/engine/engine.cpp | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 src/engine/engine.cpp (limited to 'src/engine/engine.cpp') diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp new file mode 100644 index 0000000..29fa65a --- /dev/null +++ b/src/engine/engine.cpp @@ -0,0 +1,347 @@ +#include "engine.h" +#include +#include +#include +#include +#include +#include +#include "rendering/vertex_buffer.h" +#include "rendering/index_buffer.h" + +namespace Donut +{ + Engine::Engine() + : m_sag_a(glm::vec3(0.0f, 0.0f, 0.0f), + static_cast(8.54e36)) + { + GLFWwindow* window = static_cast(Application::get().get_window().get_native_window()); + glfwGetFramebufferSize(window, &m_width, &m_height); + m_compute_height = 420; + m_compute_width = (m_width * 420) / m_height; + + m_camera.set_orbital_mode(true); + m_camera.set_radius(6.34194e10); + m_camera.set_min_radius(1e10); + m_camera.set_max_radius(1e12); + m_camera.set_orbit_speed(0.01f); + m_camera.set_zoom_speed(25e9f); + + m_objects = + { + { glm::vec4(4e11f, 0.0f, 0.0f, 4e10f), glm::vec4(1,1,0,1), static_cast(1.98892e30) }, + { glm::vec4(0.0f, 0.0f, 4e11f, 4e10f), glm::vec4(1,0,0,1), static_cast(1.98892e30) }, + { glm::vec4(0.0f, 0.0f, 0.0f, m_sag_a.m_rs), glm::vec4(0,0,0,1), static_cast(m_sag_a.m_mass) } + }; + + m_quad_shader = Shader::create("assets/shaders/quad.glsl"); + m_grid_shader = Shader::create("assets/shaders/grid.glsl"); + m_compute_shader = Shader::create_compute("Geodesic", load_compute_shader("assets/shaders/geodesic.glsl")); + + m_camera_ubo = UniformBuffer::create(128, 1); + m_disk_ubo = UniformBuffer::create(sizeof(float) * 4, 2); + + uint32_t obj_ubo_size = sizeof(int) + 3 * sizeof(float) + + 16 * (sizeof(glm::vec4) + sizeof(glm::vec4)) + + 16 * sizeof(float); + m_objects_ubo = UniformBuffer::create(obj_ubo_size, 3); + + float quad_vertices[] = + { + -1.0f, 1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + m_quad_vao = VertexArray::create(); + + auto vertex_buffer = VertexBuffer::create(quad_vertices, static_cast(sizeof(quad_vertices))); + VertexBufferLayout layout; + layout.push(2); + layout.push(2); + vertex_buffer->set_layout(layout); + m_quad_vao->add_vertex_buffer(vertex_buffer); + + m_texture = Texture2D::create(m_width, m_height); + } + + void Engine::generate_grid(const std::vector& objects) + { + const int grid_size = 25; + const float spacing = 1e10f; + + std::vector vertices; + std::vector indices; + + for (int z = 0; z <= grid_size; ++z) + { + for (int x = 0; x <= grid_size; ++x) + { + float world_x = (x - grid_size / 2) * spacing; + float world_z = (z - grid_size / 2) * spacing; + float y = 0.0f; + + for (const auto& obj : objects) + { + glm::vec3 obj_pos = glm::vec3(obj.m_pos_radius); + double mass = obj.m_mass; + double radius = obj.m_pos_radius.w; + + double r_s = 2.0 * G * mass / (c * c); + double dx = world_x - obj_pos.x; + double dz = world_z - obj_pos.z; + double dist = sqrt(dx * dx + dz * dz); + + if (dist > r_s) + { + double delta_y = 2.0 * sqrt(r_s * (dist - r_s)); + y += static_cast(delta_y) - 3e10f; + } + else + { + y += 2.0f * static_cast(sqrt(r_s * r_s)) - 3e10f; + } + } + + vertices.emplace_back(world_x, y, world_z); + } + } + + for (int z = 0; z < grid_size; ++z) + { + for (int x = 0; x < grid_size; ++x) + { + int i = z * (grid_size + 1) + x; + indices.push_back(i); + indices.push_back(i + 1); + indices.push_back(i); + indices.push_back(i + grid_size + 1); + } + } + + if (!m_grid_vao) + { + m_grid_vao = Ref(VertexArray::create()); + + auto vertex_buffer = Ref(VertexBuffer::create(vertices.data(), static_cast(vertices.size() * sizeof(glm::vec3)))); + VertexBufferLayout layout; + layout.push(3); + vertex_buffer->set_layout(layout); + m_grid_vao->add_vertex_buffer(vertex_buffer); + + auto index_buffer = Ref(IndexBuffer::create(indices.data(), static_cast(indices.size()))); + m_grid_vao->set_index_buffer(index_buffer); + } + else + { + auto vertex_buffer = m_grid_vao->get_vertex_buffers()[0]; + vertex_buffer->set_data(vertices.data(), static_cast(vertices.size() * sizeof(glm::vec3))); + } + + m_grid_index_count = static_cast(indices.size()); + } + + void Engine::draw_grid(const glm::mat4& view_proj) + { + if (!m_grid_shader || !m_grid_vao) + return; + + m_grid_shader->bind(); + m_grid_shader->set_mat4("viewProj", view_proj); + + RenderCommand::disable_depth_test(); + RenderCommand::enable_blending(); + + m_grid_vao->bind(); + glDrawElements(GL_LINES, m_grid_index_count, GL_UNSIGNED_INT, nullptr); + + RenderCommand::enable_depth_test(); + } + + void Engine::update_window_dimensions() + { + GLFWwindow* window = static_cast(Application::get().get_window().get_native_window()); + int old_width = m_width; + int old_height = m_height; + glfwGetFramebufferSize(window, &m_width, &m_height); + m_compute_height = 420; + m_compute_width = (m_width * 420) / m_height; + + if (old_width != m_width || old_height != m_height) + m_texture = Texture2D::create(m_width, m_height); + } + + void Engine::draw_full_screen_quad() + { + RenderCommand::set_viewport(0, 0, m_width, m_height); + + m_quad_shader->bind(); + std::cout << "Texture ID: " << m_texture->get_renderer_id() << ", Size: " << m_texture->get_width() << "x" << m_texture->get_height() << std::endl; + m_texture->bind(0); + m_quad_shader->set_int("screenTexture", 0); + std::cout << "Set screenTexture uniform to slot 0\n"; + + RenderCommand::disable_depth_test(); + RenderCommand::draw_indexed(m_quad_vao, 6); + RenderCommand::enable_depth_test(); + } + + void Engine::dispatch_compute(const Camera& cam) + { + int cw = m_compute_width; + int ch = m_compute_height; + + if (m_texture->get_width() != cw || m_texture->get_height() != ch) + m_texture = Texture2D::create(cw, ch); + + m_compute_shader->bind(); + upload_camera_ubo(cam); + upload_disk_ubo(); + upload_objects_ubo(m_objects); + + m_texture->bind_as_image(0, false); + + uint32_t groups_x = (uint32_t)std::ceil(cw / 16.0f); + uint32_t groups_y = (uint32_t)std::ceil(ch / 16.0f); + m_compute_shader->dispatch(groups_x, groups_y, 1); + m_compute_shader->memory_barrier(IMAGE_ACCESS_BARRIER_BIT); + + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); + } + + void Engine::upload_camera_ubo(const Camera& cam) + { + struct UBOData + { + glm::vec3 pos; float _pad0; + glm::vec3 right; float _pad1; + glm::vec3 up; float _pad2; + glm::vec3 forward; float _pad3; + float tan_half_fov; + float aspect; + bool moving; + int _pad4; + } data; + + glm::vec3 fwd = glm::normalize(cam.get_target() - cam.get_orbital_position()); + glm::vec3 up = glm::vec3(0, 1, 0); + glm::vec3 right = glm::normalize(glm::cross(fwd, up)); + up = glm::cross(right, fwd); + + data.pos = cam.get_orbital_position(); + data.right = right; + data.up = up; + data.forward = fwd; + data.tan_half_fov = static_cast(tan(glm::radians(60.0f * 0.5f))); + data.aspect = static_cast(m_width) / static_cast(m_height); + data.moving = cam.is_dragging() || cam.is_panning(); + + m_camera_ubo->set_data(&data, sizeof(UBOData)); + } + + void Engine::upload_objects_ubo(const std::vector& objs) + { + 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(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)); + } + + void Engine::upload_disk_ubo() + { + float r1 = static_cast(m_sag_a.m_rs * 2.2); + float r2 = static_cast(m_sag_a.m_rs * 5.2); + float num = 2.0f; + float thickness = 1e9f; + float disk_data[4] = { r1, r2, num, thickness }; + + m_disk_ubo->set_data(disk_data, sizeof(disk_data)); + } + + void Engine::update_physics(float delta_time) + { + 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 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 acc = {direction[0] * acc1, direction[1] * acc1, direction[2] * acc1}; + + if (m_gravity) + { + obj.m_velocity.x += static_cast(acc[0]); + obj.m_velocity.y += static_cast(acc[1]); + obj.m_velocity.z += static_cast(acc[2]); + + obj.m_pos_radius.x += static_cast(obj.m_velocity.x); + obj.m_pos_radius.y += static_cast(obj.m_velocity.y); + obj.m_pos_radius.z += static_cast(obj.m_velocity.z); + } + } + } + } + } + + void Engine::render_scene() + { + glm::mat4 view = glm::lookAt(m_camera.get_orbital_position(), m_camera.get_target(), glm::vec3(0,1,0)); + glm::mat4 proj = glm::perspective(glm::radians(60.0f), float(m_width)/m_height, 1e9f, 1e14f); + glm::mat4 view_proj = proj * view; + + generate_grid(m_objects); + draw_grid(view_proj); + + RenderCommand::set_viewport(0, 0, m_width, m_height); + dispatch_compute(m_camera); + draw_full_screen_quad(); + } + + std::string Engine::load_compute_shader(const std::string& path) + { + std::ifstream in(path); + if(!in.is_open()) + { + std::cerr << "Failed to open compute shader: " << path << "\n"; + return ""; + } + + std::stringstream ss; + ss << in.rdbuf(); + std::string result = ss.str(); + if (result.empty()) + std::cerr << "Warning: Compute shader file is empty: " << path << "\n"; + else + std::cout << "Successfully loaded compute shader: " << path << " (size: " << result.size() << " bytes)\n"; + return result; + } +} -- cgit v1.3