hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/engine.cpp154
-rw-r--r--src/engine/engine.h1
2 files changed, 152 insertions, 3 deletions
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
index ef9b93d..3b5e320 100644
--- a/src/engine/engine.cpp
+++ b/src/engine/engine.cpp
@@ -3,6 +3,10 @@
#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"
@@ -325,7 +329,7 @@ namespace Donut
for (size_t i = 0; i < m_objects.size(); ++i)
{
const auto& obj = m_objects[i];
- DONUT_INFO("Object {}: Pos=({:.2e}, {:.2e}, {:.2e}), Radius={:.2e}, Mass={:.2e}, Color=({:.2f}, {:.2f}, {:.2f})",
+ 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,
@@ -333,12 +337,156 @@ namespace Donut
obj.m_color.x, obj.m_color.y, obj.m_color.z
);
}
- DONUT_INFO("Camera position: ({:.2e}, {:.2e}, {:.2e})",
+ 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: {:.2e}", m_camera.get_orbital_radius());
+ DONUT_INFO("Camera radius: {}", m_camera.get_orbital_radius());
DONUT_INFO("========================");
}
+
+ void Engine::export_high_res_frame(const std::string& filename, int width, int height)
+ {
+ 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;
+ }
+
+ high_res_framebuffer->bind();
+
+ RenderCommand::set_viewport(0, 0, width, height);
+ RenderCommand::clear();
+
+ auto high_res_texture = Texture2D::create(compute_width, compute_height);
+ if (!high_res_texture)
+ {
+ DONUT_ERROR("Failed to create high-resolution texture");
+ return;
+ }
+
+ high_res_texture->set_data(nullptr, compute_width * compute_height * 4);
+ 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();
+ high_res_texture->bind_as_image(0, false);
+
+ uint32_t groups_x = static_cast<uint32_t>(std::ceil(compute_width / 16.0f));
+ uint32_t groups_y = static_cast<uint32_t>(std::ceil(compute_height / 16.0f));
+ m_compute_program->dispatch(groups_x, groups_y, 1);
+ m_compute_program->memory_barrier(IMAGE_ACCESS_BARRIER_BIT);
+
+ 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
index b0e06f3..fab895e 100644
--- a/src/engine/engine.h
+++ b/src/engine/engine.h
@@ -101,6 +101,7 @@ namespace Donut
void set_early_exit_distance(float distance) { m_early_exit_distance = distance; }
void load_objects_from_scene(const std::vector<Donut::Object>& objects);
+ void export_high_res_frame(const std::string& filename, int width = 4096, int height = 3072);
void print_object_info() const;
private:
Ref<Shader> create_compute_program(const char* path);