diff options
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | src/Core/Application.cpp | 238 | ||||
| -rw-r--r-- | src/Core/Application.h | 53 | ||||
| -rw-r--r-- | src/Core/Camera.cpp | 225 | ||||
| -rw-r--r-- | src/Core/Camera.h | 131 | ||||
| -rw-r--r-- | src/Core/Event.h | 362 | ||||
| -rw-r--r-- | src/Core/Log.cpp | 156 | ||||
| -rw-r--r-- | src/Core/Log.h | 156 | ||||
| -rw-r--r-- | src/Core/Memory.h | 24 | ||||
| -rw-r--r-- | src/Core/State.h | 19 | ||||
| -rw-r--r-- | src/Core/Window.cpp | 341 | ||||
| -rw-r--r-- | src/Core/Window.h | 78 | ||||
| -rw-r--r-- | src/Engine/Engine.cpp | 614 | ||||
| -rw-r--r-- | src/Engine/Engine.h | 184 | ||||
| -rw-r--r-- | src/Engine/Object.h | 76 | ||||
| -rw-r--r-- | src/Engine/Scene.h | 70 | ||||
| -rw-r--r-- | src/Rendering/Framebuffer.cpp | 17 | ||||
| -rw-r--r-- | src/Rendering/Framebuffer.h | 65 | ||||
| -rw-r--r-- | src/Rendering/Renderer.cpp | 64 | ||||
| -rw-r--r-- | src/Rendering/Renderer.h | 158 | ||||
| -rw-r--r-- | src/Rendering/Shader.cpp | 84 | ||||
| -rw-r--r-- | src/Rendering/Shader.h | 58 | ||||
| -rw-r--r-- | src/Rendering/Texture.cpp | 68 | ||||
| -rw-r--r-- | src/Rendering/Texture.h | 42 |
24 files changed, 1 insertions, 3284 deletions
@@ -1,4 +1,4 @@ - + A real-time black hole ray tracer. ## Table of Contents diff --git a/src/Core/Application.cpp b/src/Core/Application.cpp deleted file mode 100644 index 667fc73..0000000 --- a/src/Core/Application.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "application.h" - -#include "rendering/renderer.h" -#include "settings_manager.h" - -#include "states/simulation_state.h" -#include "states/config_state.h" -#include "states/world_builder_state.h" - -#include <GLFW/glfw3.h> -#include <imgui.h> -#include <ImGuizmo.h> - -#include "platform/vulkan/vulkan_renderer.h" - -#ifdef __APPLE__ -#include "platform/metal/metal_context.h" -#include "platform/vulkan/vulkan_context.h" -#endif - -namespace Donut -{ - Application* Application::s_instance = nullptr; - - Application::Application(const std::string& name, int width, int height) - : m_running(true), m_minimized(false) - { - s_instance = this; - - // Select the render API before the window is created: the window is - // built differently for Vulkan (GLFW_NO_API) than for OpenGL. - Logger::init(); - SettingsManager::initialize(); - { - const auto& settings = SettingsManager::get_settings_const(); - RendererAPI::set_api(settings.graphics.render_api == "Vulkan" - ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL); - } - - if (RendererAPI::get_api() == RendererAPI::API::Vulkan) - vulkan_prepare_glfw(); // must precede glfwInit() inside the Window ctor - - m_window = create_scope<Window>(name, width, height); - m_window->set_event_callback([this](Event& event) - { - on_event(event); - }); - - on_init(); - } - - Application::~Application() - { - on_shutdown(); - s_instance = nullptr; - } - - auto Application::run() -> void - { - while (m_running) - { - if (m_vulkan_renderer) - { - glfwPollEvents(); // before the ImGui frame so input is current - if (!m_minimized) - m_vulkan_renderer->draw_frame(glm::vec4(0.05f, 0.06f, 0.10f, 1.0f), - [this] { build_vulkan_ui(); }); - } - else - { - if (!m_minimized) - { - on_update(); - on_render(); - } - m_window->on_update(); // polls events + swaps buffers (OpenGL) - } - } - } - - auto Application::build_vulkan_ui() -> void - { - // Placeholder UI proving the ImGui Vulkan backend renders. The real - // application UI (states' on_im_ui_render) moves here once the scene is - // ported to Vulkan (B-3). - ImGui::Begin("Donut - Vulkan backend"); - ImGui::Text("Geodesic black hole through Vulkan (MoltenVK)."); - ImGui::Text("%.1f FPS", ImGui::GetIO().Framerate); - ImGui::Separator(); - ImGui::TextWrapped("Drag to orbit, scroll to zoom. HDRI starfield is live; " - "next is porting the simulation UI to Vulkan."); - ImGui::End(); - } - - auto Application::close() -> void - { - m_running = false; - } - - auto Application::on_event(Event& event) -> void - { - EventDispatcher dispatcher(event); - dispatcher.dispatch<WindowCloseEvent>([this, &event](WindowCloseEvent& e) - { - m_running = false; - event.handled = true; - return true; - }); - - dispatcher.dispatch<WindowResizeEvent>([this, &event](WindowResizeEvent& e) - { - if (e.get_width() == 0 || e.get_height() == 0) - m_minimized = true; - else - m_minimized = false; - - if (m_vulkan_renderer) - { - m_vulkan_renderer->on_resize(e.get_width(), e.get_height()); - } - else - { - Renderer::on_window_resize(e.get_width(), e.get_height()); - if (m_engine) m_engine->set_window_dimensions(e.get_width(), e.get_height()); - } - event.handled = true; - return true; - }); - - dispatcher.dispatch<KeyPressedEvent>([this, &event](KeyPressedEvent& e) - { - if (!m_state_manager) - return true; - if (e.get_key_code() == GLFW_KEY_1) - { - m_state_manager->switch_to_state("Config"); - event.handled = true; - return true; - } - else if (e.get_key_code() == GLFW_KEY_2) - { - m_state_manager->switch_to_state("Simulation"); - event.handled = true; - return true; - } - else if (e.get_key_code() == GLFW_KEY_3) - { - m_state_manager->switch_to_state("WorldBuilder"); - event.handled = true; - return true; - } - - return true; - }); - - if (m_state_manager) - m_state_manager->on_event(event); - } - - auto Application::on_init() -> void - { - // (Logger, settings and API selection happen in the constructor.) - - if (RendererAPI::get_api() == RendererAPI::API::Vulkan) - { - int w = 0, h = 0; - glfwGetFramebufferSize((GLFWwindow*)m_window->get_native_window(), &w, &h); - m_vulkan_renderer = create_scope<VulkanRenderer>(); - if (!m_vulkan_renderer->init(m_window->get_native_window(), w, h)) - DONUT_ERROR("Vulkan renderer initialization failed"); - else - m_vulkan_renderer->init_im_gui(); - // Scene rendering hooks in here in the B-3 phase; the Vulkan path now - // clears, presents, and draws the ImGui UI. - return; - } - - Renderer::init(); - m_window->init_im_gui(); - - Renderer::on_window_resize(1280, 720); - RenderCommand::set_face_culling(false); - - m_engine = create_scope<Engine>(); - m_engine->set_window_dimensions(1280, 720); - - m_state_manager = create_scope<StateManager>(); - m_state_manager->register_state("Config", create_scope<ConfigState>()); - m_state_manager->register_state("Simulation", create_scope<SimulationState>()); - m_state_manager->register_state("WorldBuilder", create_scope<WorldBuilderState>()); - m_state_manager->switch_to_state("Config"); - } - - auto Application::on_shutdown() -> void - { - if (m_vulkan_renderer) - { - m_vulkan_renderer->shutdown(); - m_vulkan_renderer.reset(); - } - else - { - if (m_state_manager) - m_state_manager->shutdown(); - Renderer::shutdown(); - } - SettingsManager::shutdown(); - Logger::shutdown(); - } - - auto Application::on_update() -> void - { - float current_frame = (float)glfwGetTime(); - m_delta_time = current_frame - m_last_frame; - m_last_frame = current_frame; - - m_state_manager->update(m_delta_time); - } - - auto Application::on_render() -> void - { - m_state_manager->render(); - m_window->begin_im_gui_frame(); - - ImGuizmo::BeginFrame(); - ImGuizmo::SetOrthographic(false); - - setup_docking_layout(); - m_state_manager->on_im_ui_render(); - m_window->end_im_gui_frame(); - } - - auto Application::setup_docking_layout() -> void - { - ImGuiViewport* viewport = ImGui::GetMainViewport(); - ImGui::DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags_PassthruCentralNode); - } -}; diff --git a/src/Core/Application.h b/src/Core/Application.h deleted file mode 100644 index 06c4e94..0000000 --- a/src/Core/Application.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "state_manager.h" -#include "memory.h" -#include "window.h" -#include "event.h" -#include "log.h" - -#include "engine/engine.h" - -namespace Donut -{ - class VulkanRenderer; // live-window Vulkan backend (platform/vulkan) - - class Application - { - public: - Application(const std::string& name = "Donut", - int width = 1280, int height = 720); - ~Application(); - - auto run() -> void; - auto close() -> void; - - auto get_window() -> Window& { return *m_window; } - auto get_state_manager() -> StateManager& { return *m_state_manager; } - auto get_engine() -> Engine& { return *m_engine; } - static auto get() -> Application& { return *s_instance; } - - private: - auto on_init() -> void; - auto on_shutdown() -> void; - auto on_update() -> void; - auto on_render() -> void; - auto on_event(Event& event) -> void; - auto setup_docking_layout() -> void; - auto build_vulkan_ui() -> void; // ImGui UI built each frame on the Vulkan path - - private: - Scope<StateManager> m_state_manager; - Scope<Window> m_window; - Scope<Engine> m_engine; - Scope<VulkanRenderer> m_vulkan_renderer; // non-null only when the Vulkan API is selected - - bool m_running; - bool m_minimized; - - float m_delta_time = 0.0f; - float m_last_frame = 0.0f; - - static Application* s_instance; - }; -} diff --git a/src/Core/Camera.cpp b/src/Core/Camera.cpp deleted file mode 100644 index 35b7a2f..0000000 --- a/src/Core/Camera.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "camera.h" - -#include <glm/gtc/quaternion.hpp> -#include <GLFW/glfw3.h> - -namespace Donut -{ - Camera::Camera(float fov, float aspect_ratio, float near_plane, float far_plane) - : m_fov(fov), m_aspect_ratio(aspect_ratio), m_near_plane(near_plane), m_far_plane(far_plane) - { - recalculate_projection_matrix(); - recalculate_view_matrix(); - } - - auto Camera::set_projection(float fov, float aspect_ratio, float near_plane, float far_plane) -> void - { - m_fov = fov; - m_aspect_ratio = aspect_ratio; - m_near_plane = near_plane; - m_far_plane = far_plane; - recalculate_projection_matrix(); - } - - auto Camera::recalculate_projection_matrix() -> void - { - m_projection_matrix = glm::perspective(glm::radians(m_fov), m_aspect_ratio, m_near_plane, m_far_plane); - m_view_projection_matrix = m_projection_matrix * m_view_matrix; - } - - auto Camera::recalculate_view_matrix() -> void - { - if (m_camera_mode == CameraMode::FPS) - { - float pitch = glm::radians(m_rotation.x); - float yaw = glm::radians(m_rotation.y); - float roll = glm::radians(m_rotation.z); - - glm::vec3 direction; - direction.x = cos(yaw) * cos(pitch); - direction.y = sin(pitch); - direction.z = sin(yaw) * cos(pitch); - - glm::vec3 world_up(0.0f, 1.0f, 0.0f); - glm::vec3 front = glm::normalize(direction); - glm::vec3 right = glm::normalize(glm::cross(front, world_up)); - glm::vec3 up = glm::normalize(glm::cross(right, front)); - - m_view_matrix = glm::lookAt(m_position, m_position + front, up); - m_view_projection_matrix = m_projection_matrix * m_view_matrix; - } - else if (m_camera_mode == CameraMode::Orbital) - { - glm::vec3 position = get_orbital_position(); - glm::vec3 target = m_orbital_target; - glm::vec3 up(0.0f, 1.0f, 0.0f); - - m_view_matrix = glm::lookAt(position, target, up); - m_view_projection_matrix = m_projection_matrix * m_view_matrix; - } - } - - auto Camera::get_forward_direction() const -> glm::vec3 - { - float pitch = glm::radians(m_rotation.x); - float yaw = glm::radians(m_rotation.y); - - glm::vec3 direction; - direction.x = cos(yaw) * cos(pitch); - direction.y = sin(pitch); - direction.z = sin(yaw) * cos(pitch); - - return glm::normalize(direction); - } - - auto Camera::get_right_direction() const -> glm::vec3 - { - glm::vec3 world_up(0.0f, 1.0f, 0.0f); - return glm::normalize(glm::cross(get_forward_direction(), world_up)); - } - - auto Camera::get_up_direction() const -> glm::vec3 - { - return glm::normalize(glm::cross(get_right_direction(), get_forward_direction())); - } - - auto Camera::on_mouse_move(float x_offset, float y_offset, bool constrain_pitch) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - x_offset *= m_mouse_sensitivity; - y_offset *= m_mouse_sensitivity; - - m_rotation.y += x_offset; - m_rotation.x += y_offset; - - if (constrain_pitch) - { - if (m_rotation.x > 89.0f) - m_rotation.x = 89.0f; - if (m_rotation.x < -89.0f) - m_rotation.x = -89.0f; - } - - recalculate_view_matrix(); - } - } - - auto Camera::move_forward(float delta_time) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - m_position += get_forward_direction() * m_movement_speed * delta_time; - recalculate_view_matrix(); - } - } - - auto Camera::move_backward(float delta_time) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - m_position -= get_forward_direction() * m_movement_speed * delta_time; - recalculate_view_matrix(); - } - } - - auto Camera::move_right(float delta_time) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - m_position += get_right_direction() * m_movement_speed * delta_time; - recalculate_view_matrix(); - } - } - - auto Camera::move_left(float delta_time) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - m_position -= get_right_direction() * m_movement_speed * delta_time; - recalculate_view_matrix(); - } - } - - auto Camera::move_up(float delta_time) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - glm::vec3 world_up(0.0f, 1.0f, 0.0f); - m_position += world_up * m_movement_speed * delta_time; - recalculate_view_matrix(); - } - } - - auto Camera::move_down(float delta_time) -> void - { - if (m_camera_mode == CameraMode::FPS) - { - glm::vec3 world_up(0.0f, 1.0f, 0.0f); - m_position -= world_up * m_movement_speed * delta_time; - recalculate_view_matrix(); - } - } - - auto Camera::get_orbital_position() const -> glm::vec3 - { - float clamped_elevation = glm::clamp(m_elevation, 0.01f, float(std::numbers::pi) - 0.01f); - return glm::vec3 - ( - m_orbital_radius * sin(clamped_elevation) * cos(m_azimuth), - m_orbital_radius * cos(clamped_elevation), - m_orbital_radius * sin(clamped_elevation) * sin(m_azimuth) - ); - } - - auto Camera::update_orbital() -> void - { - m_orbital_target = glm::vec3(0.0f, 0.0f, 0.0f); - if (m_dragging || m_panning) - m_moving = true; - else - m_moving = false; - recalculate_view_matrix(); - } - - auto Camera::process_orbital_mouse_move(double x, double y) -> void - { - if (m_dragging && !m_panning) - { - float dx = float(x - m_last_x_orbital); - float dy = float(y - m_last_y_orbital); - - m_azimuth += dx * m_orbital_speed; - m_elevation -= dy * m_orbital_speed; - m_elevation = glm::clamp(m_elevation, 0.01f, float(std::numbers::pi) - 0.01f); - } - - m_last_x_orbital = x; - m_last_y_orbital = y; - update_orbital(); - } - - auto Camera::process_orbital_mouse_button(int button, int action, int mods) -> void - { - if (button == GLFW_MOUSE_BUTTON_LEFT) - { - if (action == GLFW_PRESS) - { - m_dragging = true; - m_panning = false; - } - else if (action == GLFW_RELEASE) - { - m_dragging = false; - m_panning = false; - } - } - } - - auto Camera::process_orbital_scroll(double x_offset, double y_offset) -> void - { - m_orbital_radius -= y_offset * m_zoom_speed; - m_orbital_radius = glm::clamp(m_orbital_radius, m_orbital_min_radius, m_orbital_max_radius); - update_orbital(); - } -} diff --git a/src/Core/Camera.h b/src/Core/Camera.h deleted file mode 100644 index c997c35..0000000 --- a/src/Core/Camera.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include <glm/glm.hpp> -#include <glm/gtc/matrix_transform.hpp> - -#include <numbers> - -namespace Donut -{ - enum class CameraMode - { - FPS, - Orbital - }; - - class Camera - { - public: - Camera(float fov = 45.0f, float aspect_ratio = 16.0f / 9.0f, - float near_plane = 0.1f, float far_plane = 100.0f); - ~Camera() = default; - - auto set_position(const glm::vec3& position) -> void { m_position = position; recalculate_view_matrix(); } - auto set_rotation(const glm::vec3& rotation) -> void { m_rotation = rotation; recalculate_view_matrix(); } - - auto get_position() const -> const glm::vec3& { return m_position; } - auto get_rotation() const -> const glm::vec3& { return m_rotation; } - - auto get_forward_direction() const -> glm::vec3; - auto get_right_direction() const -> glm::vec3; - auto get_up_direction() const -> glm::vec3; - - auto get_projection_matrix() const -> const glm::mat4& { return m_projection_matrix; } - auto get_view_matrix() const -> const glm::mat4& { return m_view_matrix; } - auto get_view_projection_matrix() const -> const glm::mat4& { return m_view_projection_matrix; } - - auto set_projection(float fov, float aspect_ratio, float near_plane, float far_plane) -> void; - auto on_mouse_move(float x_offset, float y_offset, bool constrain_pitch = true) -> void; - - auto move_forward(float delta_time) -> void; - auto move_backward(float delta_time) -> void; - auto move_right(float delta_time) -> void; - auto move_left(float delta_time) -> void; - auto move_up(float delta_time) -> void; - auto move_down(float delta_time) -> void; - - auto set_mouse_sensitivity(float sensitivity) -> void { m_mouse_sensitivity = sensitivity; } - auto get_mouse_sensitivity() const -> float { return m_mouse_sensitivity; } - - auto set_movement_speed(float speed) -> void { m_movement_speed = speed; } - auto get_movement_speed() const -> float { return m_movement_speed; } - - auto set_orbital_target(const glm::vec3& target) -> void { m_orbital_target = target; } - auto get_orbital_target() const -> const glm::vec3& { return m_orbital_target; } - - auto set_orbital_radius(double radius) -> void { m_orbital_radius = radius; } - auto get_orbital_radius() const -> double { return m_orbital_radius; } - - auto set_orbital_limits(double min_radius, double max_radius) -> void - { - m_orbital_min_radius = min_radius; - m_orbital_max_radius = max_radius; - } - - auto set_orbital_speed(float speed) -> void { m_orbital_speed = speed; } - auto get_orbital_speed() const -> float { return m_orbital_speed; } - - auto set_zoom_speed(double speed) -> void { m_zoom_speed = speed; } - auto get_zoom_speed() const -> double { return m_zoom_speed; } - - auto set_azimuth(float azimuth) -> void { m_azimuth = azimuth; } - auto get_azimuth() const -> float { return m_azimuth; } - - auto set_elevation(float elevation) -> void { m_elevation = elevation; } - auto get_elevation() const -> float { return m_elevation; } - - auto get_orbital_position() const -> glm::vec3; - auto update_orbital() -> void; - auto process_orbital_mouse_move(double x, double y) -> void; - auto process_orbital_mouse_button(int button, int action, int mods) -> void; - auto process_orbital_scroll(double x_offset, double y_offset) -> void; - - auto set_camera_mode(CameraMode mode) -> void { m_camera_mode = mode; } - auto get_camera_mode() const -> CameraMode { return m_camera_mode; } - - auto is_dragging() const -> bool { return m_dragging; } - auto is_panning() const -> bool { return m_panning; } - auto is_moving() const -> bool { return m_moving; } - auto get_last_x() const -> double { return m_last_x; } - auto get_last_y() const -> double { return m_last_y; } - - private: - auto recalculate_view_matrix() -> void; - auto recalculate_projection_matrix() -> void; - - private: - CameraMode m_camera_mode = CameraMode::FPS; - - glm::mat4 m_projection_matrix; - glm::mat4 m_view_matrix; - glm::mat4 m_view_projection_matrix; - - glm::vec3 m_position = { 0.0f, 0.0f, 3.0f }; - glm::vec3 m_rotation = { 0.0f, 0.0f, 0.0f }; - - float m_fov = 45.0f; - float m_aspect_ratio = 16.0f / 9.0f; - float m_near_plane = 0.1f; - float m_far_plane = 100.0f; - - float m_mouse_sensitivity = 0.1f; - float m_movement_speed = 5.0f; - bool m_first_mouse = true; - float m_last_x = 0.0f; - float m_last_y = 0.0f; - - glm::vec3 m_orbital_target = glm::vec3(0.0f, 0.0f, 0.0f); - double m_orbital_radius = 6.34194e10; - double m_orbital_min_radius = 1e10; - double m_orbital_max_radius = 1e12; - float m_azimuth = 0.0f; - float m_elevation = static_cast<float>(std::numbers::pi) / 2.0f; - float m_orbital_speed = 0.01f; - double m_zoom_speed = 25e9f; - bool m_dragging = false; - bool m_panning = false; - bool m_moving = false; - double m_last_x_orbital = 0.0; - double m_last_y_orbital = 0.0; - }; -} diff --git a/src/Core/Event.h b/src/Core/Event.h deleted file mode 100644 index 1891206..0000000 --- a/src/Core/Event.h +++ /dev/null @@ -1,362 +0,0 @@ -#pragma once - -#include <functional> -#include <unordered_map> -#include <vector> -#include <string> -#include <sstream> - -namespace Donut -{ - class Event; - class EventDispatcher; - - enum class EventType - { - None = 0, - - WindowClose, - WindowResize, - WindowFocus, - WindowLostFocus, - WindowMoved, - - KeyPressed, - KeyReleased, - KeyTyped, - - MouseButtonPressed, - MouseButtonReleased, - MouseMoved, - MouseScrolled - }; - - enum EventCategory - { - None = 0, - EventCategoryApplication = 1 << 0, - EventCategoryInput = 1 << 1, - EventCategoryKeyboard = 1 << 2, - EventCategoryMouse = 1 << 3, - EventCategoryMouseButton = 1 << 4 - }; - - class Event - { - public: - virtual ~Event() = default; - - virtual auto get_event_type() const -> EventType = 0; - virtual auto get_name() const -> const char* = 0; - virtual auto get_category_flags() const -> int = 0; - virtual auto to_string() const -> std::string { return get_name(); } - - auto is_in_category(EventCategory category) -> bool { return get_category_flags() & category; } - - bool handled = false; - }; - - #define EVENT_CLASS_TYPE(type) \ - static auto get_static_type() -> EventType { return EventType::type; } \ - virtual auto get_event_type() const -> EventType override { return get_static_type(); } \ - virtual auto get_name() const -> const char* override { return #type; } - - #define APPLICATION_EVENT_CLASS_TYPE(type) \ - EVENT_CLASS_TYPE(type) \ - virtual auto get_category_flags() const -> int override { return EventCategoryApplication; } - - #define MOUSE_EVENT_CLASS_TYPE(type) \ - EVENT_CLASS_TYPE(type) \ - virtual auto get_category_flags() const -> int override { return EventCategoryMouse | \ - EventCategoryInput; } - - #define MOUSE_BUTTON_EVENT_CLASS_TYPE(type) \ - EVENT_CLASS_TYPE(type) \ - virtual auto get_category_flags() const -> int override { return EventCategoryMouseButton | \ - EventCategoryMouse | \ - EventCategoryInput; } - - #define KEYBOARD_EVENT_CLASS_TYPE(type) \ - EVENT_CLASS_TYPE(type) \ - virtual auto get_category_flags() const -> int override { return EventCategoryKeyboard | \ - EventCategoryInput; } - - class WindowResizeEvent - : public Event - { - public: - WindowResizeEvent(unsigned int width, unsigned int height) - : m_width(width), m_height(height) { } - - auto get_width() const -> unsigned int { return m_width; } - auto get_height() const -> unsigned int { return m_height; } - - auto to_string() const -> std::string override - { - return "WindowResizeEvent: " + std::to_string(m_width) + ", " + std::to_string(m_height); - } - - APPLICATION_EVENT_CLASS_TYPE(WindowResize) - - private: - unsigned int m_width, m_height; - }; - - class WindowCloseEvent - : public Event - { - public: - WindowCloseEvent() = default; - APPLICATION_EVENT_CLASS_TYPE(WindowClose) - }; - - class WindowFocusEvent - : public Event - { - public: - WindowFocusEvent() = default; - APPLICATION_EVENT_CLASS_TYPE(WindowFocus) - }; - - class WindowLostFocusEvent - : public Event - { - public: - WindowLostFocusEvent() = default; - APPLICATION_EVENT_CLASS_TYPE(WindowLostFocus) - }; - - class WindowMovedEvent - : public Event - { - public: - WindowMovedEvent(int x, int y) - : m_x(x), m_y(y) { } - - auto get_x() const -> int { return m_x; } - auto get_y() const -> int { return m_y; } - - auto to_string() const -> std::string override - { - return "WindowMovedEvent: " + std::to_string(m_x) + ", " + std::to_string(m_y); - } - - APPLICATION_EVENT_CLASS_TYPE(WindowMoved) - - private: - int m_x, m_y; - }; - - class KeyEvent - : public Event - { - public: - auto get_key_code() const -> int { return m_key_code; } - virtual auto get_category_flags() const -> int override { return EventCategoryKeyboard | - EventCategoryInput; } - - protected: - KeyEvent(int keycode) - : m_key_code(keycode) { } - int m_key_code; - }; - - class KeyPressedEvent - : public KeyEvent - { - public: - KeyPressedEvent(int keycode, bool is_repeat = false) - : KeyEvent(keycode), m_is_repeat(is_repeat) { } - - auto is_repeat() const -> bool { return m_is_repeat; } - - auto to_string() const -> std::string override - { - return "KeyPressedEvent: " + std::to_string(m_key_code) + - " (repeat = " + std::to_string(m_is_repeat) + ")"; - } - - KEYBOARD_EVENT_CLASS_TYPE(KeyPressed) - - private: - bool m_is_repeat; - }; - - class KeyReleasedEvent - : public KeyEvent - { - public: - KeyReleasedEvent(int keycode) - : KeyEvent(keycode) { } - - auto to_string() const -> std::string override - { - return "KeyReleasedEvent: " + std::to_string(m_key_code); - } - - KEYBOARD_EVENT_CLASS_TYPE(KeyReleased) - }; - - class KeyTypedEvent - : public KeyEvent - { - public: - KeyTypedEvent(int keycode) - : KeyEvent(keycode) { } - - auto to_string() const -> std::string override - { - return "KeyTypedEvent: " + std::to_string(m_key_code); - } - - KEYBOARD_EVENT_CLASS_TYPE(KeyTyped) - }; - - class MouseMovedEvent - : public Event - { - public: - MouseMovedEvent(float x, float y) - : m_mouse_x(x), m_mouse_y(y) { } - - auto get_x() const -> float { return m_mouse_x; } - auto get_y() const -> float { return m_mouse_y; } - - auto to_string() const -> std::string override - { - return "MouseMovedEvent: " + std::to_string(m_mouse_x) + ", " + std::to_string(m_mouse_y); - } - - MOUSE_EVENT_CLASS_TYPE(MouseMoved) - - private: - float m_mouse_x, m_mouse_y; - }; - - class MouseScrolledEvent - : public Event - { - public: - MouseScrolledEvent(float x_offset, float y_offset) - : m_x_offset(x_offset), m_y_offset(y_offset) { } - - auto get_x_offset() const -> float { return m_x_offset; } - auto get_y_offset() const -> float { return m_y_offset; } - - auto to_string() const -> std::string override - { - return "MouseScrolledEvent: " + std::to_string(m_x_offset) + - ", " + std::to_string(m_y_offset); - } - - MOUSE_EVENT_CLASS_TYPE(MouseScrolled) - - private: - float m_x_offset, m_y_offset; - }; - - class MouseButtonEvent - : public Event - { - public: - auto get_mouse_button() const -> int { return m_button; } - virtual auto get_category_flags() const -> int override { return EventCategoryMouseButton | - EventCategoryMouse | - EventCategoryInput; } - - protected: - MouseButtonEvent(int button) - : m_button(button) { } - int m_button; - }; - - class MouseButtonPressedEvent - : public MouseButtonEvent - { - public: - MouseButtonPressedEvent(int button) - : MouseButtonEvent(button) { } - - auto to_string() const -> std::string override - { - return "MouseButtonPressedEvent: " + std::to_string(m_button); - } - - MOUSE_BUTTON_EVENT_CLASS_TYPE(MouseButtonPressed) - }; - - class MouseButtonReleasedEvent - : public MouseButtonEvent - { - public: - MouseButtonReleasedEvent(int button) - : MouseButtonEvent(button) { } - - auto to_string() const -> std::string override - { - return "MouseButtonReleasedEvent: " + std::to_string(m_button); - } - - MOUSE_BUTTON_EVENT_CLASS_TYPE(MouseButtonReleased) - }; - - class EventDispatcher - { - public: - EventDispatcher(Event& event) - : m_event(event) { } - - template<typename T, typename F> - auto dispatch(const F& func) -> bool - { - if (m_event.get_event_type() == T::get_static_type()) - { - m_event.handled = func(static_cast<T&>(m_event)); - return true; - } - return false; - } - - private: - Event& m_event; - }; - - class EventHandler - { - public: - using EventCallbackFn = std::function<void(Event&)>; - - EventHandler() = default; - ~EventHandler() = default; - - auto set_event_callback(const EventCallbackFn& callback) -> void - { - m_event_callback = callback; - } - - auto on_event(Event& event) -> void - { - if (m_event_callback) - m_event_callback(event); - } - - template<typename T> - auto bind_event(const std::function<void(T&)>& callback) -> void - { - m_event_callback = [callback](Event& event) - { - if (event.get_event_type() == T::get_static_type()) - callback(static_cast<T&>(event)); - }; - } - - private: - EventCallbackFn m_event_callback; - }; - - #undef EVENT_CLASS_TYPE - #undef APPLICATION_EVENT_CLASS_TYPE - #undef MOUSE_EVENT_CLASS_TYPE - #undef MOUSE_BUTTON_EVENT_CLASS_TYPE - #undef KEYBOARD_EVENT_CLASS_TYPE -} diff --git a/src/Core/Log.cpp b/src/Core/Log.cpp deleted file mode 100644 index 5a0434f..0000000 --- a/src/Core/Log.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "log.h" - -#include <filesystem> - -#if defined(DONUT_WINDOWS) - #include <windows.h> -#endif - -namespace Donut -{ - Ref<Logger> Logger::s_logger; - - auto Logger::init() -> void - { - s_logger = create_ref<Logger>(); - s_logger->set_log_level(LogLevel::Info); - s_logger->enable_console_output(true); - s_logger->enable_file_output(true); - s_logger->set_log_file("logs/donut.log"); - - s_logger->log_message(LogLevel::Info, "Logging system initialized"); - } - - auto Logger::shutdown() -> void - { - if (s_logger) - s_logger->log_message(LogLevel::Info, "Shutting down logging system"); - s_logger.reset(); - } - - auto Logger::get_logger() -> Ref<Logger> - { - return s_logger; - } - - Logger::Logger() - : m_log_level(LogLevel::Info), - m_console_output(true), - m_file_output(false) { } - - Logger::~Logger() - { - if (m_log_file.is_open()) - m_log_file.close(); - } - - auto Logger::set_log_file(const std::string& filename) -> void - { - std::filesystem::path log_path(filename); - std::filesystem::create_directories(log_path.parent_path()); - - m_log_file.open(filename, std::ios::app); - if (!m_log_file.is_open()) - std::cerr << "Failed to open log file: " << filename << std::endl; - } - - auto Logger::get_time_stamp() -> std::string - { - auto now = std::chrono::system_clock::now(); - auto time = std::chrono::system_clock::to_time_t(now); - - std::stringstream ss; - ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S"); - - return ss.str(); - } - - auto Logger::get_log_level_string(LogLevel level) -> std::string - { - switch (level) - { - case LogLevel::trace: return "TRACE"; - case LogLevel::Info: return "INFO"; - case LogLevel::Warn: return "WARN"; - case LogLevel::Err: return "ERROR"; - case LogLevel::Fatal: return "FATAL"; - default: return "UNKNOWN"; - } - } - - auto Logger::set_console_color(LogLevel level) -> void - { -#if defined(DONUT_WINDOWS) - HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); - WORD color; - - switch (level) { - case LogLevel::trace: - color = FOREGROUND_RED | - FOREGROUND_GREEN | - FOREGROUND_BLUE; - break; - case LogLevel::Info: - color = FOREGROUND_GREEN | - FOREGROUND_INTENSITY; - break; - case LogLevel::Warn: - color = FOREGROUND_RED | - FOREGROUND_GREEN | - FOREGROUND_INTENSITY; - break; - case LogLevel::Err: - color = FOREGROUND_RED | - FOREGROUND_INTENSITY; - break; - case LogLevel::Fatal: - color = FOREGROUND_RED | - FOREGROUND_BLUE | - FOREGROUND_INTENSITY; - break; - default: - color = FOREGROUND_RED | - FOREGROUND_GREEN | - FOREGROUND_BLUE; - break; - } - - SetConsoleTextAttribute(h_console, color); -#else - const char* color_code; - switch (level) { - case LogLevel::trace: - color_code = "\033[37m"; - break; - case LogLevel::Info: - color_code = "\033[32;1m"; - break; - case LogLevel::Warn: - color_code = "\033[33;1m"; - break; - case LogLevel::Err: - color_code = "\033[31;1m"; - break; - case LogLevel::Fatal: - color_code = "\033[35;1m"; - break; - default: - color_code = "\033[37m"; - break; - } - std::cout << color_code; -#endif - } - - auto Logger::reset_console_color() -> void - { -#if defined(DONUT_WINDOWS) - HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleTextAttribute(h_console, FOREGROUND_RED | - FOREGROUND_GREEN | - FOREGROUND_BLUE); -#else - std::cout << "\033[0m"; -#endif - } -} diff --git a/src/Core/Log.h b/src/Core/Log.h deleted file mode 100644 index db6b4b4..0000000 --- a/src/Core/Log.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once - -#include "core/memory.h" - -#include <string> -#include <vector> -#include <sstream> -#include <iostream> -#include <fstream> -#include <chrono> -#include <iomanip> -#include <mutex> -#include <string_view> - -namespace Donut -{ - enum class LogLevel - { - trace = 0, - Info = 2, - Warn = 3, - Err = 4, - Fatal = 5 - }; - - class Logger - { - public: - Logger(); - ~Logger(); - - static auto init() -> void; - static auto shutdown() -> void; - - static auto get_logger() -> Ref<Logger>; - - template<typename... Args> - static auto trace(const std::string_view& format, const Args&... args) -> void - { - auto logger = get_logger(); - if (logger) logger->log_message(LogLevel::trace, format, args...); - } - - template<typename... Args> - static auto info(const std::string_view& format, const Args&... args) -> void - { - auto logger = get_logger(); - if (logger) logger->log_message(LogLevel::Info, format, args...); - } - - template<typename... Args> - static auto warn(const std::string_view& format, const Args&... args) -> void - { - auto logger = get_logger(); - if (logger) logger->log_message(LogLevel::Warn, format, args...); - } - - template<typename... Args> - static auto error(const std::string_view& format, const Args&... args) -> void - { - auto logger = get_logger(); - if (logger) logger->log_message(LogLevel::Err, format, args...); - } - - template<typename... Args> - static auto fatal(const std::string_view& format, const Args&... args) -> void - { - auto logger = get_logger(); - if (logger) logger->log_message(LogLevel::Fatal, format, args...); - } - - template<typename... Args> - auto log_message(LogLevel level, const std::string_view& format, const Args&... args) -> void - { - if (level < m_log_level) - return; - - std::lock_guard<std::mutex> lock(m_mutex); - std::string message = format_string(format, args...); - std::string full_message = get_time_stamp() + " [" + get_log_level_string(level) + "] " + message; - - if (m_console_output) - { - set_console_color(level); - std::cout << full_message << std::endl; - reset_console_color(); - } - - if (m_file_output && m_log_file.is_open()) - { - m_log_file << full_message << std::endl; - m_log_file.flush(); - } - } - - template<typename... Args> - auto format_string(const std::string_view& format, const Args&... args) -> std::string - { - std::string result = format.data(); - std::vector<std::string> arg_strings = { to_string(args)... }; - - size_t arg_index = 0; - size_t pos = 0; - - while ((pos = result.find("{}", pos)) != std::string::npos && arg_index < arg_strings.size()) - { - result.replace(pos, 2, arg_strings[arg_index]); - pos += arg_strings[arg_index].length(); - arg_index++; - } - - return result; - } - - template<typename T> - auto to_string(const T& value) -> std::string - { - std::stringstream ss; - ss << value; - return ss.str(); - } - - auto set_log_level(LogLevel level) -> void { m_log_level = level; } - auto enable_console_output(bool enable) -> void { m_console_output = enable; } - auto enable_file_output(bool enable) -> void { m_file_output = enable; } - auto set_log_file(const std::string& filename) -> void; - - auto get_time_stamp() -> std::string; - auto get_log_level_string(LogLevel level) -> std::string; - auto set_console_color(LogLevel level) -> void; - auto reset_console_color() -> void; - - private: - LogLevel m_log_level; - bool m_console_output; - bool m_file_output; - std::ofstream m_log_file; - std::mutex m_mutex; - - static Ref<Logger> s_logger; - }; -} - -#if defined(DONUT_DEBUG) - #define DONUT_TRACE(format, ...) ::Donut::Logger::trace(format, ##__VA_ARGS__) - #define DONUT_INFO(format, ...) ::Donut::Logger::info(format, ##__VA_ARGS__) - #define DONUT_WARN(format, ...) ::Donut::Logger::warn(format, ##__VA_ARGS__) - #define DONUT_ERROR(format, ...) ::Donut::Logger::error(format, ##__VA_ARGS__) - #define DONUT_FATAL(format, ...) ::Donut::Logger::fatal(format, ##__VA_ARGS__) -#else - #define DONUT_TRACE(format, ...) {} - #define DONUT_INFO(format, ...) {} - #define DONUT_WARN(format, ...) {} - #define DONUT_ERROR(format, ...) {} - #define DONUT_FATAL(format, ...) {} -#endif diff --git a/src/Core/Memory.h b/src/Core/Memory.h deleted file mode 100644 index 3240c71..0000000 --- a/src/Core/Memory.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <memory> - -namespace Donut -{ - template<typename T> - using Ref = std::shared_ptr<T>; - - template<typename T> - using Scope = std::unique_ptr<T>; - - template<typename T, typename ... Args> - constexpr auto create_scope(Args&& ... args) -> Scope<T> - { - return std::make_unique<T>(std::forward<Args>(args)...); - } - - template<typename T, typename ... Args> - constexpr auto create_ref(Args&& ... args) -> Ref<T> - { - return std::make_shared<T>(std::forward<Args>(args)...); - } -}; 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/Window.cpp b/src/Core/Window.cpp deleted file mode 100644 index 047ef0d..0000000 --- a/src/Core/Window.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include <glad/glad.h> -#include "window.h" -#include "theme_manager.h" -#include "rendering/renderer.h" // RendererAPI::get_api() - -#include <cstdint> - -#include <imgui.h> -#include <imgui_impl_glfw.h> -#include <imgui_impl_opengl3.h> - -namespace Donut -{ - static bool s_glfw_initialized = false; - static uint32_t s_glfw_window_count = 0; - - Window::Window(const std::string& title, int width, int height) - : m_title(title), m_width(width), - m_height(height), m_is_closed(false) - { - init(); - } - - Window::~Window() - { - shutdown(); - } - - auto Window::init() -> void - { - DONUT_INFO("Initializing window: ", m_title, " (", m_width, "x", m_height, ")"); - - if (!s_glfw_initialized) - { - int success = glfwInit(); - if (!success) - { - DONUT_ERROR("Could not initialize GLFW!"); - return; - } - - s_glfw_initialized = true; - DONUT_INFO("GLFW initialized successfully"); - } - - if (RendererAPI::get_api() == RendererAPI::API::Vulkan) - { - // Vulkan manages presentation itself; GLFW must not create a GL context. - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - } - else - { -#ifdef __APPLE__ - // macOS only exposes OpenGL up to 4.1 Core Profile, and requires a - // forward-compatible core-profile context for any modern (>= 3.3) - // shader to compile. Without these hints GLFW hands back a legacy - // 2.1 context and every GLSL shader in the project fails to build. - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); -#endif - } - - m_window = glfwCreateWindow(m_width, m_height, m_title.c_str(), nullptr, nullptr); - if (!m_window) - { - DONUT_ERROR("Could not create GLFW window!"); - glfwTerminate(); - return; - } - - DONUT_INFO("GLFW window created successfully"); - - if (RendererAPI::get_api() != RendererAPI::API::Vulkan) - glfwMakeContextCurrent(m_window); - glfwSetWindowUserPointer(m_window, this); - - glfwSetErrorCallback(glfw_error_callback); - glfwSetWindowCloseCallback(m_window, glfw_window_close_callback); - glfwSetWindowSizeCallback(m_window, glfw_window_size_callback); - glfwSetWindowFocusCallback(m_window, glfw_window_focus_callback); - glfwSetWindowPosCallback(m_window, glfw_window_pos_callback); - glfwSetKeyCallback(m_window, glfw_key_callback); - glfwSetCharCallback(m_window, glfw_char_callback); - glfwSetMouseButtonCallback(m_window, glfw_mouse_button_callback); - glfwSetScrollCallback(m_window, glfw_mouse_scroll_callback); - glfwSetCursorPosCallback(m_window, glfw_cursor_pos_callback); - - s_glfw_window_count++; - } - - auto Window::shutdown() -> void - { - DONUT_INFO("Shutting down window: ", m_title); - - shutdown_im_gui(); - - glfwDestroyWindow(m_window); - s_glfw_window_count--; - - if (s_glfw_window_count == 0) - { - glfwTerminate(); - s_glfw_initialized = false; - DONUT_INFO("GLFW terminated (no more windows)"); - } - } - - auto Window::on_update() const -> void - { - glfwPollEvents(); - if (RendererAPI::get_api() != RendererAPI::API::Vulkan) - glfwSwapBuffers(m_window); // Vulkan presents via the swapchain instead - } - - auto Window::should_close() const -> bool - { - return glfwWindowShouldClose(m_window) || m_is_closed; - } - - auto Window::set_cursor_locked(bool locked) -> void - { - m_cursor_locked = locked; - glfwSetInputMode(m_window, GLFW_CURSOR, locked ? - GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); - } - - auto Window::set_cursor_visible(bool visible) -> void - { - m_cursor_visible = visible; - glfwSetInputMode(m_window, GLFW_CURSOR, visible ? - GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN); - } - - auto Window::init_im_gui() -> void - { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; -#ifndef __APPLE__ - // Multi-viewport (dragging ImGui panels out as separate OS windows) - // relies on a populated platform-monitor list and is unreliable on - // macOS, where it intermittently asserts (Monitors.Size > 0) and - // aborts. Docking stays enabled; panels just remain inside the window. - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; -#endif - - setup_im_gui_fonts(); - ThemeManager::set_theme(Theme::Dark); - - ImGuiStyle& style = ImGui::GetStyle(); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - style.WindowRounding = 0.0f; - style.Colors[ImGuiCol_WindowBg].w = 1.0f; - } - - ImGui_ImplGlfw_InitForOpenGL(m_window, true); -#ifdef __APPLE__ - // macOS uses a core-profile context, which rejects the legacy - // "#version 130" GLSL the ImGui backend defaults to. 150 is the - // minimum core-profile GLSL that macOS's OpenGL 4.1 accepts. - ImGui_ImplOpenGL3_Init("#version 150"); -#else - ImGui_ImplOpenGL3_Init("#version 130"); -#endif - - DONUT_INFO("ImGUI initialized successfully"); - } - - auto Window::setup_im_gui_fonts() -> void - { - ImGuiIO& io = ImGui::GetIO(); - io.Fonts->Clear(); - - m_main_font = io.Fonts->AddFontFromFileTTF("assets/fonts/inter/static/Inter_18pt-Regular.ttf", 16.0f); - if (!m_main_font) - { - DONUT_WARN("Failed to load Inter font, falling back to default"); - m_main_font = io.Fonts->AddFontDefault(); - } - else - DONUT_INFO("Successfully loaded Inter font"); - - m_large_font = io.Fonts->AddFontFromFileTTF("assets/fonts/inter/static/Inter_18pt-Bold.ttf", 20.0f); - if (!m_large_font) - m_large_font = m_main_font; - - m_small_font = io.Fonts->AddFontFromFileTTF("assets/fonts/inter/static/Inter_18pt-Light.ttf", 12.0f); - if (!m_small_font) - m_small_font = m_main_font; - - io.FontDefault = m_main_font; - DONUT_INFO("ImGUI fonts loaded successfully"); - } - - auto Window::shutdown_im_gui() -> void - { - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - DONUT_INFO("ImGUI shutdown"); - } - - auto Window::begin_im_gui_frame() -> void - { - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - } - - auto Window::end_im_gui_frame() -> void - { - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - ImGuiIO& io = ImGui::GetIO(); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - GLFWwindow* backup_current_context = glfwGetCurrentContext(); - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - glfwMakeContextCurrent(backup_current_context); - } - } - - auto Window::glfw_error_callback(int error, const char* description) -> void - { - DONUT_ERROR("GLFW Error ({}): {}", error, description ? description : ""); - } - - auto Window::glfw_window_close_callback(GLFWwindow* window) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - WindowCloseEvent event; - win->m_event_handler.on_event(event); - } - - auto Window::glfw_window_size_callback(GLFWwindow* window, int width, int height) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - win->m_width = width; - win->m_height = height; - - WindowResizeEvent event(width, height); - win->m_event_handler.on_event(event); - } - - auto Window::glfw_window_focus_callback(GLFWwindow* window, int focused) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - - if (focused) - { - WindowFocusEvent event; - win->m_event_handler.on_event(event); - } - else - { - WindowLostFocusEvent event; - win->m_event_handler.on_event(event); - } - } - - auto Window::glfw_window_pos_callback(GLFWwindow* window, int xpos, int ypos) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - WindowMovedEvent event(xpos, ypos); - win->m_event_handler.on_event(event); - } - - auto Window::glfw_key_callback(GLFWwindow* window, int key, int scancode, - int action, int mods) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - - switch (action) - { - case GLFW_PRESS: - { - KeyPressedEvent event(key, false); - win->m_event_handler.on_event(event); - } break; - case GLFW_RELEASE: - { - KeyReleasedEvent event(key); - win->m_event_handler.on_event(event); - } break; - case GLFW_REPEAT: - { - KeyPressedEvent event(key, true); - win->m_event_handler.on_event(event); - } break; - } - } - - auto Window::glfw_char_callback(GLFWwindow* window, unsigned int keycode) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - KeyTypedEvent event(keycode); - win->m_event_handler.on_event(event); - } - - auto Window::glfw_mouse_button_callback(GLFWwindow* window, int button, - int action, int mods) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - - switch (action) - { - case GLFW_PRESS: - { - MouseButtonPressedEvent event(button); - win->m_event_handler.on_event(event); - } break; - case GLFW_RELEASE: - { - MouseButtonReleasedEvent event(button); - win->m_event_handler.on_event(event); - } break; - } - } - - auto Window::glfw_mouse_scroll_callback(GLFWwindow* window, double x_offset, double y_offset) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - MouseScrolledEvent event((float)x_offset, (float)y_offset); - win->m_event_handler.on_event(event); - } - - auto Window::glfw_cursor_pos_callback(GLFWwindow* window, double x_pos, double y_pos) -> void - { - Window* win = static_cast<Window*>(glfwGetWindowUserPointer(window)); - MouseMovedEvent event((float)x_pos, (float)y_pos); - win->m_event_handler.on_event(event); - } -} diff --git a/src/Core/Window.h b/src/Core/Window.h deleted file mode 100644 index 9b7d7b9..0000000 --- a/src/Core/Window.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include "event.h" -#include "log.h" - -#include <GLFW/glfw3.h> -#include <imgui.h> - -#include <string> - -namespace Donut -{ - class Window - { - public: - using EventCallbackFn = std::function<void(Event&)>; - - Window(const std::string& title, int width, int height); - ~Window(); - - auto should_close() const -> bool; - auto on_update() const -> void; - - auto set_event_callback(const EventCallbackFn& callback) -> void - { - m_event_handler.set_event_callback(callback); - } - - auto get_event_handler() -> EventHandler& { return m_event_handler; } - - auto get_width() const -> unsigned int { return m_width; } - auto get_height() const -> unsigned int { return m_height; } - - auto get_native_window() const -> void* { return m_window; } - - auto set_cursor_locked(bool locked) -> void; - auto set_cursor_visible(bool visible) -> void; - auto is_cursor_locked() const -> bool { return m_cursor_locked; } - auto is_cursor_visible() const -> bool { return m_cursor_visible; } - - auto init_im_gui() -> void; - auto begin_im_gui_frame() -> void; - auto end_im_gui_frame() -> void; - - private: - auto init() -> void; - auto shutdown() -> void; - - auto setup_im_gui_fonts() -> void; - auto shutdown_im_gui() -> void; - - static auto glfw_error_callback(int error, const char* description) -> void; - static auto glfw_window_close_callback(GLFWwindow* window) -> void; - static auto glfw_window_size_callback(GLFWwindow* window, int width, int height) -> void; - static auto glfw_window_focus_callback(GLFWwindow* window, int focused) -> void; - static auto glfw_window_pos_callback(GLFWwindow* window, int xpos, int ypos) -> void; - static auto glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) -> void; - static auto glfw_char_callback(GLFWwindow* window, unsigned int keycode) -> void; - static auto glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) -> void; - static auto glfw_mouse_scroll_callback(GLFWwindow* window, double x_offset, double y_offset) -> void; - static auto glfw_cursor_pos_callback(GLFWwindow* window, double x_pos, double y_pos) -> void; - - private: - GLFWwindow* m_window; - EventHandler m_event_handler; - - std::string m_title; - unsigned int m_width; - unsigned int m_height; - bool m_is_closed; - bool m_cursor_locked = false; - bool m_cursor_visible = true; - - ImFont* m_main_font = nullptr; - ImFont* m_small_font = nullptr; - ImFont* m_large_font = nullptr; - }; -} diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp deleted file mode 100644 index 059fdda..0000000 --- a/src/Engine/Engine.cpp +++ /dev/null @@ -1,614 +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) } - }; - - // The geodesic ray tracer used to be a compute shader; it is now a - // fullscreen vertex+fragment pass (see dispatch_compute) so it runs on - // macOS OpenGL 4.1, which has no compute shaders. - m_compute_program = Ref<Shader>(Shader::create("assets/shaders/Geodesic.glsl")); - m_shader_program = Ref<Shader>(Shader::create("assets/shaders/TexturedQuad.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) * 5, 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 = QuadVAO(); - m_quad_vao = result.first; - m_texture = result.second; - - // GLSL 4.10 forbids explicit binding qualifiers on uniform blocks, so - // associate the geodesic shader's blocks with their UBO binding points - // from the host side instead. - 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__ - // macOS aborts any GPU submission that runs longer than a couple of - // seconds ("GPU Hang"). The geodesic ray-marcher can far exceed that in - // a single fullscreen draw, so render it in scissored tiles and flush - // after each, keeping every submission short enough to survive the - // watchdog. Compute-capable platforms draw it in one pass. - // Largest tile that keeps a tile's worst-case work (tile^2 * step_cap) - // inside the safe watchdog zone measured on this GPU (~25M pixel-steps - // per submission); bigger tiles mean fewer glFinish stalls. - 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; - - // Render the geodesic pass into m_texture through an FBO. This replaces - // the old compute dispatch + image_store path, which relied on OpenGL - // 4.3 compute and 4.2 image load/store that macOS does not provide. - 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 fwd = glm::normalize(cam.get_orbital_target() - cam.get_orbital_position()); - glm::vec3 up = glm::vec3(0, 1, 0); - glm::vec3 right = glm::normalize(glm::cross(fwd, up)); - up = glm::cross(right, fwd); - - data.pos = cam.get_orbital_position(); - data.right = right; - data.up = up; - data.forward = fwd; - data.tan_half_fov = static_cast<float>(tan(glm::radians(60.0f * 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 - { - float r1 = static_cast<float>(m_sag_a.m_rs * 2.2); - float r2 = static_cast<float>(m_sag_a.m_rs * 5.2); - float num = 2.0f; - float thickness = static_cast<float>(m_sag_a.m_rs * m_disk_thickness); - float disk_data[5] = { r1, r2, num, thickness, m_disk_density }; - - 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_max_steps_moving; - data.max_steps_static = m_max_steps_static; - data.early_exit_distance = m_early_exit_distance; - data.time = static_cast<float>(glfwGetTime()) * m_rotation_speed; - -#ifdef __APPLE__ - // macOS has no compute shaders, so the geodesic pass runs as a tiled - // fragment shader under the OS GPU watchdog. The stock step counts - // (up to 30000) make a single tile exceed the watchdog and hang the - // GPU, so cap them here. Windows/Linux keep the full step count. - // While the camera moves, render cheaply so interaction stays smooth; - // when it settles, spend more steps for a cleaner image. Both stay well - // under the per-tile GPU-watchdog budget (see draw_geodesic_pass). - data.max_steps_moving = std::min(data.max_steps_moving, 4000); - 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::QuadVAO() -> std::pair<Ref<VertexArray>, Ref<Texture2D>> - { - float quad_vertices[] = - { - // Positions // TexCoords - -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); // Position (x, y) - layout.push<float>(2); // TexCoord (u, v) - 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; - } - - // Render the geodesic pass into high_res_texture through the geodesic FBO. - 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); - - // Display the rendered frame into the high-res framebuffer for read-back. - 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]; // R - flipped_pixels[dst_index + 1] = pixels[src_index + 1]; // G - flipped_pixels[dst_index + 2] = pixels[src_index + 2]; // B - flipped_pixels[dst_index + 3] = pixels[src_index + 3]; // A - } - } - - 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 c7d02b5..0000000 --- a/src/Engine/Engine.h +++ /dev/null @@ -1,184 +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/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__ - // Without compute shaders the geodesic pass runs as a tiled - // fragment shader (see draw_geodesic_pass), so very high working - // resolutions make each frame take many seconds. Cap it on macOS. - 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; } - private: - auto create_compute_program(const char* path) -> Ref<Shader>; - std::pair<Ref<VertexArray>, Ref<Texture2D>> QuadVAO(); - - // Draws the bound geodesic shader over a cw x ch target. On macOS this - // is split into scissored tiles (with a flush each) so no single GPU - // submission trips the OS watchdog; elsewhere it is one fast draw. - 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; - - // FBO used to render the geodesic pass into m_texture. The geodesic - // shader is a fragment shader (macOS has no compute), so it draws a - // fullscreen quad into this framebuffer instead of dispatching compute. - 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; - - 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/Rendering/Framebuffer.cpp b/src/Rendering/Framebuffer.cpp deleted file mode 100644 index 089c31e..0000000 --- a/src/Rendering/Framebuffer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "framebuffer.h" -#include "renderer.h" - -#include "platform/opengl/opengl_framebuffer.h" - -namespace Donut -{ - auto Framebuffer::create(const FramebufferSpecification& spec) -> Ref<Framebuffer> - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: return create_ref<OpenGLFramebuffer>(spec); - } - - return nullptr; - } -}; diff --git a/src/Rendering/Framebuffer.h b/src/Rendering/Framebuffer.h deleted file mode 100644 index a01a81b..0000000 --- a/src/Rendering/Framebuffer.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include "texture.h" - -namespace Donut -{ - enum class FramebufferTextureFormat - { - None = 0, - - RGBA8, - RED_INTEGER, - - DEPTH24STENCIL8, - - Depth = DEPTH24STENCIL8 - }; - - struct FramebufferTextureSpecification - { - FramebufferTextureSpecification() = default; - FramebufferTextureSpecification(FramebufferTextureFormat format) - : texture_format(format) {} - - FramebufferTextureFormat texture_format = FramebufferTextureFormat::None; - }; - - struct FramebufferAttachmentSpecification - { - FramebufferAttachmentSpecification() = default; - FramebufferAttachmentSpecification(std::initializer_list<FramebufferTextureSpecification> attachments) - : attachments(attachments) {} - - std::vector<FramebufferTextureSpecification> attachments; - }; - - struct FramebufferSpecification - { - uint32_t Width = 0, Height = 0; - FramebufferAttachmentSpecification attachments; - uint32_t Samples = 1; - - bool SwapChainTarget = false; - }; - - class Framebuffer - { - public: - virtual ~Framebuffer() = default; - - virtual auto bind() -> void = 0; - virtual auto unbind() -> void = 0; - - virtual auto resize(uint32_t width, uint32_t height) -> void = 0; - virtual auto read_pixel(uint32_t attachment_index, int x, int y) -> int = 0; - - virtual auto clear_attachment(uint32_t attachment_index, int value) -> void = 0; - virtual auto get_color_attachment_renderer_id(uint32_t index = 0) const -> uint32_t = 0; - - virtual auto get_specification() const -> const FramebufferSpecification& = 0; - - static auto create(const FramebufferSpecification& spec) -> Ref<Framebuffer>; - }; -}; diff --git a/src/Rendering/Renderer.cpp b/src/Rendering/Renderer.cpp deleted file mode 100644 index 28b7962..0000000 --- a/src/Rendering/Renderer.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "renderer.h" - -#include "platform/opengl/opengl_renderer_api.h" -#include "platform/vulkan/vulkan_renderer_api.h" - -#include <glm/gtc/matrix_transform.hpp> - -namespace Donut -{ - auto RendererAPI::create() -> Scope<RendererAPI> - { - switch (s_api) - { - case API::OpenGL: - return create_scope<OpenGLRendererAPI>(); - case API::Vulkan: - return create_scope<VulkanRendererAPI>(); - default: - return nullptr; - } - } - - RendererAPI::API RendererAPI::s_api = RendererAPI::API::OpenGL; - - auto Renderer::init() -> void - { - RenderCommand::init(); - RenderCommand::enable_depth_test(); - } - - auto Renderer::shutdown() -> void - { - } - - auto Renderer::on_window_resize(uint32_t width, uint32_t height) -> void - { - RenderCommand::set_viewport(0, 0, width, height); - } - - auto Renderer::submit(const Ref<Shader>& shader, - const Ref<VertexArray>& vertex_array, - const glm::mat4& transform, - const glm::mat4& view_projection) -> void - { - shader->bind(); - shader->set_mat4("u_ViewProjection", view_projection); - shader->set_mat4("u_Transform", transform); - - vertex_array->bind(); - RenderCommand::draw_indexed(vertex_array); - } - - Scope<RendererAPI> RenderCommand::s_renderer_api = RendererAPI::create(); - - auto Renderer::set_clear_color(const glm::vec4& color) -> void - { - RenderCommand::set_clear_color(color); - } - - auto Renderer::clear() -> void - { - RenderCommand::clear(); - } -}; diff --git a/src/Rendering/Renderer.h b/src/Rendering/Renderer.h deleted file mode 100644 index 189723d..0000000 --- a/src/Rendering/Renderer.h +++ /dev/null @@ -1,158 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include "vertex_array.h" -#include "shader.h" -#include "framebuffer.h" - -#include <glm/glm.hpp> - -namespace Donut -{ - class RendererAPI - { - public: - enum class API - { - None = 0, - OpenGL = 1, - Vulkan = 2, - }; - - public: - virtual ~RendererAPI() = default; - - virtual auto init() -> void = 0; - virtual auto set_viewport(uint32_t x, uint32_t y, - uint32_t width, uint32_t height) -> void = 0; - virtual auto set_clear_color(const glm::vec4& color) -> void = 0; - virtual auto clear() -> void = 0; - virtual auto enable_depth_test() -> void = 0; - virtual auto disable_depth_test() -> void = 0; - virtual auto set_face_culling(bool enabled) -> void = 0; - virtual auto enable_blending() -> void = 0; - virtual auto disable_blending() -> void = 0; - - virtual auto draw_indexed(const Ref<VertexArray>& vertex_array, - uint32_t index_count = 0) -> void = 0; - - virtual auto draw_arrays(uint32_t vertex_count, uint32_t first = 0) -> void = 0; - virtual auto draw_lines(const Ref<VertexArray>& vertex_array, - uint32_t index_count = 0) -> void = 0; - virtual auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void = 0; - virtual auto bind_image_texture(uint32_t texture_id, - uint32_t slot = 0, - bool read_only = false) -> void = 0; - virtual auto read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t format, uint32_t type, void* pixels) -> void = 0; - - inline static auto get_api() -> API { return s_api; } - inline static auto set_api(API api) -> void { s_api = api; } - static auto create() -> Scope<RendererAPI>; - - private: - static API s_api; - }; - - class RenderCommand - { - public: - inline static auto init() -> void - { - s_renderer_api->init(); - } - - inline static auto set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) -> void - { - s_renderer_api->set_viewport(x, y, width, height); - } - - inline static auto set_clear_color(const glm::vec4& color) -> void - { - s_renderer_api->set_clear_color(color); - } - - inline static auto clear() -> void - { - s_renderer_api->clear(); - } - - inline static auto enable_depth_test() -> void - { - s_renderer_api->enable_depth_test(); - } - - inline static auto disable_depth_test() -> void - { - s_renderer_api->disable_depth_test(); - } - - inline static auto set_face_culling(bool enabled) -> void - { - s_renderer_api->set_face_culling(enabled); - } - - inline static auto enable_blending() -> void - { - s_renderer_api->enable_blending(); - } - - inline static auto disable_blending() -> void - { - s_renderer_api->disable_blending(); - } - - inline static auto draw_indexed(const Ref<VertexArray>& vertex_array, uint32_t index_count = 0) -> void - { - s_renderer_api->draw_indexed(vertex_array, index_count); - } - - inline static auto draw_arrays(uint32_t vertex_count, uint32_t first = 0) -> void - { - s_renderer_api->draw_arrays(vertex_count, first); - } - - inline static auto draw_lines(const Ref<VertexArray>& vertex_array, uint32_t index_count = 0) -> void - { - s_renderer_api->draw_lines(vertex_array, index_count); - } - - inline static auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void - { - s_renderer_api->bind_texture(texture_id, slot); - } - - inline static auto bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) -> void - { - s_renderer_api->bind_image_texture(texture_id, slot, read_only); - } - - inline static auto read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t format, uint32_t type, void* pixels) -> void - { - s_renderer_api->read_pixels(x, y, width, height, format, type, pixels); - } - - private: - static Scope<RendererAPI> s_renderer_api; - }; - - class Renderer - { - public: - static auto init() -> void; - static auto shutdown() -> void; - - static auto on_window_resize(uint32_t width, uint32_t height) -> void; - - static auto submit(const Ref<Shader>& shader, - const Ref<VertexArray>& vertex_array, - const glm::mat4& transform, - const glm::mat4& view_projection) -> void; - - static auto set_clear_color(const glm::vec4& color) -> void; - static auto clear() -> void; - - inline static auto get_api() -> RendererAPI::API { return RendererAPI::get_api(); } - }; -}; diff --git a/src/Rendering/Shader.cpp b/src/Rendering/Shader.cpp deleted file mode 100644 index 167b855..0000000 --- a/src/Rendering/Shader.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "shader.h" -#include "renderer.h" - -#include "platform/opengl/opengl_shader.h" -#include "platform/vulkan/vulkan_shader.h" - -namespace Donut -{ - auto Shader::create(const std::string& filepath) -> Shader* - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return new OpenGLShader(filepath); - case RendererAPI::API::Vulkan: - return new VulkanShader(filepath); - default: - return nullptr; - } - } - - auto Shader::create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) -> Shader* - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return new OpenGLShader(name, vertex_src, fragment_src); - case RendererAPI::API::Vulkan: - return new VulkanShader(name, vertex_src, fragment_src); - default: - return nullptr; - } - } - - auto Shader::create_compute(const std::string& name, const std::string& compute_src) -> Shader* - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return new OpenGLShader(name, compute_src); - case RendererAPI::API::Vulkan: - return new VulkanShader(name, compute_src); - default: - return nullptr; - } - } - - auto ShaderLibrary::add(const Ref<Shader>& shader) -> void - { - auto& name = shader->get_name(); - add(name, shader); - } - - auto ShaderLibrary::add(const std::string& name, const Ref<Shader>& shader) -> void - { - m_shaders[name] = shader; - } - - auto ShaderLibrary::load(const std::string& filepath) -> Ref<Shader> - { - auto shader = Ref<Shader>(Shader::create(filepath)); - add(shader); - return shader; - } - - auto ShaderLibrary::load(const std::string& name, const std::string& filepath) -> Ref<Shader> - { - auto shader = Ref<Shader>(Shader::create(filepath)); - add(name, shader); - return shader; - } - - auto ShaderLibrary::Get(const std::string& name) -> Ref<Shader> - { - if (exists(name)) - return m_shaders[name]; - return nullptr; - } - - auto ShaderLibrary::exists(const std::string& name) const -> bool - { - return m_shaders.find(name) != m_shaders.end(); - } -}; diff --git a/src/Rendering/Shader.h b/src/Rendering/Shader.h deleted file mode 100644 index bc3fd9a..0000000 --- a/src/Rendering/Shader.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "core/memory.h" - -#include <string> -#include <unordered_map> -#include <glm/glm.hpp> - -#define SHADER_STORAGE_BARRIER_BIT 0x00002000 -#define UNIFORM_BARRIER_BIT 0x00000004 -#define TEXTURE_FETCH_BARRIER_BIT 0x00000008 -#define IMAGE_ACCESS_BARRIER_BIT 0x00000020 - -namespace Donut -{ - class Shader - { - public: - virtual ~Shader() = default; - - virtual auto bind() const -> void = 0; - virtual auto unbind() const -> void = 0; - - virtual auto set_int( const std::string& name, int value) -> void = 0; - virtual auto set_int_array(const std::string& name, int* values, uint32_t count) -> void = 0; - virtual auto set_float( const std::string& name, float value) -> void = 0; - virtual auto set_float2( const std::string& name, const glm::vec2& value) -> void = 0; - virtual auto set_float3( const std::string& name, const glm::vec3& value) -> void = 0; - virtual auto set_float4( const std::string& name, const glm::vec4& value) -> void = 0; - virtual auto set_mat4( const std::string& name, const glm::mat4& value) -> void = 0; - - virtual auto dispatch(uint32_t x, uint32_t y = 1, uint32_t z = 1) -> void = 0; - virtual auto dispatch_indirect(uint32_t offset = 0) -> void = 0; - virtual auto memory_barrier(uint32_t barriers) -> void = 0; - - virtual auto get_name() const -> const std::string& = 0; - virtual auto get_renderer_id() const -> uint32_t = 0; - - static auto create(const std::string& filepath) -> Shader*; - static auto create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) -> Shader*; - static auto create_compute(const std::string& name, const std::string& compute_src) -> Shader*; - }; - - class ShaderLibrary - { - public: - auto add(const Ref<Shader>& shader) -> void; - auto add(const std::string& name, const Ref<Shader>& shader) -> void; - auto load(const std::string& filepath) -> Ref<Shader>; - auto load(const std::string& name, const std::string& filepath) -> Ref<Shader>; - - Ref<Shader> Get(const std::string& name); - - auto exists(const std::string& name) const -> bool; - private: - std::unordered_map<std::string, Ref<Shader>> m_shaders; - }; -}; diff --git a/src/Rendering/Texture.cpp b/src/Rendering/Texture.cpp deleted file mode 100644 index 2470e46..0000000 --- a/src/Rendering/Texture.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "texture.h" -#include "renderer.h" - -#include "platform/opengl/opengl_texture.h" -#include "platform/vulkan/vulkan_texture.h" - -namespace Donut -{ - auto Texture2D::create(uint32_t width, uint32_t height) -> Ref<Texture2D> - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return create_ref<OpenGLTexture2D>(width, height); - case RendererAPI::API::Vulkan: - return create_ref<VulkanTexture2D>(width, height); - case RendererAPI::API::None: - return nullptr; - default: - return nullptr; - } - } - - auto Texture2D::create(const std::string& path) -> Ref<Texture2D> - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return create_ref<OpenGLTexture2D>(path); - case RendererAPI::API::Vulkan: - return create_ref<VulkanTexture2D>(path); - case RendererAPI::API::None: - return nullptr; - default: - return nullptr; - } - } - - auto CubemapTexture::create(uint32_t width, uint32_t height) -> Ref<CubemapTexture> - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return create_ref<OpenGLCubemapTexture>(width, height); - case RendererAPI::API::Vulkan: - return create_ref<VulkanCubemapTexture>(width, height); - case RendererAPI::API::None: - return nullptr; - default: - return nullptr; - } - } - - auto CubemapTexture::create_from_hdri(const std::string& path) -> Ref<CubemapTexture> - { - switch (Renderer::get_api()) - { - case RendererAPI::API::OpenGL: - return create_ref<OpenGLCubemapTexture>(path); - case RendererAPI::API::Vulkan: - return create_ref<VulkanCubemapTexture>(path); - case RendererAPI::API::None: - return nullptr; - default: - return nullptr; - } - } -};
\ No newline at end of file diff --git a/src/Rendering/Texture.h b/src/Rendering/Texture.h deleted file mode 100644 index e9b3e0a..0000000 --- a/src/Rendering/Texture.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "core/memory.h" - -#include <string> -#include <glm/glm.hpp> - -namespace Donut -{ - class Texture - { - public: - virtual ~Texture() = default; - - virtual auto get_width() const -> uint32_t = 0; - virtual auto get_height() const -> uint32_t = 0; - virtual auto get_renderer_id() const -> uint32_t = 0; - - virtual auto set_data(void* data, uint32_t size) -> void = 0; - virtual auto bind(uint32_t slot = 0) const -> void = 0; - virtual void bind_as_image(uint32_t slot = 0, - bool read_only = false) const = 0; - - virtual bool operator==(const Texture& other) const = 0; - }; - - class Texture2D - : public Texture - { - public: - static auto create(uint32_t width, uint32_t height) -> Ref<Texture2D>; - static auto create(const std::string& path) -> Ref<Texture2D>; - }; - - class CubemapTexture - : public Texture - { - public: - static auto create(uint32_t width, uint32_t height) -> Ref<CubemapTexture>; - static auto create_from_hdri(const std::string& path) -> Ref<CubemapTexture>; - }; -};
\ No newline at end of file |
