diff --git a/CMakeLists.txt b/CMakeLists.txt index faa95f62..ad7ae4be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,17 +132,10 @@ target_sources(${PROJECT_NAME} PUBLIC FILE_SET CXX_MODULES TYPE CXX_MODULES FILES - - # core - # atlas/atlas.cppm - atlas/core/api.cppm atlas/core/common.cppm - atlas/core/utilities/types.cppm - atlas/core/utilities/utilities.cppm atlas/core/core.cppm atlas/core/logger.cppm atlas/core/application.cppm - atlas/core/window.cppm # math atlas/core/math/types.cppm @@ -156,6 +149,7 @@ target_sources(${PROJECT_NAME} PUBLIC atlas/core/scene/level_streamer.cppm atlas/core/scene/uuid.cppm + atlas/core/utilities/utilities.cppm atlas/core/utilities/state.cppm atlas/core/utilities/poll_state.cppm @@ -169,8 +163,10 @@ target_sources(${PROJECT_NAME} PUBLIC atlas/core/event/types.cppm # editor + atlas/core/editor/editor.cppm atlas/core/editor/dockspace.cppm atlas/core/editor/menu_item.cppm + atlas/core/ui/ui.cppm atlas/core/ui/widgets.cppm atlas/core/filesystem/file_dialog.cppm @@ -179,23 +175,11 @@ target_sources(${PROJECT_NAME} PUBLIC atlas/core/serialize/serializer.cppm # renderer - atlas/renderer/context_loader.cppm atlas/renderer/renderer.cppm - atlas/drivers/drivers.cppm - atlas/drivers/graphics_context.cppm - atlas/drivers/renderer_system.cppm - - atlas/drivers/vulkan/hash.cppm - atlas/drivers/vulkan/mesh.cppm - atlas/drivers/vulkan/shader_resource_group.cppm - atlas/drivers/vulkan/render_system.cppm - atlas/drivers/vulkan/uniforms.cppm - # imgui/UI - atlas/drivers/vulkan/imgui_context.cppm atlas/core/ui/imgui_stdlib.cppm # physics @@ -204,19 +188,29 @@ target_sources(${PROJECT_NAME} PUBLIC atlas/physics/physics_engine.cppm # jolt_cpp + atlas/drivers/jolt_cpp/jolt_cpp.cppm atlas/drivers/jolt_cpp/math.cppm atlas/drivers/jolt_cpp/broad_phase.cppm atlas/drivers/jolt_cpp/contact_listener.cppm atlas/drivers/jolt_cpp/context.cppm - # drivers + # drivers/vulkan + atlas/drivers/vulkan/vulkan.cppm + atlas/drivers/vulkan/graphics_context.cppm + atlas/drivers/vulkan/window.cppm + atlas/drivers/vulkan/render_context.cppm + atlas/drivers/vulkan/imgui_context.cppm atlas/drivers/vulkan/utilities.cppm - atlas/drivers/vulkan/instance_context.cppm - atlas/drivers/vulkan/window_context.cppm - atlas/drivers/vulkan/physical_device.cppm - atlas/drivers/vulkan/device.cppm - atlas/drivers/vulkan/swapchain.cppm atlas/drivers/vulkan/environment_map.cppm + atlas/drivers/vulkan/stb_image.cppm + atlas/drivers/vulkan/gpu_uniforms.cppm + + atlas/drivers/vulkan/hash.cppm + + + # 3D Model Importers + atlas/drivers/importer/importer.cppm + atlas/drivers/importer/obj_loader.cppm ) target_sources(${PROJECT_NAME} PUBLIC diff --git a/LevelScene b/LevelScene index f7355b9b..4b88ca90 100644 --- a/LevelScene +++ b/LevelScene @@ -8,6 +8,7 @@ Entities: Rotation: [0, 0, 0] Quaternion: [0, 0, 0, 1] Mesh Source: + Flip: 0 Model Path: "" Diffuse: "" Specular: "" @@ -24,6 +25,7 @@ Entities: Rotation: [2.29999995, 95.9000015, 91.8000031] Quaternion: [0, 0, 0, 1] Mesh Source: + Flip: 1 Model Path: assets/models/viking_room.obj Diffuse: assets/models/viking_room.png Specular: "" @@ -56,6 +58,7 @@ Entities: Rotation: [2.9000001, 16.5, 0.600000024] Quaternion: [-1.5550123e-08, -1.33205403e-05, -1.63867355e-08, 1] Mesh Source: + Flip: 0 Model Path: assets/models/cube.obj Diffuse: assets/models/container_diffuse.png Specular: assets/models/wallace_gromit_image.jpg diff --git a/atlas/core/api.cppm b/atlas/core/api.cppm deleted file mode 100644 index cc0af195..00000000 --- a/atlas/core/api.cppm +++ /dev/null @@ -1,9 +0,0 @@ -module; - -#include - -export module atlas.graphics_api; - -export namespace atlas { - enum class graphics_api : uint8_t { vulkan, dx11, fx12, undefined }; -}; \ No newline at end of file diff --git a/atlas/core/application.cppm b/atlas/core/application.cppm index a7623e41..1f3cf5dc 100644 --- a/atlas/core/application.cppm +++ b/atlas/core/application.cppm @@ -1,38 +1,37 @@ module; #include -#include -#define GLM_ENABLE_EXPERIMENTAL -#include -#include #include #include #include #include + +#include +#include +#include +#include +#include + +#include +#define GLM_ENABLE_EXPERIMENTAL +#include + #include #include #include +#include export module atlas.application; import atlas.core.utilities; -import atlas.core.utilities.poll_state; -import atlas.window; -import atlas.drivers; -import atlas.renderer.context_loader; import atlas.core.event; -import atlas.drivers.renderer_system; -import atlas.renderer; -import atlas.drivers.vulkan.instance_context; +import vk; +import atlas.drivers.vulkan; + import atlas.core.scene; import atlas.core.scene.world; -import atlas.core.event; -import atlas.core.scene.components; - +import atlas.core.scene; import atlas.core.math; -import atlas.drivers.vulkan.imgui_context; -import vk; -import atlas.drivers.graphics_context; export namespace atlas { @@ -40,123 +39,144 @@ export namespace atlas { * @brief application properties settings for the window */ struct application_settings { - std::string name = "Undefined"; - uint32_t width = 0; - uint32_t height = 0; + window_params extent{}; glm::vec4 background_color = { 1.f, 0.5f, 0.5f, 1.f }; }; - /** - * @brief represents a single application that gets created by the engine - * internally - * - * There is only ever going to be one application tied to the engine's - * runtime. As the application is given responsibilities of preloading, - * pre-initialization any sort of utilities required by the engine, and any - * form of post-cleanup when the user requests the application to close. - * - */ class application { public: - /** - * @brief constructs a new application - * @param p_settings is the specific application settings to configure - * how the application may be setup - */ - application(/*NOLINT*/ ref p_context, + application() = default; + application(/*NOLINT*/ std::shared_ptr p_context, const application_settings& p_params, event::bus& p_bus) - : m_bus(&p_bus) { - console_log_info( - "application(const application_settings&) initialized!!!"); - - window_params params = { - .width = p_params.width, - .height = p_params.height, - .name = p_params.name, - }; - m_window = - initialize_window(p_context, params, graphics_api::vulkan); - m_initial_window_params = m_window->data(); - event::set_window_size(static_cast(*m_window)); - - m_renderer = - initialize_renderer(p_context, - graphics_api::vulkan, - params, - m_window->current_swapchain().image_size(), - "Renderer"); - m_renderer->set_background_color(p_params.background_color); + : m_context(p_context) + , m_bus(&p_bus) { + m_instance = p_context->instance_handle(); + m_physical = p_context->physical_device(); + m_device = p_context->logical_device(); - m_ui_context = vulkan::imgui_context( - p_context->handle(), m_window->current_swapchain(), *m_window); + m_window_params = p_params.extent; - p_context->submit_resource_free( - [this]() { m_ui_context.destroy(); }); + // m_window = std::allocate_shared(, + // m_context->instance_handle(), params); + m_window = std::make_shared(p_context, p_params.extent); - s_instance = this; + m_aspect_ratio = static_cast(m_window_params.width) / + static_cast(m_window_params.height); + event::set_window_size(m_window->glfw_window()); - // Setting internal-level listeners for specific events m_bus->create_listener(); m_bus->create_listener(); m_bus->create_listener(); - m_bus->create_immediate_listener(); - m_bus->create_immediate_listener(); - - m_bus->trigger(this, &application::reload_mesh); - m_bus->trigger( - this, &application::reload_material); - } - - ~application() { m_window->close(); } + // m_bus->create_immediate_listener(); + // m_bus->create_immediate_listener(); + // m_bus->create_immediate_listener(); + + // Requesting depth format + std::array format_support = { + vk::format::d32_sfloat, + vk::format::d32_sfloat_s8_uint, + vk::format::d24_unorm_s8_uint + }; - /** - * @return the delta time as a float for giving you the timestep every - * frame - */ - static float delta_time() { return s_instance->m_delta_time; } + m_color_format = m_window->surface_properties().format.format; + // We provide a selection of format support that we want to check is + // supported on current hardware device. + m_depth_format = m_physical->request_depth_format(format_support); + + // Initializing command buffers + std::span images = m_window->request_images(); + + m_images.resize(images.size()); + m_depth_images.resize(images.size()); + + for (uint32_t i = 0; i < m_images.size(); i++) { + vk::image_params color_img_params = { + .extent = { + .width = m_window->extent().width, + .height = m_window->extent().height, + }, + .format = m_window->surface_properties().format.format, + .memory_mask = m_physical->memory_properties( + vk::memory_property::device_local_bit), + .aspect = vk::image_aspect_flags::color_bit, + .usage = vk::image_usage::color_attachment_bit, + .mip_levels = 1, + .layer_count = 1, + }; + m_images[i] = + vk::sample_image(*m_device, images[i], color_img_params); + + vk::image_params depth_img_params = { + .extent = { + .width = m_window->extent().width, + .height = m_window->extent().height, + }, + .format = m_depth_format, + .memory_mask = m_physical->memory_properties( + vk::memory_property::device_local_bit), + .aspect = vk::image_aspect_flags::depth_bit, + .usage = vk::image_usage::depth_stencil_bit, + .mip_levels = 1, + .layer_count = 1, + }; - /** - * @brief Explicitly is used to execute the application's mainloop - */ - void execute() { - console_log_info("Executing game mainloop!!!"); + m_depth_images[i] = + vk::sample_image(*m_device, depth_img_params); + } - auto start_time = std::chrono::high_resolution_clock::now(); + m_command_buffers.resize(images.size()); - ref current_scene = m_current_world->current(); + for (uint32_t i = 0; i < m_command_buffers.size(); i++) { + vk::command_params command_params = { + .levels = vk::command_levels::primary, + .queue_index = 0, + .flags = vk::command_pool_flags::reset, + }; + m_command_buffers[i] = + vk::command_buffer(*m_device, command_params); + } - invoke_start(current_scene.get()); + m_render_context = + render_context(m_context, m_color_format, m_depth_format); + + m_imgui_context = + std::make_shared(p_context, + m_window->glfw_window(), + m_window->swapchain_handle(), + m_window->request_images().size(), + m_window->present_queue(), + // VK_FORMAT_B8G8R8A8_UNORM, + m_color_format, + m_depth_format, + m_window_params); + std::println("images.size() = {}", images.size()); + + m_window->center_window(); + + // m_bus->trigger(this, + // &application::on_scene_transition); + } - m_renderer->current_scene_context(current_scene); + void execute() { + VkClearValue clear_color = { + { { 0.f, 0.5f, 0.5f, 1.f } }, + }; - // Bug-prone API. - // Due to requiring there to be a valid m_current_scene specified. - // TODO: SHOULD have this API be invoked whenever a - // `current_scene_context` sets a new scene (for invalidation) - m_renderer->preload( - m_window->current_swapchain().swapchain_renderpass()); + VkClearValue depth_value = { + .depthStencil = { .depth = 1.f, .stencil = 0 }, + }; - /* - - flecs::system is how your able to schedule changes for given - portions of data in this case the projection/view matrices are - only being changed when flecs::world::progress(g_delta_time) is - being invoked within the mainloop - current_world_scope.system() + m_current_scene = m_world->current(); - - When users do object->add>(), this automatically gets invoked by the - .system<...> that gets invoked by the mainloop. - */ - current_scene + // Handling camera system execution + m_current_scene ->system, transform, perspective_camera>() - .each([&](flecs::pair p_pair, - transform& p_transform, - perspective_camera& p_camera) { - float aspect_ratio = m_window->aspect_ratio(); + .each([this](flecs::pair p_pair, + transform& p_transform, + perspective_camera& p_camera) { if (!p_camera.is_active) { return; } @@ -165,7 +185,7 @@ export namespace atlas { p_pair->projection = glm::perspective(glm::radians(p_camera.field_of_view), - aspect_ratio, + m_aspect_ratio, p_camera.plane.x, p_camera.plane.y); p_pair->projection[1][1] *= -1; @@ -181,199 +201,289 @@ export namespace atlas { p_pair->view = glm::inverse(p_pair->view); }); - /* - - Currently how this works is we query with anything that has a - flecs::pair - - This tells the ecs flecs what to do query for in regards to - specific objects that are a camera - - in the tag:: namespace, this is to imply components that are - empty and just represent tags, to specify their uses. - */ + auto start_time = std::chrono::high_resolution_clock::now(); + invoke_start(m_world.get()); + invoke_start(m_current_scene.get()); + + // Setting the current scene for the renderer to start rendering the + // objects + m_render_context.current_scene(*m_current_scene); + + // Querying editor cameras specific objects + // Then using this to execute specific main cameras. auto query_camera_objects = - current_scene + m_current_scene ->query_builder, perspective_camera>() .build(); + m_render_context.prebake(); + while (m_window->available()) { auto current_time = std::chrono::high_resolution_clock::now(); m_delta_time = std::chrono::duration( current_time - start_time) .count(); - start_time = current_time; + start_time = current_time; event::flush_events(); // Progresses the flecs::world by one tick (or replaced with // using the delta time) This also invokes the following // system call before the mainloop - current_scene->progress(m_delta_time); + m_current_scene->progress(m_delta_time); - m_current_frame_index = m_window->acquired_next_frame(); + m_next_image_frame_idx = m_window->acquire_next_frame(); - // Current commands that are going to be iterated through - // Use the acquired swapchain image index for the command buffer - // and swapchain framebuffer so we record and present the same - // image. - ::vk::command_buffer currently_active = - m_window->active_command(m_current_frame_index); + vk::command_buffer current = + m_command_buffers[m_next_image_frame_idx]; - invoke_physics_update(current_scene.get()); + invoke_physics_update(m_world.get()); + invoke_physics_update(m_current_scene.get()); - invoke_on_update(current_scene.get(), m_delta_time); + invoke_on_update(m_world.get(), m_delta_time); + invoke_on_update(m_current_scene.get(), m_delta_time); - invoke_defer_update(current_scene.get()); // We want this to be called after late update - // This queries all camera objects within the camera system - // Update -- going to be removing camera system in replacement - // of just simply using flecs::system to keep it simple for the - // time + // This queries all camera objects within the camera sytsem + // TODO: Should consider changing this from + // using tags in flecs for specifying active cameras. query_camera_objects.each( - [&](flecs::entity, + [&](flecs::entity p_entity, flecs::pair p_pair, perspective_camera& p_camera) { if (!p_camera.is_active) { return; } - // m_proj_view = p_pair->projection * p_pair->view; + const transform* t = p_entity.get(); + m_render_context.set_camera_pos( + glm::vec4(t->position, 1.f)); m_projection = p_pair->projection; m_view = p_pair->view; }); - // invalidate imgui context - if (m_initial_window_params.width != m_window->data().width and - m_initial_window_params.height != m_window->data().height) { - m_ui_context.invalidate(m_window->current_swapchain()); - // once we have invalidated the current width/height, we set - // that to its new width/height value post-resizing - // TODO: Make this into a event::window_resize event that - // can be handled! - m_initial_window_params = m_window->data(); - - // Make sure to update the imgui window size - ImGui::SetNextWindowSize(ImVec2( - static_cast(m_initial_window_params.width), - static_cast(m_initial_window_params.height))); - } - - // Prevents things like stalling so the CPU doesnt have to wait - // for the GPU to fully complete before starting on the next - // frame Command buffer uses this to track the frames to process - // its commands. current_frame = (acquired_next_frame + 1) % - // frames_in_flight; auto current_frame = (m_current_frame_index - // + 1) % 2; - - // viewport renderpass to render the 3D screen to the offscreen - // texture - auto viewport_framebuffer = - m_ui_context.active_framebuffer(m_current_frame_index % 2u); - m_renderer->begin_frame( - currently_active, - m_window->current_swapchain().settings(), - m_ui_context.viewport_renderpass(), - viewport_framebuffer, - m_projection, - m_view, - m_current_frame_index); - - m_renderer->end_frame(); - - m_ui_context.begin(currently_active, m_current_frame_index); - - invoke_ui_update(current_scene.get()); - - // final renderpass for rendering the offscreen information to - // the final renderpass - window_params swapchain_extent = - m_window->current_swapchain().settings(); - std::array color = { 0.1f, 0.105f, 0.11f, 1.0f }; - vk::renderpass_begin_params begin_renderpass = { - .current_command = currently_active, - .extent = { swapchain_extent.width, - swapchain_extent.height }, - .current_framebuffer = - m_window->current_swapchain().active_framebuffer( - m_current_frame_index), - .color = color, - .subpass = vk::subpass_contents::inline_bit + current.begin(vk::command_usage::simulatneous_use_bit); + + m_render_context.set_command(current); + + m_imgui_context->image_memory_barrier( + current, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + m_imgui_context->depth_image_memory_barrier( + current, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + // presenting rendering attachments + vk::rendering_attachment ui_color_render_attachment = { + .image_view = m_imgui_context->color_image_view(), + .layout = vk::image_layout::color_optimal, + .resolve_mode = vk::resolved_mode_flags::none, + .resolve_image_view = nullptr, + .resolve_image_layout = vk::image_layout::undefined, + .load = vk::attachment_load::clear, + .store = vk::attachment_store::store, + .clear_values = clear_color + }; + + vk::rendering_attachment ui_depth_stencil_attachment = { + .image_view = m_imgui_context->depth_image_view(), + .layout = vk::image_layout::depth_stencil_optimal, + .resolve_mode = vk::resolved_mode_flags::none, + .resolve_image_view = nullptr, + .resolve_image_layout = vk::image_layout::undefined, + .load = vk::attachment_load::clear, + .store = vk::attachment_store::store, + .depth_values = depth_value + }; + + vk::rendering_begin_parameters ui_begin_params = { + .render_area = { { 0, 0 }, { m_window_params.width, m_window_params.height }, }, + .layer_count = 1, + .color_attachments = std::span( + &ui_color_render_attachment, 1), + .depth_attachment = ui_depth_stencil_attachment, + .stencil_attachment = ui_depth_stencil_attachment, + }; + + vk::viewport_params viewport = { + .x = 0.0f, + .y = 0.0f, + .width = static_cast(m_window_params.width), + .height = static_cast(m_window_params.height), + .min_depth = 0.0f, + .max_depth = 1.0f, + }; + current.set_viewport( + 0, 1, std::span(&viewport, 1)); + + vk::scissor_params scissor = { + .offset = { 0, 0 }, + .extent = { static_cast(m_window_params.width), + static_cast(m_window_params.height) }, + }; + current.set_scissor( + 0, 1, std::span(&scissor, 1)); + + current.begin_rendering(ui_begin_params); + + m_render_context.begin(m_projection, m_view); + m_render_context.end(); + + current.end_rendering(); + + m_imgui_context->image_memory_barrier( + current, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + /** + * Presenting to Swapchain Memory Barriers + */ + + vk::rendering_attachment present_color_render_attachment = { + .image_view = m_images[m_next_image_frame_idx].image_view(), + .layout = vk::image_layout::color_optimal, + .resolve_mode = vk::resolved_mode_flags::none, + .resolve_image_view = nullptr, + .resolve_image_layout = vk::image_layout::undefined, + .load = vk::attachment_load::clear, + .store = vk::attachment_store::store, + .clear_values = clear_color + }; + + vk::rendering_attachment present_depth_stencil_attachment = { + .image_view = + m_depth_images[m_next_image_frame_idx].image_view(), + .layout = vk::image_layout::depth_stencil_optimal, + .resolve_mode = vk::resolved_mode_flags::none, + .resolve_image_view = nullptr, + .resolve_image_layout = vk::image_layout::undefined, + .load = vk::attachment_load::clear, + .store = vk::attachment_store::store, + .depth_values = depth_value }; - m_window->current_swapchain().swapchain_renderpass().begin( - begin_renderpass); - m_ui_context.end(); - m_window->current_swapchain().swapchain_renderpass().end( - currently_active); - currently_active.end(); - - std::array commands = { - currently_active, + + vk::rendering_begin_parameters present_begin_params = { + .render_area = { { 0, 0 }, { m_window->extent().width, m_window->extent().height }, }, + .layer_count = 1, + .color_attachments = std::span( + &present_color_render_attachment, 1), + .depth_attachment = present_depth_stencil_attachment, + .stencil_attachment = present_depth_stencil_attachment, }; - m_window->current_swapchain().submit(commands); - m_window->present(m_current_frame_index); + m_images[m_next_image_frame_idx].memory_barrier( + current, + m_color_format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + m_depth_images[m_next_image_frame_idx].memory_barrier( + current, + m_depth_format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + current.begin_rendering(present_begin_params); + m_imgui_context->begin(); + m_imgui_context->set_current_command(current); + + invoke_ui_update(m_world.get()); + invoke_ui_update(m_current_scene.get()); + m_imgui_context->end(); + current.end_rendering(); + + m_images[m_next_image_frame_idx].memory_barrier( + current, + m_window->surface_properties().format.format, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + current.end(); + + const VkCommandBuffer command = current; + m_window->submit(std::span(&command, 1)); + m_window->present(m_next_image_frame_idx); + + // Update platform window afterwards + m_imgui_context->update_platforms(); } - } - /** - * @brief Performs any post cleanup when user requests the application - * to close - */ - void post_destroy() { console_log_info("Executing post cleanup!!!"); } - - /** - * @brief we only ever have one window - * - * This static function was a means to getting access to the window to - * perform any operations or request any data the window may have to - * provide - */ - // static window& get_window() { return *s_instance->m_window; } - - /* Retrieves the current selected graphics API */ - /** - * @return the currently specified API. - */ - static graphics_api current_api() { return graphics_api::vulkan; } - - /* Returns the currently selected swapchain */ - /** - * @brief gives you the current swapchain handle - * - * TODO: This is not actually needed, and should be removed - */ - VkSwapchainKHR get_current_swapchain() { - return m_window->current_swapchain(); + invoke_post_update(m_current_scene.get()); + invoke_post_update(m_world.get()); } - void current_world(ref p_world) { m_current_world = p_world; } + // Experimental: Will look into later once we dive into scene + // transitioning void on_scene_transition(event::scene_transition& + // p_scene_transition) { + // m_world->current(p_scene_transition.next_scene); + // std::println("Attempting to switch to the scene: {}", + // p_scene_transition.next_scene); + + // // We only want to set the current scene if that specific scene + // is valid if(m_world->current() != nullptr) { + // m_current_scene = m_world->current(); + // m_render_context.current_scene(*m_current_scene); + // } + // } + + void post_destroy() { + m_imgui_context->destruct(); + m_render_context.destruct(); + + for (auto& command : m_command_buffers) { + command.destruct(); + } - void reload_mesh(event::mesh_reload&) { - console_log_info( - "application::trigger invoked from core/application!"); - } + for (auto& color_image : m_images) { + color_image.destruct(); + } - void reload_material(event::material_reload&) { - console_log_info( - "application::trigger invoked from core/application!"); + for (auto& depth_image : m_depth_images) { + depth_image.destruct(); + } + m_window->destruct(); + m_device->destruct(); } - protected: - [[nodiscard]] ref renderer_instance() const { - return m_renderer; + void current_world(std::shared_ptr p_world) { + m_world = std::move(p_world); } private: - float m_delta_time = 0.f; - ref m_current_world; - ref m_window; - window_params m_initial_window_params; - ref m_renderer = nullptr; - glm::mat4 m_projection; - glm::mat4 m_view; - uint32_t m_current_frame_index = -1; - vulkan::imgui_context m_ui_context; + float m_aspect_ratio = 0.f; + uint32_t m_next_image_frame_idx = 0; + VkFormat m_color_format; + VkFormat m_depth_format; + std::shared_ptr m_context; + std::shared_ptr m_window = nullptr; event::bus* m_bus = nullptr; + glm::mat4 m_view = glm::mat4(1.f); + glm::mat4 m_projection = glm::mat4(1.f); + + render_context m_render_context; + + std::shared_ptr m_world; + + std::shared_ptr m_imgui_context; + std::shared_ptr m_current_scene = nullptr; + + // vulkan-cpp specific handles + vk::instance m_instance; + std::optional m_physical; + std::shared_ptr m_device; + std::vector m_images; + std::vector m_depth_images; + std::vector m_command_buffers; + float m_delta_time = 0.f; + window_params m_window_params{}; static application* s_instance; }; diff --git a/atlas/core/common.cppm b/atlas/core/common.cppm index 62f1de6d..b84a8c0f 100644 --- a/atlas/core/common.cppm +++ b/atlas/core/common.cppm @@ -3,7 +3,7 @@ module; #include #include -export module atlas.common; +export module atlas.core.utilities:common; export namespace atlas { /** diff --git a/atlas/core/core.cppm b/atlas/core/core.cppm index 7c580ddc..3f1869ec 100644 --- a/atlas/core/core.cppm +++ b/atlas/core/core.cppm @@ -1,8 +1 @@ export module core; - -// export import :common; -export import atlas.common; -// export import :application; -// export import :logger; - -export namespace atlas {}; \ No newline at end of file diff --git a/atlas/core/editor/dockspace.cppm b/atlas/core/editor/dockspace.cppm index 4dd6f438..2a37d59c 100644 --- a/atlas/core/editor/dockspace.cppm +++ b/atlas/core/editor/dockspace.cppm @@ -6,7 +6,7 @@ module; #include -export module atlas.core.editor.dockspace; +export module atlas.core.editor:dockspace; export namespace atlas::ui { /** diff --git a/atlas/core/editor/editor.cppm b/atlas/core/editor/editor.cppm new file mode 100644 index 00000000..936b7285 --- /dev/null +++ b/atlas/core/editor/editor.cppm @@ -0,0 +1,6 @@ +module; + +export module atlas.core.editor; + +export import :menu_item; +export import :dockspace; \ No newline at end of file diff --git a/atlas/core/editor/menu_item.cppm b/atlas/core/editor/menu_item.cppm index 9ff2209a..2f0035d3 100644 --- a/atlas/core/editor/menu_item.cppm +++ b/atlas/core/editor/menu_item.cppm @@ -6,7 +6,7 @@ module; #include #include -export module atlas.core.editor.menu_item; +export module atlas.core.editor:menu_item; export namespace atlas::ui { struct block { diff --git a/atlas/core/entry_point/main.cpp b/atlas/core/entry_point/main.cpp index 0725c701..724d3fb8 100644 --- a/atlas/core/entry_point/main.cpp +++ b/atlas/core/entry_point/main.cpp @@ -1,18 +1,67 @@ // For glfwInit call #include +#include +#include +#include +#include +#include + +#define GLFW_INCLUDE_VULKAN +#if _WIN32 +#define VK_USE_PLATFORM_WIN32_KHR +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include +#else +#include +#include +#endif + import atlas.application; -import atlas.common; -import atlas.logger; -import atlas.graphics_api; -import atlas.drivers.graphics_context; -import atlas.renderer.context_loader; +import atlas.core.utilities; +import atlas.drivers.vulkan; import atlas.core.event; +import vk; // Defined in the user-application side [[nodiscard]] atlas::ref initialize_application( - atlas::ref p_context, + std::shared_ptr p_context, atlas::event::bus& p_bus); +static VKAPI_ATTR VkBool32 VKAPI_CALL +debug_callback( + [[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, + [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT p_message_type, + const VkDebugUtilsMessengerCallbackDataEXT* p_callback_data, + [[maybe_unused]] void* p_user_data) { + std::print("validation layer:\t\t{}\n\n", p_callback_data->pMessage); + return false; +} + +std::vector +get_instance_extensions() { + std::vector extension_names; + uint32_t extension_count = 0; + const char** required_extensions = + glfwGetRequiredInstanceExtensions(&extension_count); + + for (uint32_t i = 0; i < extension_count; i++) { + std::println("Required Extension = {}", required_extensions[i]); + extension_names.emplace_back(required_extensions[i]); + } + + extension_names.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + +#if defined(__APPLE__) + extension_names.emplace_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + extension_names.emplace_back( + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#endif + + return extension_names; +} + int main() { // We should not have our core system start up during testing environment @@ -23,17 +72,105 @@ main() { return -1; } - atlas::event::bus event_bus; - atlas::ref context = - atlas::initialize_context("vulkan", atlas::graphics_api::vulkan); + if (!glfwVulkanSupported()) { + std::println("GLFW: Vulkan is not supported!"); + return -1; + } + std::array validation_layers = { + "VK_LAYER_KHRONOS_validation", + }; + + // Retrieving the Vulkan instance-level extensions + std::vector global_extensions = get_instance_extensions(); + + vk::debug_message_utility debug_callback_info = { + .severity = + vk::message::verbose | vk::message::warning | vk::message::error, + .message_type = + vk::debug::general | vk::debug::validation | vk::debug::performance, + .callback = debug_callback + }; + + vk::application_params config = { + .name = "vulkan instance", + // specify to using vulkan 1.4 + .version = vk::api_version::vk_1_4, + // .validation takes in a std::span + .validations = validation_layers, + // .extensions also takes in std::span + .extensions = global_extensions + }; + + // 1. Setting up vk instance + vk::instance api_instance(config, debug_callback_info); +#if defined(__APPLE__) + std::expected physical_device_expected = + api_instance.enumerate_physical_device(vk::physical_gpu::integrated); +#else + std::expected physical_device_expected = + api_instance.enumerate_physical_device(vk::physical_gpu::discrete); +#endif + vk::physical_device physical_device = physical_device_expected.value(); + + std::array priorities = { 0.f }; +#if defined(__APPLE__) + std::array extensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + "VK_KHR_portability_subset", + "VK_KHR_dynamic_rendering", + }; +#else + std::array extensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + "VK_KHR_dynamic_rendering", + }; +#endif + + vk::device_features device_features{ + vk::dynamic_rendering_feature{ { + .dynamicRendering = true, + } }, + vk::descriptor_indexing_feature{ { + .shaderSampledImageArrayNonUniformIndexing = true, + .descriptorBindingSampledImageUpdateAfterBind = true, + .descriptorBindingPartiallyBound = true, + .descriptorBindingVariableDescriptorCount = true, + .runtimeDescriptorArray = true, + } }, + vk::buffer_device_address{ { + .bufferDeviceAddress = true, + } }, + }; + + vk::device_params logical_device_params = { + .features = device_features.data(), + .queue_priorities = priorities, + .extensions = extensions, + .queue_family_index = 0, + }; + + std::array bytes{}; + std::pmr::monotonic_buffer_resource memory_resource{ bytes.data(), + bytes.size() }; + std::pmr::polymorphic_allocator allocator{ &memory_resource }; + + std::shared_ptr logical_device = + std::allocate_shared( + allocator, physical_device, logical_device_params); + + std::shared_ptr context = + std::allocate_shared( + allocator, api_instance, physical_device, logical_device); + + atlas::event::bus event_bus; atlas::ref app = initialize_application(context, event_bus); app->execute(); - app->post_destroy(); + logical_device->wait(); - context->destroy(); + app->post_destroy(); return 0; } \ No newline at end of file diff --git a/atlas/core/event/event.cppm b/atlas/core/event/event.cppm index 6c6da69f..376c48fd 100644 --- a/atlas/core/event/event.cppm +++ b/atlas/core/event/event.cppm @@ -26,6 +26,13 @@ namespace atlas { */ enum input_state { None, Idle, Pressed, Released }; + export enum cursor_mode : uint32_t { + normal = 0x00034001, + hidden = 0x00034002, + disabled = 0x00034003, + captured = 0x00034004, + }; + struct joystick_button { int ID = -1; std::string Name = ""; @@ -143,6 +150,11 @@ namespace atlas { s_window_address = p_window; } + void set_cursor_mode(cursor_mode p_mode) { + glfwSetInputMode( + s_window_address, GLFW_CURSOR, static_cast(p_mode)); + } + // specfying listening for events void flush_events() { glfwPollEvents(); diff --git a/atlas/core/event/types.cppm b/atlas/core/event/types.cppm index 0fb4f1bc..d988564f 100644 --- a/atlas/core/event/types.cppm +++ b/atlas/core/event/types.cppm @@ -1,7 +1,7 @@ module; #include -#include +#include export module atlas.core.event:types; @@ -29,8 +29,8 @@ export namespace atlas::event { * @param to_scene is the new scene that is going to be transitioned to */ struct scene_transition { - const void* from_scene; - const void* to_scene; + std::string from_scene; + std::string next_scene; }; /** diff --git a/atlas/core/filesystem/file_dialog.cppm b/atlas/core/filesystem/file_dialog.cppm index 03954ba5..ae31d2cf 100644 --- a/atlas/core/filesystem/file_dialog.cppm +++ b/atlas/core/filesystem/file_dialog.cppm @@ -6,7 +6,7 @@ module; export module atlas.core.filesystem.file_dialog; -import atlas.logger; +import atlas.core.utilities; export namespace atlas::filesystem { std::string load_from_file_dialog( diff --git a/atlas/core/logger.cppm b/atlas/core/logger.cppm index e71f24b6..54b4a1a8 100644 --- a/atlas/core/logger.cppm +++ b/atlas/core/logger.cppm @@ -10,8 +10,8 @@ module; #include #include -export module atlas.logger; -export import atlas.common; +export module atlas.core.utilities:logger; +import :common; export namespace atlas { /** diff --git a/atlas/core/math/math.cppm b/atlas/core/math/math.cppm index 580bb924..6d88fa7a 100644 --- a/atlas/core/math/math.cppm +++ b/atlas/core/math/math.cppm @@ -4,6 +4,7 @@ module; #include export module atlas.core.math; +export import :types; export namespace atlas { diff --git a/atlas/core/math/types.cppm b/atlas/core/math/types.cppm index 330b18bc..0c3811b1 100644 --- a/atlas/core/math/types.cppm +++ b/atlas/core/math/types.cppm @@ -3,7 +3,7 @@ module; #include #include -export module atlas.core.math.types; +export module atlas.core.math:types; export namespace atlas { diff --git a/atlas/core/scene/components.cppm b/atlas/core/scene/components.cppm index 41d36647..6a525d46 100644 --- a/atlas/core/scene/components.cppm +++ b/atlas/core/scene/components.cppm @@ -5,7 +5,7 @@ module; #include #include -export module atlas.core.scene.components; +export module atlas.core.scene:components; import atlas.core.math; diff --git a/atlas/core/scene/game_object.cppm b/atlas/core/scene/game_object.cppm index 381e3955..664cded5 100644 --- a/atlas/core/scene/game_object.cppm +++ b/atlas/core/scene/game_object.cppm @@ -3,8 +3,8 @@ module; #include #include -export module atlas.core.scene.game_object; -import atlas.core.scene.components; +export module atlas.core.scene:game_object; +import :components; export namespace atlas { /** diff --git a/atlas/core/scene/level_streamer.cppm b/atlas/core/scene/level_streamer.cppm index d3c8a566..4f2124df 100644 --- a/atlas/core/scene/level_streamer.cppm +++ b/atlas/core/scene/level_streamer.cppm @@ -8,9 +8,8 @@ module; export module atlas.core.level_streamer; -import atlas.logger; +import atlas.core.utilities; import atlas.core.scene; -import atlas.core.scene.uuid; import atlas.core.event; export namespace atlas { @@ -34,19 +33,30 @@ export namespace atlas { * @return the currently active scene to retrieve */ ref current_scene(const std::string& p_name) { + if (!m_scenes.contains(p_name)) { + return nullptr; + } + return m_scenes[p_name]; } template void default_scene(const std::string& p_name, event::bus& p_bus) { m_scenes.emplace( - p_name, - std::allocate_shared( - std::pmr::polymorphic_allocator(m_allocator.resource()), - p_name, - p_bus)); + p_name, std::allocate_shared(m_allocator, p_name, p_bus)); } + // Experimental: This was just for testing. Will come back to later. + // template + // void create_scene(const std::string& p_name, event::bus& p_bus) { + // m_scenes.emplace( + // p_name, + // std::allocate_shared( + // std::pmr::polymorphic_allocator(m_allocator.resource()), + // p_name, + // p_bus)); + // } + /** * @brief used to iterate through over the scenes created * diff --git a/atlas/core/scene/scene.cppm b/atlas/core/scene/scene.cppm index 746222f7..81b9747c 100644 --- a/atlas/core/scene/scene.cppm +++ b/atlas/core/scene/scene.cppm @@ -7,9 +7,9 @@ export module atlas.core.scene; import atlas.core.utilities; import atlas.core.event; -import atlas.core.scene.game_object; -import atlas.core.scene.uuid; -import atlas.core.scene.components; +export import :game_object; +export import :uuid; +export import :components; export namespace atlas { /** diff --git a/atlas/core/scene/uuid.cppm b/atlas/core/scene/uuid.cppm index 590c6199..138725cb 100644 --- a/atlas/core/scene/uuid.cppm +++ b/atlas/core/scene/uuid.cppm @@ -2,7 +2,7 @@ module; #include #include -export module atlas.core.scene.uuid; +export module atlas.core.scene:uuid; export namespace atlas { diff --git a/atlas/core/scene/world.cppm b/atlas/core/scene/world.cppm index 0616e4de..000a6d71 100644 --- a/atlas/core/scene/world.cppm +++ b/atlas/core/scene/world.cppm @@ -6,7 +6,7 @@ module; export module atlas.core.scene.world; -import atlas.common; +import atlas.core.utilities; import atlas.core.scene; import atlas.core.level_streamer; import atlas.core.event; @@ -64,6 +64,11 @@ export namespace atlas { m_current = m_level_streamer->current_scene(p_name); } + // template + // void create_scene(const std::string& p_name, event::bus& p_bus) { + // m_level_streamer->create_scene(p_name, p_bus); + // } + private: ref m_current; std::string m_name = "Undefined Tag"; diff --git a/atlas/core/serialize/serializer.cppm b/atlas/core/serialize/serializer.cppm index cdeaeb06..3d66df17 100644 --- a/atlas/core/serialize/serializer.cppm +++ b/atlas/core/serialize/serializer.cppm @@ -1,7 +1,5 @@ module; -// #include -// #include #include #include #include @@ -9,14 +7,13 @@ module; #include #include #include +#include export module atlas.core.serialize; -import atlas.common; import atlas.core.scene; import atlas.core.serialize.types; -import atlas.core.scene.components; -import atlas.logger; +import atlas.core.utilities; namespace atlas { // used to serialize entities @@ -93,13 +90,15 @@ namespace atlas { // Deserialize atlas::material component if (p_entity_value["Mesh Source"]) { - auto perspective_camera_data = p_entity_value["Mesh Source"]; - p_deserialize_to_object.set({ - .model_path = - perspective_camera_data["Model Path"].as(), - .diffuse = perspective_camera_data["Diffuse"].as(), - .specular = perspective_camera_data["Specular"].as(), - }); + auto mesh = p_entity_value["Mesh Source"]; + if (!mesh["Model Path"].as().empty()) { + p_deserialize_to_object.set({ + .flip = static_cast(mesh["Flip"].as()), + .model_path = mesh["Model Path"].as(), + .diffuse = mesh["Diffuse"].as(), + .specular = mesh["Specular"].as(), + }); + } } if (p_entity_value["Point Light"]) { @@ -177,8 +176,8 @@ namespace atlas { * @param p_scene_ctx is the current scene to perform * serialization/deserialization to */ - serializer(const ref& p_scene_ctx) - : m_current_scene_ctx(p_scene_ctx) {} + serializer(ref p_scene) + : m_current_scene_ctx(/*NOLINT*/ p_scene) {} /** * @param p_filepath is the specified path to save the file @@ -208,8 +207,9 @@ namespace atlas { .without() .build(); - q.each([&output](flecs::entity p_entity_id) { - serialize_entity(output, p_entity_id); + q.each([&output](flecs::entity p_entity) { + std::println("Serialize Entity: {}", p_entity.name().c_str()); + serialize_entity(output, p_entity); }); std::ofstream output_file(p_filepath.string()); @@ -235,7 +235,7 @@ namespace atlas { return false; } - console_log_info("Before loading environment mappings!"); + // console_log_info("Before loading environment mappings!"); std::string environment_map_data = ""; if (data["Environment"]) { environment_map_data = data["Environment"].as(); @@ -244,7 +244,10 @@ namespace atlas { environment_map_data); } - p_registry.set({ .filepath = environment_map_data }); + if (!environment_map_data.empty()) { + p_registry.set( + { .filepath = environment_map_data }); + } YAML::Node entity_objects = data["Entities"]; diff --git a/atlas/core/serialize/types.cppm b/atlas/core/serialize/types.cppm index e576edae..f8464c61 100644 --- a/atlas/core/serialize/types.cppm +++ b/atlas/core/serialize/types.cppm @@ -4,7 +4,7 @@ module; #include export module atlas.core.serialize.types; -import atlas.core.scene.components; +import atlas.core.scene; namespace YAML { /** @@ -404,6 +404,7 @@ export namespace atlas { p_output << YAML::Key << "Mesh Source"; p_output << YAML::BeginMap; + p_output << YAML::Key << "Flip" << YAML::Value << p_material->flip; p_output << YAML::Key << "Model Path" << YAML::Value << p_material->model_path; p_output << YAML::Key << "Diffuse" << YAML::Value diff --git a/atlas/core/ui/imgui_stdlib.cppm b/atlas/core/ui/imgui_stdlib.cppm index 888093bd..52cb5490 100644 --- a/atlas/core/ui/imgui_stdlib.cppm +++ b/atlas/core/ui/imgui_stdlib.cppm @@ -3,7 +3,7 @@ module; #include #include -export module atlas.core.ui.widgets.imgui_stdlib; +export module atlas.core.ui:imgui_stdlib; struct InputTextCallback_UserData { std::string* Str; diff --git a/atlas/core/ui/ui.cppm b/atlas/core/ui/ui.cppm new file mode 100644 index 00000000..9bf9a9ca --- /dev/null +++ b/atlas/core/ui/ui.cppm @@ -0,0 +1,6 @@ +module; + +export module atlas.core.ui; + +export import :widgets; +export import :imgui_stdlib; \ No newline at end of file diff --git a/atlas/core/ui/widgets.cppm b/atlas/core/ui/widgets.cppm index b6459ddb..dcac9168 100644 --- a/atlas/core/ui/widgets.cppm +++ b/atlas/core/ui/widgets.cppm @@ -8,10 +8,10 @@ module; #include #include -export module atlas.core.ui.widgets; +export module atlas.core.ui:widgets; import atlas.core.filesystem.file_dialog; -import atlas.core.scene.components; +import atlas.core.scene; export namespace atlas::ui { using ::ImGui::InputText; diff --git a/atlas/core/utilities/poll_state.cppm b/atlas/core/utilities/poll_state.cppm index ebc93631..e384967b 100644 --- a/atlas/core/utilities/poll_state.cppm +++ b/atlas/core/utilities/poll_state.cppm @@ -1,10 +1,11 @@ module; +#include #include #include #include -export module atlas.core.utilities.poll_state; +export module atlas.core.utilities:poll_state; export namespace atlas { inline std::unordered_map>> @@ -17,6 +18,8 @@ export namespace atlas { s_physica_update{}; inline std::unordered_map>> s_start{}; + inline std::unordered_map>> + s_post{}; void poll_update(void* p_address, const std::function& p_callback) { @@ -42,26 +45,9 @@ export namespace atlas { s_start[p_address].emplace_back(p_callback); } - // TEMP: This is a temporary solution, should look into doing this - // differently - void remove_update(void* p_address) { - s_update.erase(p_address); - } - - void remove_defer_update(void* p_address) { - s_defer_update.erase(p_address); - } - - void remove_physics_update(void* p_address) { - s_physica_update.erase(p_address); - } - - void remove_ui_update(void* p_address) { - s_ui_update.erase(p_address); - } - - void remove_start(void* p_address) { - s_start.erase(p_address); + void post_update_poll(void* p_address, + const std::function& p_callback) { + s_post[p_address].emplace_back(p_callback); } /** @@ -82,10 +68,6 @@ export namespace atlas { * */ void invoke_on_update(void* p_scene, float p_delta_time) { - // for (auto& [address, on_update] : s_update) { - // on_update(p_delta_time); - // } - for (auto& on_update : s_update[p_scene]) { on_update(p_delta_time); } @@ -114,4 +96,10 @@ export namespace atlas { on_update(); } } + + void invoke_post_update(void* p_scene) { + for (auto& post_update : s_post[p_scene]) { + post_update(); + } + } }; \ No newline at end of file diff --git a/atlas/core/utilities/state.cppm b/atlas/core/utilities/state.cppm index 48a55ea3..cf4f7f94 100644 --- a/atlas/core/utilities/state.cppm +++ b/atlas/core/utilities/state.cppm @@ -3,9 +3,9 @@ module; #include #include -export module atlas.core.utilities.state; +export module atlas.core.utilities:state; -import atlas.core.utilities.poll_state; +import :poll_state; export namespace atlas { /** @@ -169,4 +169,14 @@ export namespace atlas { (p_instance->*p_callable)(); }); } + + template + void register_post(UObject* p_instance, const UCallback& p_callable) { + static_assert(std::is_member_pointer_v, + "Cannot register a function that is not a member " + "function of a class object"); + post_update_poll(p_instance, [p_instance, p_callable]() { + (p_instance->*p_callable)(); + }); + } }; \ No newline at end of file diff --git a/atlas/core/utilities/types.cppm b/atlas/core/utilities/types.cppm deleted file mode 100644 index eb2e8700..00000000 --- a/atlas/core/utilities/types.cppm +++ /dev/null @@ -1,21 +0,0 @@ -module; - -#include -#include -#include - -export module atlas.core.utilities.types; - -export namespace atlas { - struct window_params { - uint32_t width; - uint32_t height; - std::string name = ""; - }; - - // TODO: Move this into atlas.drivers.vulkan.utilities - struct surface_properties { - VkSurfaceCapabilitiesKHR surface_capabilities; - VkSurfaceFormatKHR surface_format; - }; -}; \ No newline at end of file diff --git a/atlas/core/utilities/utilities.cppm b/atlas/core/utilities/utilities.cppm index 0261aff2..0b48cb03 100644 --- a/atlas/core/utilities/utilities.cppm +++ b/atlas/core/utilities/utilities.cppm @@ -1,7 +1,19 @@ +module; + +#include +#include + export module atlas.core.utilities; -export import atlas.logger; -export import atlas.common; -export import atlas.graphics_api; -export import atlas.core.utilities.types; -export import atlas.core.utilities.state; +export import :logger; +export import :common; +export import :poll_state; +export import :state; + +namespace atlas { + export struct window_params { + uint32_t width; + uint32_t height; + std::string name = ""; + }; +}; \ No newline at end of file diff --git a/atlas/core/window.cppm b/atlas/core/window.cppm deleted file mode 100644 index 58edb5c5..00000000 --- a/atlas/core/window.cppm +++ /dev/null @@ -1,106 +0,0 @@ -module; - -#include -#include -#include - -export module atlas.window; - -// import atlas.common; -// import atlas.graphics_api; -// import atlas.core.utilities.types; -import atlas.core.utilities; -import atlas.drivers.vulkan.swapchain; -import vk; - -export namespace atlas { - - class window { - public: - virtual ~window() = default; - - [[nodiscard]] window_params data() const { return get_params(); } - - /** - * @brief Checks if window is available to close - */ - [[nodiscard]] bool available() const { - return !glfwWindowShouldClose(native_window()); - } - - /** - * @brief Returns the aspect ratio of the current window - */ - [[nodiscard]] float aspect_ratio() const { - return static_cast(get_params().width) / - static_cast(get_params().height); - } - - /** - * @brief gives you the next presentable image to use and the index to - * retrieving that image - * - * @return uint32_t - */ - [[nodiscard]] uint32_t acquired_next_frame() { - return read_acquired_next_frame(); - } - - /** - * @brief Returns the window's currently selected swapchain - */ - [[nodiscard]] vulkan::swapchain current_swapchain() const { - return window_swapchain(); - } - - /** - * @brief retrieves the current command buffer using the current frame - * index to ensure we are processing commands to the right command - * buffer in our current frame - * - * @return command buffer to actively record commands to - */ - vk::command_buffer active_command(uint32_t p_frame_index) { - return current_active_command(p_frame_index); - } - - /** - * @brief operator overload for treating atlas::window as a GLFWwindow - * handle - */ - operator GLFWwindow*() const { return native_window(); } - - /** - * @brief operator overload for treating atlas::window as a GLFWwindow - * handle - */ - operator GLFWwindow*() { return native_window(); } - - /** - * @brief Closing the window operation - */ - void close() { glfwSetWindowShouldClose(native_window(), true); } - - /** - * @brief does the presentation operation that is operated internally - * with the vulkan swapchain - * - * @param p_current_frame_idx is current frame index to currently - * process an image in the current frame - */ - void present(const uint32_t& p_current_frame_idx) { - return present_frame(p_current_frame_idx); - } - - protected: - [[nodiscard]] virtual window_params get_params() const = 0; - [[nodiscard]] virtual GLFWwindow* native_window() const = 0; - [[nodiscard]] virtual uint32_t read_acquired_next_frame() = 0; - [[nodiscard]] virtual vulkan::swapchain window_swapchain() const = 0; - - [[nodiscard]] virtual vk::command_buffer current_active_command( - uint32_t p_frame_idx) = 0; - - virtual void present_frame(const uint32_t& p_current_frame) = 0; - }; -}; \ No newline at end of file diff --git a/atlas/drivers/drivers.cppm b/atlas/drivers/drivers.cppm deleted file mode 100644 index 12820831..00000000 --- a/atlas/drivers/drivers.cppm +++ /dev/null @@ -1,41 +0,0 @@ -module; - -#include - -export module atlas.drivers; - -import atlas.core.utilities; -import atlas.window; -import atlas.drivers.graphics_context; -import atlas.drivers.vulkan.window_context; - -/** - * @brief This drivers.cppm will contain API-agnostic implementation that may be - * widely implemented differently. - * - * Such as Window contexts, graphics API-agnostic implementation, renderers, - * etc. - */ - -export namespace atlas { - /** - * @brief constructs an atlas::window - * - * There should only ever be one window constructed throughout the entire - * application - * - * @param p_settings is the window settings to construct the window with - * - * @return shared_ptr - */ - ref initialize_window(ref p_context, - const window_params& p_params, - graphics_api p_api) { - switch (p_api) { - case graphics_api::vulkan: - return create_ref(p_context, p_params); - default: - return nullptr; - } - } -}; \ No newline at end of file diff --git a/atlas/drivers/graphics_context.cppm b/atlas/drivers/graphics_context.cppm deleted file mode 100644 index 3f0c8108..00000000 --- a/atlas/drivers/graphics_context.cppm +++ /dev/null @@ -1,30 +0,0 @@ -module; - -#include -#include - -export module atlas.drivers.graphics_context; - -export namespace atlas { - - class graphics_context { - public: - virtual ~graphics_context() = default; - - void submit_resource_free(const std::function& p_resource) { - return context_submit_resource_free(p_resource); - } - - [[nodiscard]] VkInstance handle() const { return context_handle(); } - - void destroy() { return destroy_context(); } - - protected: - virtual void destroy_context() = 0; - virtual void context_submit_resource_free( - const std::function& p_resource) = 0; - - [[nodiscard]] virtual VkInstance context_handle() const = 0; - }; - -}; \ No newline at end of file diff --git a/atlas/drivers/importer/importer.cppm b/atlas/drivers/importer/importer.cppm new file mode 100644 index 00000000..e745b282 --- /dev/null +++ b/atlas/drivers/importer/importer.cppm @@ -0,0 +1,6 @@ +module; + +export module atlas.drivers.importer; + +// Importers to load .obj 3D models +export import :obj_loader; \ No newline at end of file diff --git a/atlas/drivers/importer/obj_loader.cppm b/atlas/drivers/importer/obj_loader.cppm new file mode 100644 index 00000000..42d76fc1 --- /dev/null +++ b/atlas/drivers/importer/obj_loader.cppm @@ -0,0 +1,144 @@ +module; + +#include +#include +#include +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +export module atlas.drivers.importer:obj_loader; + +import vk; + +template +void +hash_combine(size_t& seed, const T& v, const Rest&... rest) { + seed ^= std::hash()(v) + 0x9e3779b9 + (seed << 6) + (seed << 2); + (hash_combine(seed, rest), ...); +} + +namespace std { + + template<> + struct hash { + size_t operator()(const vk::vertex_input& vertex) const { + size_t seed = 0; + hash_combine( + seed, vertex.position, vertex.color, vertex.normals, vertex.uv); + return seed; + } + }; +} + +export namespace atlas { + class obj_importer { + public: + obj_importer(const std::string& p_path, bool p_flip) + : m_flip(p_flip) { + m_load = load(p_path); + } + + bool load(const std::string& p_path) { + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + std::string warn; + std::string err; + + if (!tinyobj::LoadObj( + &attrib, &shapes, &materials, &warn, &err, p_path.c_str())) { + return false; + } + + std::unordered_map unique_vertices{}; + + for (const auto& shape_face : shapes) { + for (const auto& index : shape_face.mesh.indices) { + vk::vertex_input vertex{}; + + if (!unique_vertices.contains(vertex)) { + unique_vertices[vertex] = + static_cast(m_vertices.size()); + m_vertices.push_back(vertex); + } + + if (index.vertex_index >= 0) { + vertex.position = { + attrib.vertices[3 * index.vertex_index + 0], + attrib.vertices[3 * index.vertex_index + 1], + attrib.vertices[3 * index.vertex_index + 2] + }; + + vertex.color = { + attrib.colors[3 * index.vertex_index + 0], + attrib.colors[3 * index.vertex_index + 1], + attrib.colors[3 * index.vertex_index + 2] + }; + } + + if (index.normal_index >= 0) { + vertex.normals = { + attrib.normals[3 * index.normal_index + 0], + attrib.normals[3 * index.normal_index + 1], + attrib.normals[3 * index.normal_index + 2] + }; + } + + if (!attrib.texcoords.empty()) { + glm::vec2 flipped_uv = { + attrib.texcoords[static_cast( + index.texcoord_index) * + 2], + 1.0f - attrib.texcoords[static_cast( + index.texcoord_index) * + 2 + + 1], + }; + + glm::vec2 original_uv = { + attrib.texcoords[static_cast( + index.texcoord_index) * + 2], + attrib.texcoords[static_cast( + index.texcoord_index) * + 2 + + 1], + }; + + vertex.uv = m_flip ? flipped_uv : original_uv; + } + else { + vertex.uv = glm::vec2(0.f, 0.f); + } + + if (!unique_vertices.contains(vertex)) { + unique_vertices[vertex] = + static_cast(m_vertices.size()); + m_vertices.push_back(vertex); + } + + m_indices.push_back(unique_vertices[vertex]); + } + } + + return true; + } + + [[nodiscard]] bool is_load() const { return m_load; } + + //! @return the geometry vertices + std::span vertices() { return m_vertices; } + + //! @return the geometry indices + std::span indices() { return m_indices; } + + private: + std::vector m_vertices; + std::vector m_indices; + bool m_flip = false; + bool m_load = false; + }; +}; \ No newline at end of file diff --git a/atlas/drivers/jolt_cpp/broad_phase.cppm b/atlas/drivers/jolt_cpp/broad_phase.cppm index cb4d9b71..85fa99cb 100644 --- a/atlas/drivers/jolt_cpp/broad_phase.cppm +++ b/atlas/drivers/jolt_cpp/broad_phase.cppm @@ -32,9 +32,9 @@ module; #include #include -export module atlas.drivers.jolt_cpp.broad_phase; +export module atlas.drivers.jolt_cpp:broad_phase; -import atlas.common; +import atlas.core.utilities; export namespace atlas::physics { diff --git a/atlas/drivers/jolt_cpp/contact_listener.cppm b/atlas/drivers/jolt_cpp/contact_listener.cppm index d5ba6a54..146a36ac 100644 --- a/atlas/drivers/jolt_cpp/contact_listener.cppm +++ b/atlas/drivers/jolt_cpp/contact_listener.cppm @@ -32,9 +32,8 @@ module; #include #include -export module atlas.drivers.jolt_cpp.contact_listener; -import atlas.logger; -// import atlas.core.event.types; +export module atlas.drivers.jolt_cpp:contact_listener; +import atlas.core.utilities; import atlas.core.event; export namespace atlas::physics { diff --git a/atlas/drivers/jolt_cpp/context.cppm b/atlas/drivers/jolt_cpp/context.cppm index 2d874ace..39c7b268 100644 --- a/atlas/drivers/jolt_cpp/context.cppm +++ b/atlas/drivers/jolt_cpp/context.cppm @@ -35,20 +35,16 @@ module; #include #include -export module atlas.drivers.jolt_cpp.context; +export module atlas.drivers.jolt_cpp:context; + +import :broad_phase; +import :contact_listener; +import :math; -// import atlas.logger; -// import atlas.common; import atlas.core.utilities; import atlas.core.event; -import atlas.core.scene.components; - -import atlas.drivers.jolt_cpp.broad_phase; -import atlas.drivers.jolt_cpp.contact_listener; - -import atlas.drivers.jolt_cpp.types; +import atlas.core.scene; import atlas.drivers.physics_context; -import atlas.drivers.jolt_cpp.types; namespace atlas::physics { @@ -99,7 +95,7 @@ namespace atlas::physics { uint32_t max_contact_constraints = 8192; }; - static void trace_impl(const char* p_in_fmt, ...) { + void trace_impl(const char* p_in_fmt, ...) { va_list list; va_start(list, p_in_fmt); char buffer[1024]; diff --git a/atlas/drivers/jolt_cpp/jolt_cpp.cppm b/atlas/drivers/jolt_cpp/jolt_cpp.cppm new file mode 100644 index 00000000..461de37f --- /dev/null +++ b/atlas/drivers/jolt_cpp/jolt_cpp.cppm @@ -0,0 +1,6 @@ +export module atlas.drivers.jolt_cpp; + +export import :context; +export import :broad_phase; +export import :contact_listener; +export import :math; \ No newline at end of file diff --git a/atlas/drivers/jolt_cpp/math.cppm b/atlas/drivers/jolt_cpp/math.cppm index 828b3a56..432d05ec 100644 --- a/atlas/drivers/jolt_cpp/math.cppm +++ b/atlas/drivers/jolt_cpp/math.cppm @@ -9,8 +9,8 @@ module; #include #define GLM_ENABLE_EXPERIMENTAL #include -export module atlas.drivers.jolt_cpp.types; -import atlas.core.math.types; +export module atlas.drivers.jolt_cpp:math; +import atlas.core.math; export namespace atlas { template<> diff --git a/atlas/drivers/physics_context.cppm b/atlas/drivers/physics_context.cppm index 2418b33c..5fc13c32 100644 --- a/atlas/drivers/physics_context.cppm +++ b/atlas/drivers/physics_context.cppm @@ -5,8 +5,8 @@ module; export module atlas.drivers.physics_context; -import atlas.common; -import atlas.core.scene.components; +import atlas.core.utilities; +import atlas.core.scene; import atlas.core.event; namespace atlas::physics { diff --git a/atlas/drivers/renderer_system.cppm b/atlas/drivers/renderer_system.cppm index bf6dc842..fef82ec0 100644 --- a/atlas/drivers/renderer_system.cppm +++ b/atlas/drivers/renderer_system.cppm @@ -7,8 +7,6 @@ module; export module atlas.drivers.renderer_system; -// import atlas.core.utilities.types; -// import atlas.common; import atlas.core.utilities; import atlas.core.scene; import vk; diff --git a/atlas/drivers/vulkan/device.cppm b/atlas/drivers/vulkan/device.cppm deleted file mode 100644 index d333eae8..00000000 --- a/atlas/drivers/vulkan/device.cppm +++ /dev/null @@ -1,215 +0,0 @@ -module; - -#include - -#define GLFW_INCLUDE_VULKAN -#if _WIN32 -#define VK_USE_PLATFORM_WIN32_KHR -#include -#define GLFW_EXPOSE_NATIVE_WIN32 -#include -#include -#else -#include -#include -#endif - -#include -#include - -export module atlas.drivers.vulkan.device; - -import atlas.drivers.vulkan.utilities; -import atlas.drivers.vulkan.physical_device; - -namespace atlas::vulkan { - static VkFormat search_supported_depth_format( - const VkPhysicalDevice& p_physical, - std::span p_formats, - VkImageTiling p_tiling, - VkFormatFeatureFlags p_feature_flag) { - VkFormat format = VK_FORMAT_UNDEFINED; - - for (size_t i = 0; i < p_formats.size(); i++) { - VkFormat current_format = p_formats[i]; - VkFormatProperties format_properties; - vkGetPhysicalDeviceFormatProperties( - p_physical, current_format, &format_properties); - - if (p_tiling == VK_IMAGE_TILING_LINEAR) { - if (format_properties.linearTilingFeatures & p_feature_flag) { - format = current_format; - } - } - else if (p_tiling == VK_IMAGE_TILING_OPTIMAL and - format_properties.optimalTilingFeatures & p_feature_flag) { - format = current_format; - } - } - - return format; - } - - static VkFormat search_depth_format(const VkPhysicalDevice& p_physical) { - std::vector candidate_formats = { - VK_FORMAT_D32_SFLOAT, - VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_FORMAT_D24_UNORM_S8_UINT - }; - - VkFormat format = search_supported_depth_format( - p_physical, - candidate_formats, - VK_IMAGE_TILING_OPTIMAL, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); - return format; - } - - /** - * @brief logical device implementation wrapper around the VkDevice - * - * This class was a wrapper around VKDevice, that provided you with other - * API's to do with that particular logical device. - * - * Logical devices are representation of virtual software ways to interact - * with the GPU through Vulkan specifications - * - * TODO: Out-of-date. Using vulkan-cpp ::vk::device class to provide API's - * that allow you to do more queries on specific attributes the logical - * device gives you. - */ - export class device { - struct device_queue_family { - VkQueue graphics_queue; - VkQueue transfer_queue; - VkQueue compute_queue; - }; - - public: - device() = default; - - /** - * @brief construct a new logical device - * @param p_physical is the physical device required for the creation of - * the logical device - */ - device(const physical_device& p_physical) - : m_physical(p_physical) { - m_depth_format_selected = search_depth_format(m_physical); - - float queue_priority[1] = { 0.0f }; - -#if defined(__APPLE__) - std::vector device_extension = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, "VK_KHR_portability_subset" - }; -#else - std::vector device_extension = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; -#endif - - uint32_t graphics_index = - m_physical.read_queue_family_indices().graphics; - - VkDeviceQueueCreateInfo queue_create_info = { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .queueFamilyIndex = graphics_index, - .queueCount = 1, - .pQueuePriorities = queue_priority, - }; - - VkDeviceCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .queueCreateInfoCount = 1, - .pQueueCreateInfos = &queue_create_info, - .enabledLayerCount = 0, - .ppEnabledLayerNames = nullptr, - .enabledExtensionCount = - static_cast(device_extension.size()), - .ppEnabledExtensionNames = device_extension.data(), - }; - - VkPhysicalDeviceFeatures features; - vkGetPhysicalDeviceFeatures(m_physical, &features); - features.robustBufferAccess = false; - create_info.pEnabledFeatures = &features; - - vk_check( - vkCreateDevice(m_physical, &create_info, nullptr, &m_driver), - "vkCreateDevice"); - - vkGetDeviceQueue( - m_driver, graphics_index, 0, &m_device_queues.graphics_queue); - } - - // Use .destroy to explicitly invoke when to do proper vulkan cleanup - ~device() = default; - - /** - * @brief returns the specified graphics queue from this logical device - */ - [[nodiscard]] VkQueue graphics_queue() const { - return m_device_queues.graphics_queue; - } - - /** - * @return -1 if there are no flags available/compatible/valid - */ - uint32_t select_memory_type(uint32_t p_type_filter, - VkMemoryPropertyFlags p_property_flag) { - VkPhysicalDeviceMemoryProperties mem_props; - vkGetPhysicalDeviceMemoryProperties(m_physical, &mem_props); - - for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) { - if ((p_type_filter & (1 << i)) and - (mem_props.memoryTypes[i].propertyFlags & - p_property_flag) == p_property_flag) { - return i; - } - } - - return -1; - } - - void destroy() { - vkDeviceWaitIdle(m_driver); - vkDestroyDevice(m_driver, nullptr); - } - - /** - * @brief gives you the depth format from the logical device - * - * @return VkFormat - */ - [[nodiscard]] VkFormat depth_format() const { - return m_depth_format_selected; - } - - /** - * @brief allows to treat vk_driver as a VkDevice handle - * - * For vulkan API's that accept only taking in VKDevice, this simplifies - * the need to not have a getter API - */ - operator VkDevice() const { return m_driver; } - - /** - * @brief allows to treat vk_driver as a VkDevice handle - * - * For vulkan API's that accept only taking in VKDevice, this simplifies - * the need to not have a getter API - */ - operator VkDevice() { return m_driver; } - - private: - physical_device m_physical{}; - VkDevice m_driver = nullptr; - device_queue_family m_device_queues{}; - VkFormat m_depth_format_selected; - }; -}; diff --git a/atlas/drivers/vulkan/environment_map.cppm b/atlas/drivers/vulkan/environment_map.cppm index b06c4c05..0a9c2a87 100644 --- a/atlas/drivers/vulkan/environment_map.cppm +++ b/atlas/drivers/vulkan/environment_map.cppm @@ -7,6 +7,14 @@ module; #include #include #include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#define GLM_ENABLE_EXPERIMENTAL +#include +#include #define GLFW_INCLUDE_VULKAN #if _WIN32 @@ -21,598 +29,768 @@ module; #endif #include -#define GLM_FORCE_RADIANS -#include -#include -#define GLM_ENABLE_EXPERIMENTAL -#include -#include - -export module atlas.drivers.vulkan.environment_map; - -import atlas.drivers.vulkan.instance_context; +export module atlas.drivers.vulkan:environment_map; import vk; -namespace atlas { - - export struct skybox_uniform { - glm::mat4 proj_view; - }; - - export class environment_map { - public: - environment_map() = default; - - environment_map(const VkDevice& p_device, - const std::filesystem::path& p_filename, - VkPhysicalDeviceMemoryProperties p_memory_properties, - VkRenderPass p_renderpass) - : m_device(p_device) { - create_hdr_skybox(p_filename, p_memory_properties); - - create_skybox_pipeline(p_memory_properties, p_renderpass); +struct environment_uniforms { + glm::mat4 proj_view; +}; + +struct environment_push_constant { + uint64_t scene_environment_address = 0; +}; + +/** + * + * @brief Vulkan-specific implementation for loading GPU resources associated to + * loading environent maps. + * + */ +export class environment_map { +public: + environment_map() = default; + environment_map(std::shared_ptr p_device, + vk::physical_device& p_physical, + const std::string& p_filename, + /*NOLINT*/ VkFormat p_color_format, + VkFormat p_depth_format) + : m_color_format(p_color_format) + , m_depth_format(p_depth_format) { + /*NOLINT*/ m_device = p_device; + m_physical = p_physical; + m_memory_mask = + m_physical->memory_properties(vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit); + + construct(p_filename); + } + + environment_map(std::shared_ptr p_device, + vk::physical_device& p_physical, + std::span p_color, + const vk::image_extent& p_extent, + /*NOLINT*/ VkFormat p_color_format, + VkFormat p_depth_format) + : m_color_format(p_color_format) + , m_depth_format(p_depth_format) { + /*NOLINT*/ m_device = p_device; + m_physical = p_physical; + m_memory_mask = + m_physical->memory_properties(vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit); + + construct(p_color, p_extent); + } + + /** + * @brief loads in a new HDRI environment map + */ + void construct(const std::string& p_filename) { + bool res = create_hdr(p_filename); + + if (!res) { + std::println("Cannot load environment: {}", p_filename); } - // ~environment_map() { - // destroy(); - // } - - void create_hdr_skybox( - const std::filesystem::path& p_filename, - VkPhysicalDeviceMemoryProperties p_memory_properties) { - - stbi_set_flip_vertically_on_load(true); - int w, h, channels; - float* pixels = stbi_loadf( - p_filename.string().c_str(), &w, &h, &channels, STBI_rgb_alpha); - - if (!pixels) { - throw std::runtime_error("Failed to load HDR image at: " + - p_filename.string()); - } - - const uint32_t width = static_cast(w); - const uint32_t height = static_cast(h); - - VkFormat texture_format = VK_FORMAT_R32G32B32A32_SFLOAT; - const uint64_t bytes_per_pixel_channel = 16; // float are 4 bytes - const uint64_t total_size_bytes = - static_cast(width * height * bytes_per_pixel_channel); - const uint64_t image_size = total_size_bytes; - - // Creating staging buffer - uint32_t property_flag = vk::memory_property::host_visible_bit | - vk::memory_property::host_cached_bit; - vk::buffer_parameters staging_buffer_params = { - .device_size = static_cast(image_size), - .physical_memory_properties = p_memory_properties, - .property_flags = - static_cast(property_flag), - .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - }; - - vk::buffer_stream staging_buffer = - vk::buffer_stream(m_device, staging_buffer_params); - - // Creating image handle to storing the HDR - vk::image_params skybox_image_params = { - .extent = { .width = width, .height = height, }, - .format = texture_format, - .property = vk::memory_property::device_local_bit, - .aspect = vk::image_aspect_flags::color_bit, - .usage = vk::image_usage::transfer_dst_bit | - vk::image_usage::sampled_bit, - .phsyical_memory_properties = p_memory_properties, - }; - m_skybox_image = vk::sample_image(m_device, skybox_image_params); - - // Transferring data from the CPU - // void* data = nullptr; - // vkMapMemory(m_device, staging_memory, 0, total_size_bytes, 0, - // &data); std::memcpy(data, pixels, - // static_cast(total_size_bytes)); vkUnmapMemory(m_device, - // staging_memory); - std::span pixels_data( - reinterpret_cast(pixels), image_size); - staging_buffer.write(pixels_data); - - // Free CPU pixels immediately after staging copy - stbi_image_free(pixels); - - // 6. Record and Execute Upload - vk::command_params upload_params = { - .levels = vk::command_levels::primary, - .queue_index = 0, // Graphics Queue - .flags = vk::command_pool_flags::reset, - }; - vk::command_buffer upload_cmd(m_device, upload_params); - - upload_cmd.begin(vk::command_usage::one_time_submit); - - // Begin Memory Barrier: Undefined to TRANSFER_DST - m_skybox_image.memory_barrier(upload_cmd, - texture_format, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - staging_buffer.copy_to_image( - upload_cmd, m_skybox_image, skybox_image_params.extent); - - // Begin Memory Barrier: TRANSFER_DST to SHADER_READ_ONLY - m_skybox_image.memory_barrier( - upload_cmd, - texture_format, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - upload_cmd.end(); - - VkQueue graphics_queue; - vkGetDeviceQueue(m_device, 0, 0, &graphics_queue); - - VkCommandBuffer raw_cmd = upload_cmd; - VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = 1, - .pCommandBuffers = &raw_cmd, - }; - - vkQueueSubmit(graphics_queue, 1, &submit_info, nullptr); - vkQueueWaitIdle(graphics_queue); - - upload_cmd.destroy(); - staging_buffer.destroy(); - stbi_set_flip_vertically_on_load(false); + if (res) { + std::println("Loaded succesfully: {}", p_filename); } - - void create_buffers() { - std::vector skyboxVertices = { - // positions - -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, - - 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, - - -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, - - -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f - }; - // m_physical = instance_context::physical_driver(); - // m_device = instance_context::logical_device(); - - // std::vector vertices = { - // vk::vertex_input{ - // .position = {-1.0f, 1.0f, -1.0f,} - // }, - // }; - std::vector vertices = { - // Front Face - vk::vertex_input{ { -1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - - // Left Face - vk::vertex_input{ { -1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - - // Right Face - vk::vertex_input{ { 1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - - // Back Face - vk::vertex_input{ { -1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - - // Top Face - vk::vertex_input{ { -1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, 1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - - // Bottom Face - vk::vertex_input{ { -1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, -1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { -1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }, - vk::vertex_input{ { 1.0f, -1.0f, 1.0f }, - { 1.0f, 1.0f, 1.0f }, - { 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } } - }; - // for (size_t i = 0; i < skyboxVertices.size(); i += 3) { - // vk::vertex_input v{}; - - // // Assign position from the float array - // v.position = glm::vec3( - // vertices[i], - // vertices[i + 1], - // vertices[i + 2] - // ); - - // // Default values for the remaining fields - // v.color = glm::vec3(1.0f); // Default white - // v.normals = glm::vec3(0.0f); // Or calculate if needed - // v.uv = glm::vec2(0.0f); - - // vertices.push_back(v); - // } - vk::vertex_params vbo_params = { - .phsyical_memory_properties = - vulkan::instance_context::physical_driver() - .memory_properties(), - .vertices = vertices - }; - - m_skybox_vbo = vk::vertex_buffer(m_device, vbo_params); + create_pipelines(); + } + + /** + * @brief loads in raw pixels and texture dimensions to receive in raw + * pixels data if no HDRI is provided. + */ + void construct(std::span p_color, + const vk::image_extent& p_extent) { + bool res = create_hdr(p_color, p_extent); + + if (!res) { + std::println("Cannot load environment"); } - void create_skybox_pipeline( - VkPhysicalDeviceMemoryProperties p_memory_properties, - const VkRenderPass& p_renderpass) { - create_buffers(); - std::array attribute_entries = { - vk::vertex_attribute_entry{ - .location = 0, - .format = vk::format::rgb32_sfloat, - .stride = offsetof(vk::vertex_input, position), - }, - vk::vertex_attribute_entry{ - .location = 1, - .format = vk::format::rgb32_sfloat, - .stride = offsetof(vk::vertex_input, color), - }, - vk::vertex_attribute_entry{ - .location = 2, - .format = vk::format::rgb32_sfloat, - .stride = offsetof(vk::vertex_input, normals), - }, - vk::vertex_attribute_entry{ - .location = 3, - .format = vk::format::rg32_sfloat, - .stride = offsetof(vk::vertex_input, uv), - } - }; - std::array attribute = { - vk::vertex_attribute{ - // layout (set = 0, binding = 0) - .binding = 0, - .entries = attribute_entries, - .stride = sizeof(vk::vertex_input), - .input_rate = vk::input_rate::vertex, - }, - }; + if (res) { + std::println("Loaded succesfully raw pixels successfully"); + } + create_pipelines(); + } + + /** + * @brief performs the loading operation to read in the pixel float data of + * the actual HDRI metadata. + */ + bool create_hdr(const std::string& p_filename) { + stbi_set_flip_vertically_on_load(true); + int w, h, channels; + float* pixels = + stbi_loadf(p_filename.c_str(), &w, &h, &channels, STBI_rgb_alpha); + + if (!pixels) { + return false; + } - const std::array sources = { - vk::shader_source{ - .filename = "builtin.shaders/skybox/skybox.vert.spv", - .stage = vk::shader_stage::vertex, - }, - vk::shader_source{ - .filename = "builtin.shaders/skybox/skybox.frag.spv", - .stage = vk::shader_stage::fragment, - }, - }; - - vk::shader_resource_info shader_info = { - .sources = sources, - }; - m_skybox_shaders = vk::shader_resource(m_device, shader_info); - m_skybox_shaders.vertex_attributes(attribute); - - // set=0 binding=0 UBO: mat4 VP - vk::uniform_params ubo_params = { - .phsyical_memory_properties = p_memory_properties, - .size_bytes = sizeof(skybox_uniform), - .debug_name = "skybox_ubo", - .vkSetDebugUtilsObjectNameEXT = nullptr, - }; - m_skybox_ubo = vk::uniform_buffer(m_device, ubo_params); - // vk::uniform_buffer(m_device, sizeof(skybox_uniform), ubo_params); - - skybox_uniform identity = { .proj_view = glm::mat4(1.0f) }; - identity.proj_view[1][1] *= -1; - // m_skybox_ubo.write(std::span(&identity, - // 1)); - m_skybox_ubo.update(&identity); - - // set=0 bindings: - // - binding 0: UBO (vertex) - // - binding 1: samplerCube (fragment) - std::array entries = { - vk::descriptor_entry{ - .type = vk::buffer::uniform, - .binding_point = - vk::descriptor_binding_point{ - .binding = 0, .stage = vk::shader_stage::vertex }, - .descriptor_count = 1, - }, - vk::descriptor_entry{ - .type = vk::buffer::combined_image_sampler, - .binding_point = - vk::descriptor_binding_point{ - .binding = 1, .stage = vk::shader_stage::fragment }, - .descriptor_count = 1, - }, - }; - - vk::descriptor_layout desc_layout = { - .slot = 0, - .max_sets = 1, - .entries = entries, - }; - m_skybox_descriptors = - vk::descriptor_resource(m_device, desc_layout); - - const std::array ubo_writes = { - vk::write_buffer{ - .buffer = static_cast(m_skybox_ubo), - .offset = 0, - .range = static_cast(sizeof(skybox_uniform)) }, - }; - const vk::write_buffer_descriptor ubo_write_desc = { - .dst_binding = 0, - .uniforms = ubo_writes, - }; - - const std::array image_writes = { - vk::write_image{ - .sampler = m_skybox_image.sampler(), - .view = m_skybox_image.image_view(), - .layout = vk::image_layout::shader_read_only_optimal, + const uint64_t width = static_cast(w); + const uint64_t height = static_cast(h); + + VkFormat texture_format = VK_FORMAT_R32G32B32A32_SFLOAT; + const uint64_t bytes_per_pixel_channel = 16; // float are 4 bytes + const uint64_t total_size_bytes = + static_cast(width * height * bytes_per_pixel_channel); + const uint64_t image_size = total_size_bytes; + + vk::buffer_parameters staging_params = { + .memory_mask = m_memory_mask, + .usage = vk::buffer_usage::transfer_src_bit, + }; + + vk::buffer staging_buffer = + vk::buffer(*m_device, image_size, staging_params); + + // Creating GPU image resource + vk::image_params skybox_params = { + .extent = { .width = static_cast(width), .height = static_cast(height), }, + .format = texture_format, + .memory_mask = m_memory_mask, + // .property = vk::memory_property::device_local_bit, + .aspect = vk::image_aspect_flags::color_bit, + .usage = vk::image_usage::transfer_dst_bit | + vk::image_usage::sampled_bit, + .address_mode_u = vk::sampler_address_mode::repeat, + .addrses_mode_v = vk::sampler_address_mode::clamp_to_edge, + // .view_type = VK_IMAGE_VIEW_TYPE_CUBE, + }; + m_skybox_image = vk::sample_image(*m_device, skybox_params); + + // Transferring CPU data to GPU-visible data + std::span pixels_data( + reinterpret_cast(pixels), image_size); + staging_buffer.transfer(pixels_data); + + // Free CPU pixels immediately after staging copy + stbi_image_free(pixels); + + // 6. Record and Execute Upload + vk::command_params upload_params = { + .levels = vk::command_levels::primary, + .queue_index = 0, // Graphics Queue + .flags = vk::command_pool_flags::reset, + }; + vk::command_buffer upload_cmd(*m_device, upload_params); + + upload_cmd.begin(vk::command_usage::one_time_submit); + + // Performing image layout transitions to ensure we do not lose any data + // transferring over to the GPU. Begin Memory Barrier: Undefined to + // TRANSFER_DST + m_skybox_image.memory_barrier(upload_cmd, + texture_format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vk::buffer_image_copy image_copy{ + .image_offset = { .width = 0, .height = 0, .depth = 0, }, + .image_extent = skybox_params.extent, + }; + staging_buffer.copy_to_image( + upload_cmd, + m_skybox_image, + std::span(&image_copy, 1)); + + // Begin Memory Barrier: TRANSFER_DST to SHADER_READ_ONLY + m_skybox_image.memory_barrier(upload_cmd, + texture_format, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + upload_cmd.end(); + + VkQueue graphics_queue; + vkGetDeviceQueue(*m_device, 0, 0, &graphics_queue); + + VkCommandBuffer raw_cmd = upload_cmd; + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &raw_cmd, + }; + + vkQueueSubmit(graphics_queue, 1, &submit_info, nullptr); + vkQueueWaitIdle(graphics_queue); + + upload_cmd.destruct(); + staging_buffer.destruct(); + stbi_set_flip_vertically_on_load(false); + + return true; + } + + bool create_hdr(std::span p_colors, + const vk::image_extent& p_extent) { + + VkFormat texture_format = VK_FORMAT_R32G32B32A32_SFLOAT; + const uint64_t bytes_per_pixel_channel = 16; // float are 4 bytes + const uint64_t total_size_bytes = + static_cast(static_cast(p_extent.width) * + p_extent.height * bytes_per_pixel_channel); + const uint64_t image_size = total_size_bytes; + + vk::buffer_parameters staging_params = { + .memory_mask = m_memory_mask, + .usage = vk::buffer_usage::transfer_src_bit, + }; + + vk::buffer staging_buffer = + vk::buffer(*m_device, image_size, staging_params); + + // Creating image handle to storing the HDR + vk::image_params skybox_params = { + .extent = { .width = static_cast(p_extent.width), .height = static_cast(p_extent.height), }, + .format = texture_format, + .memory_mask = m_memory_mask, + // .property = vk::memory_property::device_local_bit, + .aspect = vk::image_aspect_flags::color_bit, + .usage = vk::image_usage::transfer_dst_bit | + vk::image_usage::sampled_bit, + // .view_type = VK_IMAGE_VIEW_TYPE_CUBE, + }; + m_skybox_image = vk::sample_image(*m_device, skybox_params); + + // Transferring data from the CPU + std::span pixels_data( + reinterpret_cast(p_colors.data()), image_size); + staging_buffer.transfer(pixels_data); + + // 6. Record and Execute Upload + vk::command_params upload_params = { + .levels = vk::command_levels::primary, + .queue_index = 0, // Graphics Queue + .flags = vk::command_pool_flags::reset, + }; + vk::command_buffer upload_cmd(*m_device, upload_params); + + upload_cmd.begin(vk::command_usage::one_time_submit); + + // Begin Memory Barrier: Undefined to TRANSFER_DST + m_skybox_image.memory_barrier(upload_cmd, + texture_format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vk::buffer_image_copy image_copy{ + .image_offset = { .width = 0, .height = 0, .depth = 0, }, + .image_extent = skybox_params.extent, + }; + staging_buffer.copy_to_image( + upload_cmd, + m_skybox_image, + std::span(&image_copy, 1)); + + // Begin Memory Barrier: TRANSFER_DST to SHADER_READ_ONLY + m_skybox_image.memory_barrier(upload_cmd, + texture_format, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + upload_cmd.end(); + + VkQueue graphics_queue; + vkGetDeviceQueue(*m_device, 0, 0, &graphics_queue); + + VkCommandBuffer raw_cmd = upload_cmd; + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &raw_cmd, + }; + + vkQueueSubmit(graphics_queue, 1, &submit_info, nullptr); + vkQueueWaitIdle(graphics_queue); + + upload_cmd.destruct(); + staging_buffer.destruct(); + + return true; + } + + void create_buffers() { + std::vector vertices = { + // Front Face + vk::vertex_input{ + .position = { -1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + + // Left Face + vk::vertex_input{ + .position = { -1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position{ -1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + + // Right Face + vk::vertex_input{ + .position = { 1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + + // Back Face + vk::vertex_input{ + .position = { -1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + + // Top Face + vk::vertex_input{ + .position = { -1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, 1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + + // Bottom Face + vk::vertex_input{ + .position = { -1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, -1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { -1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + }, + vk::vertex_input{ + .position = { 1.0f, -1.0f, 1.0f }, + .color = { 1.0f, 1.0f, 1.0f }, + .normals = { 0.0f, 0.0f, 0.0f }, + .uv = { 0.0f, 0.0f }, + } + }; + + m_vertices_size = vertices.size(); + + vk::buffer_parameters vertex_params = { + // .memory_mask = p_physical.memory_properties( + // vk::memory_property::device_local_bit | + // vk::memory_property::host_visible_bit), + .memory_mask = m_memory_mask, + .usage = vk::buffer_usage::transfer_dst_bit | + vk::buffer_usage::vertex_buffer_bit, + }; + + m_skybox_vbo = vk::vertex_buffer(*m_device, vertices, vertex_params); + } + + void create_pipelines() { + create_buffers(); + std::array attribute_entries = { + vk::vertex_attribute_entry{ + .location = 0, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, position), + }, + vk::vertex_attribute_entry{ + .location = 1, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, color), + }, + vk::vertex_attribute_entry{ + .location = 2, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, normals), + }, + vk::vertex_attribute_entry{ + .location = 3, + .format = vk::format::rg32_sfloat, + .stride = offsetof(vk::vertex_input, uv), + } + }; + std::array attribute = { + vk::vertex_attribute{ + // layout (set = 0, binding = 0) + .binding = 0, + .entries = attribute_entries, + .stride = sizeof(vk::vertex_input), + .input_rate = vk::input_rate::vertex, + }, + }; + + const std::array sources = { + vk::shader_source{ + .filename = "builtin.shaders/skybox/skybox.vert.spv", + .stage = vk::shader_stage::vertex, + }, + vk::shader_source{ + .filename = "builtin.shaders/skybox/skybox.frag.spv", + .stage = vk::shader_stage::fragment, + }, + }; + + vk::shader_resource_info shader_info = { + .sources = sources, + }; + m_skybox_shaders = vk::shader_resource(*m_device, shader_info); + m_skybox_shaders.vertex_attributes(attribute); + + // Specifying descriptors + + std::array entries = { + vk::descriptor_entry{ + // layout (set = 0, binding = 1) uniform sampler2D textures[]; + .type = vk::descriptor_type::combined_image_sampler, + .binding_point = { + .binding = 1, + .stage = vk::shader_stage::fragment, }, - }; - const vk::write_image_descriptor image_write_desc = { - .dst_binding = 1, - .sample_images = image_writes, - }; - - m_skybox_descriptors.update(std::span(&ubo_write_desc, 1), - std::span(&image_write_desc, 1)); - - const std::array layouts = { - m_skybox_descriptors.layout(), - }; - - const std::array - blend_attachments = { - vk::color_blend_attachment_state{ .blend_enabled = false }, - }; - vk::color_blend_state blend_state = { - .logic_op_enable = false, - .logical_op = vk::logical_op::copy, - .attachments = blend_attachments, - .blend_constants = {}, - }; - - std::array dyn = { - vk::dynamic_state::viewport, - vk::dynamic_state::scissor, - }; - - // pipeline expects a non-const span - std::array pipeline_layouts = layouts; - - vk::pipeline_params pipe_info = { - .renderpass = p_renderpass, + .descriptor_count = 1, + .flags = vk::descriptor_bind_flags::partially_bound_bit | + vk::descriptor_bind_flags::update_after_bind, + }, + }; + + // layout(set = 0, ...) + uint32_t max_descriptors = 1; + vk::descriptor_layout set0_layout = { + .slot = 0, + .max_sets = 1, + .entries = entries, // descriptor layout entries description + .descriptor_counts = std::span(&max_descriptors, 1), + }; + m_skybox_descriptor = vk::descriptor_resource( + *m_device, + set0_layout, + vk::descriptor_layout_flags::update_after_bind_pool); + + // specifying push constant for pipelines + std::array + color_blend_attachments = { + vk::color_blend_attachment_state{}, + }; + + std::array dynamic_states = { + vk::dynamic_state::viewport, + vk::dynamic_state::scissor, + }; + + uint32_t vertex_mask = static_cast(vk::shader_stage::vertex); + uint32_t fragment_mask = + static_cast(vk::shader_stage::fragment); + uint32_t stage_mask = vertex_mask | fragment_mask; + m_stage = static_cast(stage_mask); + vk::push_constant_range range = { + .stage = m_stage, + .offset = 0, + .range = sizeof(environment_push_constant), + }; + + VkDescriptorSetLayout descriptor0_layout = m_skybox_descriptor.layout(); + uint32_t color_format = static_cast(m_color_format); + vk::pipeline_params skybox_pipeline_params = { + .use_render_pipeline = true, + .color_attachment_formats = std::span(&color_format, 1), + .depth_format = static_cast(m_depth_format), + .stencil_format = static_cast(m_depth_format), + .renderpass = nullptr, .shader_modules = m_skybox_shaders.handles(), - .vertex_attributes = - m_skybox_shaders.vertex_attributes(), // no vertex input - .vertex_bind_attributes = - m_skybox_shaders.vertex_bind_attributes(), // no vertex input - .descriptor_layouts = pipeline_layouts, - .input_assembly = - vk::input_assembly_state{ - .topology = vk::primitive_topology::triangle_list, - .primitive_restart_enable = false, - }, - .viewport = - vk::viewport_state{ .viewport_count = 1, .scissor_count = 1 }, - .rasterization = - vk::rasterization_state{ - .polygon_mode = vk::polygon_mode::fill, - .cull_mode = vk::cull_mode::front_bit, - // .cull_mode = vk::cull_mode::none, - // .front_face = vk::front_face::counter_clockwise, - .front_face = vk::front_face::clockwise, - .line_width = 1.f, - }, - .multisample = vk::multisample_state{}, - .color_blend = blend_state, + .vertex_attributes = m_skybox_shaders.vertex_attributes(), + .vertex_bind_attributes = m_skybox_shaders.vertex_bind_attributes(), + .descriptor_layouts = std::span(&descriptor0_layout, 1), + .color_blend = { + .attachments = color_blend_attachments, + }, .depth_stencil_enabled = true, - .depth_stencil = - vk::depth_stencil_state{ + .depth_stencil = { .depth_test_enable = true, .depth_write_enable = false, .depth_compare_op = vk::compare_op::less_or_equal, .depth_bounds_test_enable = false, .stencil_test_enable = false, - }, - .dynamic_states = dyn, - }; - - m_skybox_pipeline = vk::pipeline(m_device, pipe_info); - } - - void update_uniform(const skybox_uniform& p_ubo) { - // m_skybox_ubo.transfer(std::span(&p_ubo, - // 1)); - m_skybox_ubo.update(&p_ubo); - } - - void bind(const VkCommandBuffer& p_current) { - m_skybox_pipeline.bind(p_current); - m_skybox_descriptors.bind(p_current, m_skybox_pipeline.layout()); - m_skybox_vbo.bind(p_current); - } - - void draw(const VkCommandBuffer& p_current) { - // bind(p_current); - vkCmdDraw(p_current, m_skybox_vbo.size(), 1, 0, 0); - // vkCmdDrawIndexed(p_current, 36, 1, 0, 0, 0); - } - - //! @brief Retreving the sample image of the environment map. - [[nodiscard]] vk::sample_image image() const { return m_skybox_image; } - - void destroy() { - - m_skybox_image.destroy(); - if (m_skybox_pipeline.alive()) { - m_skybox_pipeline.destroy(); - } - m_skybox_descriptors.destroy(); - m_skybox_ubo.destroy(); - m_skybox_shaders.destroy(); - m_skybox_vbo.destroy(); - } - - //! TODO: Logic for converting the HDR image handles to a skybox - //! samplerCube - void process_to_cubemap() {} - - private: - VkDevice m_device = nullptr; - - vk::sample_image m_skybox_image; - - vk::shader_resource m_skybox_shaders{}; - vk::uniform_buffer m_skybox_ubo{}; - vk::descriptor_resource m_skybox_descriptors{}; - vk::pipeline m_skybox_pipeline{}; - vk::vertex_buffer m_skybox_vbo; - }; - + }, + .dynamic_states = dynamic_states, + .push_constants = std::span(&range, 1), + }; + m_skybox_pipeline = vk::pipeline(*m_device, skybox_pipeline_params); + + vk::buffer_parameters uniform_params = { + .memory_mask = m_physical->memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), + .usage = vk::buffer_usage::uniform_buffer_bit | + vk::buffer_usage::shader_device_address_bit, + .allocate_flags = vk::memory_allocate_flags::device_address_bit_khr, + }; + + m_skybox_uniforms = vk::dyn::buffer( + *m_device, sizeof(environment_uniforms), uniform_params); + + vk::write_image environment_image = { + .sampler = m_skybox_image.sampler(), + .view = m_skybox_image.image_view(), + .layout = vk::image_layout::shader_read_only_optimal, + }; + std::array write_descriptors = { + // layout(set = 0, binding = 1) sampler2D environment; + vk::write_image_descriptor{ + .dst_binding = 1, + .sample_images = + std::span(&environment_image, 1), + }, + }; + + m_skybox_descriptor.update({}, write_descriptors); + } + + void set_current_command(vk::command_buffer& p_current) { + m_current_command = &p_current; + } + + void begin(const glm::mat4& p_proj, const glm::mat4& p_view) { + m_proj_view = p_proj * glm::mat4(glm::mat3(p_view)); + + m_skybox_pipeline.bind(*m_current_command); + environment_uniforms scene_ubo = { + .proj_view = m_proj_view, + }; + + m_skybox_uniforms.transfer( + std::span(&scene_ubo, 1)); + + const VkDescriptorSet skybox_descriptor = m_skybox_descriptor; + m_current_command->bind_descriptors( + m_skybox_pipeline.layout(), + VK_PIPELINE_BIND_POINT_GRAPHICS, + std::span(&skybox_descriptor, 1)); + } + + void end() { + const uint64_t scene_environment = + m_skybox_uniforms.get_device_address(); + + environment_push_constant environment_push_const = { + .scene_environment_address = scene_environment, + }; + + m_skybox_pipeline.push_constant( + *m_current_command, environment_push_const, m_stage, 0); + + // Binding our vertex buffers here + const VkBuffer& skybox_vertex = m_skybox_vbo; + uint64_t offset = 0; + m_current_command->bind_vertex_buffers( + std::span(&skybox_vertex, 1), + std::span(&offset, 1)); + + vkCmdDraw(*m_current_command, m_vertices_size, 1, 0, 0); + } + + [[nodiscard]] VkImageView image_view() const { + return m_skybox_image.image_view(); + } + + [[nodiscard]] VkSampler sampler() const { return m_skybox_image.sampler(); } + + void destruct() { + m_skybox_vbo.destruct(); + m_skybox_image.destruct(); + m_skybox_descriptor.destruct(); + m_skybox_shaders.destruct(); + m_skybox_pipeline.destruct(); + m_skybox_uniforms.reset(); + } + +private: + glm::mat4 m_proj_view; + vk::command_buffer* m_current_command; + uint64_t m_vertices_size = 0; + std::shared_ptr m_device; + std::optional m_physical; + vk::vertex_buffer m_skybox_vbo; + vk::sample_image m_skybox_image; + uint32_t m_memory_mask; + vk::shader_stage m_stage; + + VkFormat m_color_format; + VkFormat m_depth_format; + vk::dyn::buffer m_skybox_uniforms; + vk::descriptor_resource m_skybox_descriptor; + vk::shader_resource m_skybox_shaders; + vk::pipeline m_skybox_pipeline; }; \ No newline at end of file diff --git a/atlas/drivers/vulkan/gpu_uniforms.cppm b/atlas/drivers/vulkan/gpu_uniforms.cppm new file mode 100644 index 00000000..5677a7d2 --- /dev/null +++ b/atlas/drivers/vulkan/gpu_uniforms.cppm @@ -0,0 +1,83 @@ +module; + +#include + +#define GLM_FORCE_RADIANS +#include +#include +#define GLM_ENABLE_EXPERIMENTAL +#include + +export module atlas.drivers.vulkan:gpu_uniforms; + +import vk; + +export namespace atlas { + struct gpu_mesh_data { + vk::vertex_buffer vertex; + vk::index_buffer index; + uint32_t index_count = 0; + uint32_t instance = 1; + uint32_t first_index = 0; + uint32_t vertex_offset = 0; + uint32_t first_instance = 0; + bool has_indices_buffer = false; + uint32_t vertices_size = 0; + uint32_t indices_size = 0; + }; + + struct push_constant_data { + uint64_t scene_address = 0; + uint64_t model_mat_array_address = 0; + uint32_t model_idx = 0; + uint32_t diffuse_idx = 0; + uint32_t specular_idx = 0; + uint64_t point_light_address; + }; + + struct scene_uniforms { + glm::mat4 view = glm::mat4(1.f); + glm::mat4 proj = glm::mat4(1.f); + glm::vec4 camera_pos = glm::vec4(1.f); + }; + + struct objects_uniform { + std::span model_matrices; + }; + + struct gpu_material { + uint64_t diffuse_idx = 0; + uint64_t specular_idx = 0; + }; + + struct gpu_point_light { + glm::vec4 position; // this is provided by the transform + glm::vec4 color = { 1.f, 1.f, 1.f, 1.f }; + float attenuation = 1.f; + float constant = 1.f; + float linear = 1.f; + float quadratic = 1.f; + + glm::vec4 ambient = glm::vec4(1.f); + glm::vec4 diffuse = glm::vec4(1.f); + glm::vec4 specular = glm::vec4(1.f); + }; + + struct light_scene_ubo { + alignas(16) uint32_t num_lights = 0; + alignas(16) std::array point_lights{}; + }; + + /** + * + * @brief slot is the index into the texture array to retrieve this specific + * texture data + * + * vk::texture is the texture data to configure the GPU-visible image + * resource + */ + struct gpu_image { + uint64_t slot = 0; + vk::texture texture_data; + }; +}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/graphics_context.cppm b/atlas/drivers/vulkan/graphics_context.cppm new file mode 100644 index 00000000..9f9e7242 --- /dev/null +++ b/atlas/drivers/vulkan/graphics_context.cppm @@ -0,0 +1,65 @@ +module; + +#include +#include +#include +#include + +#include + +#define GLFW_INCLUDE_VULKAN +#if _WIN32 +#define VK_USE_PLATFORM_WIN32_KHR +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include +#else +#include +#include +#endif + +export module atlas.drivers.vulkan:graphics_context; + +import vk; + +export namespace atlas { + + /** + * @brief graphics context to manage core resources that is used as the + * primary resource access to the core Vulkan handles. + */ + class graphics_context { + public: + graphics_context() = default; + graphics_context(const vk::instance& p_api_instance, + vk::physical_device& p_physical, + std::shared_ptr p_device) + : m_api_instance(p_api_instance) + , m_physical(&p_physical) + , m_device(/*NOLINT*/ p_device) { + // Constructing the graphics context + } + + ~graphics_context() = default; + + //! @return vk::instance + [[nodiscard]] vk::instance instance_handle() const { + return m_api_instance; + } + + //! @return vk::physical_device + [[nodiscard]] vk::physical_device physical_device() const { + return *m_physical; + } + + //! @return shared_ptr + std::shared_ptr logical_device() { return m_device; } + + private: + vk::instance m_api_instance; + vk::physical_device* m_physical = nullptr; + std::shared_ptr m_device = nullptr; + std::deque> m_submit_resource_free{}; + }; +}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/imgui_context.cppm b/atlas/drivers/vulkan/imgui_context.cppm index d533fefa..5a167309 100644 --- a/atlas/drivers/vulkan/imgui_context.cppm +++ b/atlas/drivers/vulkan/imgui_context.cppm @@ -8,20 +8,24 @@ module; #include #include #include +#include +#include +#include +#include +#include +#include + +export module atlas.drivers.vulkan:imgui_context; -export module atlas.drivers.vulkan.imgui_context; +import :graphics_context; -import atlas.common; +import atlas.core.utilities; import vk; -import atlas.drivers.vulkan.instance_context; -import atlas.drivers.vulkan.physical_device; -import atlas.drivers.vulkan.device; -import atlas.drivers.vulkan.swapchain; import atlas.core.utilities; -namespace atlas::vulkan { - static void im_gui_layout_color_modification() { +namespace atlas { + void imgui_layout_color_modification() { auto& colors = ImGui::GetStyle().Colors; // @note Colors is ImVec4 colors[ImGuiCol_WindowBg] = ImVec4{ 0.1f, 0.105f, 0.11f, 1.0f }; @@ -56,6 +60,24 @@ namespace atlas::vulkan { ImVec4{ 0.1f, 0.150f, 0.951f, 1.0f }; } + VkPipelineRenderingCreateInfo pipeline_rendering_info( + std::span p_color_attachment_formats, + const uint32_t p_depth_format, + const uint32_t p_stencil_format) { + VkPipelineRenderingCreateInfo rendering_ci = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, + .pNext = nullptr, + .colorAttachmentCount = + static_cast(p_color_attachment_formats.size()), + .pColorAttachmentFormats = reinterpret_cast( + p_color_attachment_formats.data()), + .depthAttachmentFormat = static_cast(p_depth_format), + .stencilAttachmentFormat = static_cast(p_stencil_format), + }; + + return rendering_ci; + } + void transition_image_layout(VkDevice p_device, vk::sample_image& p_image, VkFormat p_format, @@ -91,32 +113,60 @@ namespace atlas::vulkan { vkQueueSubmit(temp_graphics_queue, 1, &submit_info, nullptr); vkQueueWaitIdle(temp_graphics_queue); - temp_command_buffer.destroy(); + temp_command_buffer.destruct(); } - export ImTextureID g_viewport_image_id = nullptr; + /** + * @brief Represents the context for rendering the UI-specific properties + * + * This context is responsible to perform any configurations and rerouting + * of the underlying UI logic. + */ + export VkDescriptorSet g_viewport_image_id = nullptr; export class imgui_context { public: - imgui_context() = default; - - imgui_context(const VkInstance& p_instance, - const swapchain& p_swapchain_ctx, - GLFWwindow* p_window_ctx) { - m_instance = p_instance; - m_physical = instance_context::physical_driver(); - VkPhysicalDeviceMemoryProperties memory_properties = - instance_context::physical_driver().memory_properties(); - m_driver = instance_context::logical_device(); - // vk::device device_temp = instance_context::physical_driver(); - - m_current_swapchain_handler = p_swapchain_ctx; - m_extent = { .width = p_swapchain_ctx.settings().width, - .height = p_swapchain_ctx.settings().height }; - - // Setting up imgui + imgui_context() = delete; + imgui_context(/*NOLINT*/ std::shared_ptr p_context, + GLFWwindow* p_window, + /*NOLINT*/ std::shared_ptr, + uint32_t p_image_count, + const vk::device_present_queue& p_queue, + /*NOLINT*/ const VkFormat& p_color_format, + /*NOLINT*/ const VkFormat& p_depth_format, + const window_params& p_params) + : m_params(p_params) { + m_instance = p_context->instance_handle(); + m_device = p_context->logical_device(); + m_physical = p_context->physical_device(); + std::println("Constructing imgui_context"); + + m_color_format = p_color_format; + m_depth_format = p_depth_format; + + // Common setup for imgui IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = nullptr; + + std::filesystem::path path = + std::filesystem::current_path() / "imgui.ini"; + + std::string data_source = ""; + if (std::filesystem::exists(path)) { + std::ifstream file(path.string()); + + if (!file) { + std::println("Cannot load {}", path.string()); + } + + std::stringstream ss; + ss << file.rdbuf(); + data_source = ss.str(); + } + + ImGui::LoadIniSettingsFromMemory(data_source.c_str(), + data_source.size()); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls @@ -127,14 +177,8 @@ namespace atlas::vulkan { ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / // Platform Windows - // io.ConfigViewportsNoAutoMerge = true; - // io.ConfigViewportsNoAutoMerge = true; - // io.ConfigViewportsNoTaskBarIcon = true; - - // Setup Dear ImGui style - // ImGui::StyleColorsDark(); - // ImGui::StyleColorsClassic(); - im_gui_layout_color_modification(); + // Additional configurations + imgui_layout_color_modification(); ImGuiStyle& style = ImGui::GetStyle(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { @@ -142,25 +186,7 @@ namespace atlas::vulkan { style.Colors[ImGuiCol_WindowBg].w = 1.0f; } - m_viewport_command_buffers.resize(p_swapchain_ctx.image_size()); - - for (size_t i = 0; i < m_viewport_command_buffers.size(); i++) { - ::vk::command_params settings = { - .levels = ::vk::command_levels::primary, - // .queue_index = - // enumerate_swapchain_settings.present_index, - .queue_index = 0, - .flags = ::vk::command_pool_flags::reset, - }; - m_viewport_command_buffers[i] = - ::vk::command_buffer(m_driver, settings); - } - - // ::vk::descriptor_res - // m_imgui_descriptor = ::vk::descriptor_resource(m_driver, {}); - // 1: create descriptor pool for IMGUI - // the size of the pool is very oversize, but it's copied from - // imgui demo itself. + // Configurnig descriptor pool std::array pool_sizes = { VkDescriptorPoolSize{ VK_DESCRIPTOR_TYPE_SAMPLER, 100 }, VkDescriptorPoolSize{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, @@ -193,283 +219,180 @@ namespace atlas::vulkan { // VkDescriptorPool imgui_pool; vk::vk_check( vkCreateDescriptorPool( - m_driver, &desc_pool_create_info, nullptr, &m_desc_pool), + *m_device, &desc_pool_create_info, nullptr, &m_descriptor_pool), "vkCreateDescriptorPool"); - create(p_window_ctx, - p_swapchain_ctx.image_size(), - p_swapchain_ctx.swapchain_renderpass()); - - vk::image_params config_image = { - .extent = { .width = p_swapchain_ctx.settings().width, - .height = p_swapchain_ctx.settings().height }, - .format = VK_FORMAT_B8G8R8A8_UNORM, - .property = vk::memory_property::device_local_bit, + // Creating viewport image + vk::image_params viewport_params = { + .extent = { .width = m_params.width, + .height = m_params.height }, + // .format = VK_FORMAT_B8G8R8A8_UNORM, + .format = m_color_format, + // .property = vk::memory_property::device_local_bit, + .memory_mask = m_physical->memory_properties( + vk::memory_property::device_local_bit), .aspect = vk::image_aspect_flags::color_bit, .usage = vk::image_usage::color_attachment_bit | vk::image_usage::transfer_dst_bit | vk::image_usage::sampled_bit, - // .usage = vk::image_usage::color_attachment_bit | - // vk::image_usage::transfer_dst_bit, - .phsyical_memory_properties = memory_properties, .address_mode_u = vk::sampler_address_mode::clamp_to_edge, .addrses_mode_v = vk::sampler_address_mode::clamp_to_edge, .addrses_mode_w = vk::sampler_address_mode::clamp_to_edge, }; - m_viewport_image = vk::sample_image(m_driver, config_image); - // transition image layout uses image memory barrier - transition_image_layout(m_driver, + m_viewport_image = vk::sample_image(*m_device, viewport_params); + + std::println("before transition image layout"); + transition_image_layout(*m_device, m_viewport_image, - VK_FORMAT_B8G8R8A8_UNORM, + m_color_format, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - // Viewport-specific render pass: color attachment ends in - // SHADER_READ_ONLY_OPTIMAL so the offscreen texture can be sampled - // by ImGui. (Swapchain pass uses PRESENT_SRC.) - VkFormat depth_format = m_driver.depth_format(); - std::array<::vk::attachment, 2> viewport_attachments = { - ::vk::attachment{ - .format = VK_FORMAT_B8G8R8A8_UNORM, - .layout = ::vk::image_layout::color_optimal, - .samples = ::vk::sample_bit::count_1, - .load = ::vk::attachment_load::clear, - .store = ::vk::attachment_store::store, - .stencil_load = ::vk::attachment_load::clear, - .stencil_store = ::vk::attachment_store::dont_care, - .initial_layout = ::vk::image_layout::undefined, - .final_layout = ::vk::image_layout::shader_read_only_optimal, - }, - ::vk::attachment{ - .format = depth_format, - .layout = ::vk::image_layout::depth_stencil_optimal, - .samples = ::vk::sample_bit::count_1, - .load = ::vk::attachment_load::clear, - .store = ::vk::attachment_store::dont_care, - .stencil_load = ::vk::attachment_load::dont_care, - .stencil_store = ::vk::attachment_store::dont_care, - .initial_layout = ::vk::image_layout::undefined, - .final_layout = ::vk::image_layout::depth_stencil_optimal, - }, - }; - m_viewport_renderpass = - ::vk::renderpass(m_driver, viewport_attachments); - - vk::image_params config_depth_image = { - .extent = { .width = p_swapchain_ctx.settings().width, - .height = p_swapchain_ctx.settings().height }, - .format = m_driver.depth_format(), - .property = vk::memory_property::device_local_bit, + std::println("after transition image layout"); + + // Perform additional configurations for specific handles + vk::image_params viewport_depth_params = { + .extent = { .width = m_params.width, + .height = m_params.height }, + .format = m_depth_format, + .memory_mask = m_physical->memory_properties( + vk::memory_property::device_local_bit | + vk::memory_property::host_visible_bit), .aspect = vk::image_aspect_flags::depth_bit, - .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - .phsyical_memory_properties = memory_properties, + .usage = vk::image_usage::depth_stencil_bit, }; + m_viewport_depth_image = + vk::sample_image(*m_device, viewport_depth_params); - m_depth_viewport_image = - vk::sample_image(m_driver, config_depth_image); - - for (uint32_t i = 0; i < m_viewport_framebuffers.size(); i++) { - std::array image_view_attachments = { - m_viewport_image.image_view(), - m_depth_viewport_image.image_view() - }; - - vk::framebuffer_params framebuffer_info = { - .renderpass = m_viewport_renderpass, - .views = image_view_attachments, - .extent = { p_swapchain_ctx.settings().width, - p_swapchain_ctx.settings().height } - }; - m_viewport_framebuffers[i] = - vk::framebuffer(m_driver, framebuffer_info); - } + transition_image_layout( + *m_device, + m_viewport_depth_image, + m_depth_format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - g_viewport_image_id = - static_cast(ImGui_ImplVulkan_AddTexture( - m_viewport_image.sampler(), - m_viewport_image.image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - } + construct(p_window, p_image_count, p_queue); - void create(GLFWwindow* p_window_handler, - const uint32_t& p_image_size, - const VkRenderPass& p_current_renderpass) { - ImGui_ImplGlfw_InitForVulkan(p_window_handler, true); - ImGui_ImplVulkan_InitInfo init_info = {}; - init_info.Instance = m_instance; - init_info.PhysicalDevice = m_physical; - init_info.Device = m_driver; - init_info.Queue = m_driver.graphics_queue(); - init_info.RenderPass = p_current_renderpass; - init_info.PipelineCache = nullptr; - init_info.DescriptorPool = m_desc_pool; - init_info.MinImageCount = 2; - init_info.ImageCount = p_image_size; - init_info.UseDynamicRendering = false; - init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; - ImGui_ImplVulkan_Init(&init_info); + // Offscreen texture to retrieve + g_viewport_image_id = ImGui_ImplVulkan_AddTexture( + m_viewport_image.sampler(), + m_viewport_image.image_view(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } - void begin(const VkCommandBuffer& p_current, - const uint32_t& p_frame_index) { - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); + void image_memory_barrier( + const VkCommandBuffer& p_command, + VkImageLayout p_old, + VkImageLayout p_new, + uint32_t p_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT) { - m_current_frame_index = p_frame_index; - m_current = p_current; + m_viewport_image.memory_barrier( + p_command, m_color_format, p_old, p_new, p_aspect_mask); } - void invalidate(const swapchain& p_swapchain) { - // Wait for device to finish all operations before recreating - // resources - vkDeviceWaitIdle(m_driver); + void depth_image_memory_barrier( + const VkCommandBuffer& p_command, + VkImageLayout p_old, + VkImageLayout p_new, + uint32_t p_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT) { - for (auto& fb : m_viewport_framebuffers) { - fb.destroy(); - } + m_viewport_depth_image.memory_barrier( + p_command, m_depth_format, p_old, p_new, p_aspect_mask); + } - // Remove old texture from ImGui if needed - // ImTextureID in ImGui Vulkan backend is VkDescriptorSet cast to - // void* - if (g_viewport_image_id != nullptr) { - VkDescriptorSet old_descriptor_set = - reinterpret_cast(g_viewport_image_id); - ImGui_ImplVulkan_RemoveTexture(old_descriptor_set); - g_viewport_image_id = nullptr; - } + void construct(GLFWwindow* p_window, + uint32_t p_image_count, + const vk::device_present_queue& p_queue) { - // Destroy old images - m_viewport_image.destroy(); - m_depth_viewport_image.destroy(); + ImGui_ImplGlfw_InitForVulkan(p_window, true); + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = m_instance.value(); + init_info.PhysicalDevice = m_physical.value(); + init_info.Device = *m_device; + init_info.Queue = p_queue; + init_info.RenderPass = nullptr; + init_info.PipelineCache = nullptr; + init_info.DescriptorPool = m_descriptor_pool; + init_info.MinImageCount = 2; + init_info.ImageCount = p_image_count; + init_info.UseDynamicRendering = true; + init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; - // Recreate viewport images with new swapchain size - VkPhysicalDeviceMemoryProperties memory_properties = - instance_context::physical_driver().memory_properties(); + const uint32_t color_format = static_cast(m_color_format); + const uint32_t depth_format = static_cast(m_depth_format); - vk::image_params config_image = { - .extent = { .width = p_swapchain.settings().width, - .height = p_swapchain.settings().height }, - .format = VK_FORMAT_B8G8R8A8_UNORM, - .property = vk::memory_property::device_local_bit, - .aspect = vk::image_aspect_flags::color_bit, - .usage = vk::image_usage::color_attachment_bit | - vk::image_usage::transfer_dst_bit | - vk::image_usage::sampled_bit, - .phsyical_memory_properties = memory_properties, - .address_mode_u = vk::sampler_address_mode::clamp_to_edge, - .addrses_mode_v = vk::sampler_address_mode::clamp_to_edge, - .addrses_mode_w = vk::sampler_address_mode::clamp_to_edge, - }; - m_viewport_image = vk::sample_image(m_driver, config_image); + init_info.PipelineRenderingCreateInfo = pipeline_rendering_info( + std::span(&color_format, 1), + depth_format, + depth_format); + ImGui_ImplVulkan_Init(&init_info); + } - // Transition to shader read-only layout - transition_image_layout(m_driver, - m_viewport_image, - VK_FORMAT_B8G8R8A8_UNORM, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + void set_current_command(vk::command_buffer& p_command) { + m_current_command = &p_command; + } - // Recreate depth image - vk::image_params config_depth_image = { - .extent = { .width = p_swapchain.settings().width, - .height = p_swapchain.settings().height }, - .format = m_driver.depth_format(), - .property = vk::memory_property::device_local_bit, - .aspect = vk::image_aspect_flags::depth_bit, - .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - .phsyical_memory_properties = memory_properties, - }; - m_depth_viewport_image = - vk::sample_image(m_driver, config_depth_image); - - // Recreate framebuffers with new images - for (uint32_t i = 0; i < m_viewport_framebuffers.size(); i++) { - std::array image_view_attachments = { - m_viewport_image.image_view(), - m_depth_viewport_image.image_view() - }; - - vk::framebuffer_params framebuffer_info = { - .renderpass = m_viewport_renderpass, - .views = image_view_attachments, - .extent = { p_swapchain.settings().width, - p_swapchain.settings().height } - }; - m_viewport_framebuffers[i] = - vk::framebuffer(m_driver, framebuffer_info); - } + [[nodiscard]] VkImageView color_image_view() const { + return m_viewport_image.image_view(); + } - // Update ImGui texture ID with new image - g_viewport_image_id = (ImTextureID)ImGui_ImplVulkan_AddTexture( - m_viewport_image.sampler(), - m_viewport_image.image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + [[nodiscard]] VkImageView depth_image_view() const { + return m_viewport_depth_image.image_view(); + } - // Update extent - m_extent = { .width = p_swapchain.settings().width, - .height = p_swapchain.settings().height }; + void begin() { + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); } void end() { ImGui::Render(); ImDrawData* draw_data = ImGui::GetDrawData(); - ImGui_ImplVulkan_RenderDrawData(draw_data, m_current); + ImGui_ImplVulkan_RenderDrawData(draw_data, *m_current_command); + } + void update_platforms() { ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); - } - } - - [[nodiscard]] ::vk::command_buffer imgui_active_command() const { - return m_viewport_command_buffers[m_current_frame_index]; - } - - vk::framebuffer active_framebuffer(uint32_t p_frame) const { - return m_viewport_framebuffers[p_frame]; - } - [[nodiscard]] vk::renderpass viewport_renderpass() const { - return m_viewport_renderpass; + vkDeviceWaitIdle(*m_device); + } } - void destroy() { - ImGui_ImplVulkan_Shutdown(); - vkDestroyDescriptorPool(m_driver, m_desc_pool, nullptr); - - for (auto& command_buffer : m_viewport_command_buffers) { - command_buffer.destroy(); + void destruct() { + if (g_viewport_image_id != nullptr) { + VkDescriptorSet old_descriptor = g_viewport_image_id; + ImGui_ImplVulkan_RemoveTexture(old_descriptor); + g_viewport_image_id = nullptr; } - for (auto& fb : m_viewport_framebuffers) { - fb.destroy(); - } + ImGui_ImplVulkan_Shutdown(); + vkDestroyDescriptorPool(*m_device, m_descriptor_pool, nullptr); - m_viewport_renderpass.destroy(); - m_viewport_image.destroy(); - m_depth_viewport_image.destroy(); + m_viewport_image.destruct(); + m_viewport_depth_image.destruct(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); } private: - VkInstance m_instance = nullptr; - VkPhysicalDevice m_physical = nullptr; - device m_driver{}; - uint32_t m_current_frame_index = 0; - VkSwapchainKHR m_current_swapchain_handler = nullptr; - VkDescriptorPool m_desc_pool = nullptr; - VkCommandBuffer m_current = nullptr; - std::vector<::vk::command_buffer> m_viewport_command_buffers; - std::array m_viewport_framebuffers; - ::vk::renderpass m_viewport_renderpass; + VkFormat m_color_format; + VkFormat m_depth_format; + VkDescriptorPool m_descriptor_pool = nullptr; + vk::command_buffer* m_current_command; + std::optional m_instance; + std::optional m_physical; + std::shared_ptr m_device = nullptr; + vk::surface_params m_surface_properties; vk::sample_image m_viewport_image; - vk::sample_image m_depth_viewport_image; - window_params m_extent; + vk::sample_image m_viewport_depth_image; + window_params m_params; }; }; \ No newline at end of file diff --git a/atlas/drivers/vulkan/instance_context.cppm b/atlas/drivers/vulkan/instance_context.cppm deleted file mode 100644 index b828f4ee..00000000 --- a/atlas/drivers/vulkan/instance_context.cppm +++ /dev/null @@ -1,253 +0,0 @@ -module; - -#include -#include -#include -#include - -#define GLFW_INCLUDE_VULKAN -#if _WIN32 -#define VK_USE_PLATFORM_WIN32_KHR -#include -#define GLFW_EXPOSE_NATIVE_WIN32 -#include -#include -#else -#include -#include -#endif - -export module atlas.drivers.vulkan.instance_context; - -import atlas.logger; - -import atlas.drivers.graphics_context; -import atlas.drivers.vulkan.utilities; -import atlas.drivers.vulkan.physical_device; -import atlas.drivers.vulkan.device; - -namespace atlas::vulkan { - - static std::vector initialize_instance_extensions() { - std::vector extension_names; - - uint32_t extension_count = 0; - const char** require_extensions = - glfwGetRequiredInstanceExtensions(&extension_count); - - for (uint32_t i = 0; i < extension_count; i++) { - // std::println("Required Extension = {}", require_extensions[i]); - extension_names.emplace_back(require_extensions[i]); - } - -#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG) - extension_names.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); -#endif - -#if defined(__APPLE__) - extension_names.emplace_back( - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); - extension_names.emplace_back( - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); -#endif - - return extension_names; - } - -#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG) - const std::vector validation_layers = { - "VK_LAYER_KHRONOS_validation", - "VK_LAYER_KHRONOS_synchronization2" - }; - - static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( - [[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT - p_message_severity, - [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT p_message_type, - const VkDebugUtilsMessengerCallbackDataEXT* p_callback_data, - [[maybe_unused]] void* p_user_data) { - console_log_trace("validation layer:\t\t{}", p_callback_data->pMessage); - return false; - } -#endif - - export class instance_context : public graphics_context { - public: - instance_context(const std::string&) { - VkApplicationInfo app_info = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = nullptr, - .applicationVersion = 1, - .pEngineName = "TheAtlasEngine", - .engineVersion = 1, - .apiVersion = VK_API_VERSION_1_3, - }; - - VkInstanceCreateInfo create_info = { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .pApplicationInfo = &app_info - }; - -#if defined(__APPLE__) - create_info.flags |= - VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; -#endif - - //! @note Setting up the required extensions for vulkan - std::vector extensions = - initialize_instance_extensions(); -#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG) - extensions.push_back("VK_EXT_debug_utils"); -#endif - create_info.enabledExtensionCount = - static_cast(extensions.size()); - create_info.ppEnabledExtensionNames = extensions.data(); -#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG) - // by default we enable validation layers used for debugging! - create_info.enabledLayerCount = - static_cast(validation_layers.size()); - create_info.ppEnabledLayerNames = validation_layers.data(); - - // printing out available validation layers - uint32_t layer_count; - std::vector available_validation_layers; - vkEnumerateInstanceLayerProperties(&layer_count, nullptr); - - available_validation_layers.resize(layer_count); - vkEnumerateInstanceLayerProperties( - &layer_count, available_validation_layers.data()); - - console_log_trace( - "================================================"); - console_log_trace("\tValidation Layers Available"); - console_log_trace( - "================================================"); - for (VkLayerProperties properties : available_validation_layers) { - console_log_trace("Validation Layer:\t\t{}", - properties.layerName); - console_log_trace("Description\t\t{}", properties.description); - console_log_trace("Version\t\t\t{}", - (int)properties.specVersion); - } - - console_log_trace("\n"); - console_log_trace( - "================================================\n"); - - VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { - .sType = - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, - .pfnUserCallback = debug_callback, - }; - - // create_info.pNext = - // (VkDebugUtilsMessengerCreateInfoEXT*)&debug_create_info; - create_info.pNext = - static_cast( - &debug_create_info); -#else - create_info.enabledLayerCount = 0; - create_info.ppEnabledLayerNames = nullptr; - create_info.pNext = nullptr; -#endif - vk_check( - vkCreateInstance(&create_info, nullptr, &m_instance_handler), - "vkCreateInstance"); - -#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG) - // This needs to be created after the VkInstance is or else it wont - // be applied the debug information during validation layer error - // message execution - m_vk_set_debug_utils_object_name_ext = - reinterpret_cast( - vkGetInstanceProcAddr(m_instance_handler, - "vkSetDebugUtilsObjectNameEXT")); -#endif - - m_physical = physical_device(m_instance_handler); - m_device = device(m_physical); - - s_instance = this; - } - - ~instance_context() override { - vkDestroyInstance(m_instance_handler, nullptr); - } - - /** - * @brief returns function pointer to allow for setting debug object - * name - * - * - * This allows for utilizing vkSetDebugUtilsObjectNameEXT during debug - * builds - * - * This allows for setting up object names that is useful to the - * programmer when a validation layer error message occurs unexpectedly - * - */ - static PFN_vkSetDebugUtilsObjectNameEXT get_debug_object_name() { - return s_instance->m_vk_set_debug_utils_object_name_ext; - } - - /** - * @brief used for providing a way to submit all vulkan metaobjects - * before the destruction of the vulkan logical device - * - * Per vulkan specification, it is required to have all object handles - * created with the logical device to be destroyed before the logical - * device itself gets destroyed during post cleanup - * - * This function was a means to ensure that the destruction of those - * vulkan child objects are handled in that order correctly - */ - static void submit_resource_free(std::function&& p_resource) { - s_instance->m_resources_free.push_back(p_resource); - } - - static physical_device physical_driver() { - return s_instance->m_physical; - } - - static device logical_device() { return s_instance->m_device; } - - protected: - [[nodiscard]] VkInstance context_handle() const override { - return m_instance_handler; - } - - void context_submit_resource_free( - const std::function& p_resource) override { - m_resources_free.push_back(p_resource); - } - - void destroy_context() override { - console_log_info("destroy_context!"); - for (auto& callback : m_resources_free) { - callback(); - } - - m_device.destroy(); - } - - private: - private: - static instance_context* s_instance; - VkInstance m_instance_handler = nullptr; - std::deque> m_resources_free{}; - PFN_vkSetDebugUtilsObjectNameEXT m_vk_set_debug_utils_object_name_ext; - physical_device m_physical; - device m_device; - }; - - instance_context* instance_context::s_instance = nullptr; -}; diff --git a/atlas/drivers/vulkan/mesh.cppm b/atlas/drivers/vulkan/mesh.cppm deleted file mode 100644 index 229ea284..00000000 --- a/atlas/drivers/vulkan/mesh.cppm +++ /dev/null @@ -1,260 +0,0 @@ -module; - -#include -#include -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include -#include -#include -#include -#include - -export module atlas.drivers.vulkan.mesh; -import vk; - -import atlas.logger; -import atlas.drivers.vulkan.instance_context; -import atlas.drivers.vulkan.physical_device; -import atlas.drivers.vulkan.device; -import atlas.drivers.vulkan.hash; - -export namespace atlas::vulkan { - /** - * @brief mesh class specifically defined with vulkan implementations for - * specific primitives - * - * @brief mesh class will contain metadata needed by vulkan specifications - * Ways to communicate through vulkan by only supplying information needed - * to update this mesh - * - * @brief Represents a renderable object -- supporting various material - * types, etc - * TODO - For now we have a map, this should - * be expanded to a proper material system for blending various materials - */ - class mesh { - public: - mesh() = default; - mesh(std::span p_vertices, - std::span p_indices) { - m_physical = instance_context::physical_driver(); - m_device = instance_context::logical_device(); - - vk::vertex_params vbo_settings = { .phsyical_memory_properties = - m_physical.memory_properties(), - .vertices = p_vertices }; - vk::index_params ibo_settings = { .phsyical_memory_properties = - m_physical.memory_properties(), - .indices = p_indices }; - m_vbo = vk::vertex_buffer(m_device, vbo_settings); - m_ibo = vk::index_buffer(m_device, ibo_settings); - } - - mesh(const std::filesystem::path& p_filename, bool p_flip = false) - : m_flip(p_flip) { - m_physical = instance_context::physical_driver(); - m_device = instance_context::logical_device(); - reload_mesh(p_filename); - } - - //! @brief Reload mesh vertices and indices when requested - void reload_mesh(const std::filesystem::path& p_filename) { - load_obj(p_filename); - } - - void draw(const VkCommandBuffer& p_command_buffer) { - m_vbo.bind(p_command_buffer); - if (m_ibo.size() > 0) { - m_ibo.bind(p_command_buffer); - vkCmdDrawIndexed(p_command_buffer, m_ibo.size(), 1, 0, 0, 0); - } - else { - vkCmdDraw(p_command_buffer, m_vbo.size(), 1, 0, 0); - } - } - - void destroy() { - m_vbo.destroy(); - m_ibo.destroy(); - - m_diffuse.destroy(); - m_specular.destroy(); - m_geoemtry_ubo.destroy(); - m_material_ubo.destroy(); - } - - //! @brief Loading single texture with specified std::filesystem::path - void add_diffuse(const std::filesystem::path& p_path) { - ::vk::texture_info config_texture = { - .phsyical_memory_properties = m_physical.memory_properties(), - .filepath = p_path, - }; - m_diffuse = ::vk::texture(m_device, config_texture); - - if (!m_diffuse.loaded()) { - console_log_info("Diffuse Texture {} is NOT loaded!!!", - p_path.string()); - return; - } - } - - void add_specular(const std::filesystem::path& p_path) { - vk::texture_info config_texture = { - .phsyical_memory_properties = m_physical.memory_properties(), - .filepath = p_path, - }; - m_specular = vk::texture(m_device, config_texture); - - if (!m_specular.loaded()) { - console_log_error("Specular Texture {} is NOT loaded!!!", - p_path.string()); - return; - } - } - - [[nodiscard]] ::vk::sample_image diffuse() const { - return m_diffuse.image(); - } - [[nodiscard]] ::vk::sample_image specular() const { - return m_specular.image(); - } - - //! @return true if mesh geometry model loaded succesfully - [[nodiscard]] bool loaded() const { return m_model_loaded; } - - [[nodiscard]] bool diffuse_loaded() const { return m_diffuse.loaded(); } - - [[nodiscard]] bool specular_loaded() const { - return m_specular.loaded(); - } - - void set_flip(bool p_flip) { m_flip = p_flip; } - - private: - void load_obj(const std::filesystem::path& p_filename) { - tinyobj::attrib_t attrib; - std::vector shapes; - std::vector materials; - std::string warn, err; - - //! @note If we return the constructor then we can check if the mesh - //! loaded successfully - //! @note We also receive hints if the loading is successful! - //! @note Return default constructor automatically returns false - //! means that mesh will return the boolean as false because it - //! wasnt successful - if (!tinyobj::LoadObj(&attrib, - &shapes, - &materials, - &warn, - &err, - p_filename.string().c_str())) { - console_log_warn("Could not load model from path {}", - p_filename.string()); - m_model_loaded = false; - return; - } - - std::vector vertices; - std::vector indices; - std::unordered_map unique_vertices{}; - - // for (const auto& shape : shapes) { - for (size_t i = 0; i < shapes.size(); i++) { - auto shape = shapes[i]; - // for (const auto& index : shape.mesh.indices) { - for (size_t j = 0; j < shape.mesh.indices.size(); j++) { - auto index = shape.mesh.indices[j]; - vk::vertex_input vertex{}; - - if (!unique_vertices.contains(vertex)) { - unique_vertices[vertex] = - static_cast(vertices.size()); - vertices.push_back(vertex); - } - - if (index.vertex_index >= 0) { - vertex.position = { - attrib.vertices[3 * index.vertex_index + 0], - attrib.vertices[3 * index.vertex_index + 1], - attrib.vertices[3 * index.vertex_index + 2] - }; - - vertex.color = { - attrib.colors[3 * index.vertex_index + 0], - attrib.colors[3 * index.vertex_index + 1], - attrib.colors[3 * index.vertex_index + 2] - }; - } - - if (!attrib.normals.empty()) { - vertex.normals = { - attrib.normals[3 * index.normal_index + 0], - attrib.normals[3 * index.normal_index + 1], - attrib.normals[3 * index.normal_index + 2] - }; - } - if (!attrib.texcoords.empty()) { - glm::vec2 flipped_uv = { - attrib.texcoords[static_cast( - index.texcoord_index) * - 2], - 1.0f - attrib.texcoords[static_cast( - index.texcoord_index) * - 2 + - 1], - }; - - glm::vec2 original_uv = { - attrib.texcoords[static_cast( - index.texcoord_index) * - 2], - attrib.texcoords[static_cast( - index.texcoord_index) * - 2 + - 1], - }; - - vertex.uv = m_flip ? flipped_uv : original_uv; - } - else { - vertex.uv = glm::vec2(0.f, 0.f); - } - - if (!unique_vertices.contains(vertex)) { - unique_vertices[vertex] = - static_cast(vertices.size()); - vertices.push_back(vertex); - } - - indices.push_back(unique_vertices[vertex]); - } - } - - ::vk::vertex_params vbo_settings = { - .phsyical_memory_properties = m_physical.memory_properties(), - .vertices = vertices - }; - ::vk::index_params ibo_settings = { - .phsyical_memory_properties = m_physical.memory_properties(), - .indices = indices - }; - m_vbo = ::vk::vertex_buffer(m_device, vbo_settings); - m_ibo = ::vk::index_buffer(m_device, ibo_settings); - m_model_loaded = true; - } - - private: - physical_device m_physical; - VkDevice m_device = nullptr; - vk::texture m_diffuse; - vk::texture m_specular; - vk::vertex_buffer m_vbo{}; - vk::index_buffer m_ibo{}; - vk::uniform_buffer m_geoemtry_ubo; - vk::uniform_buffer m_material_ubo; - bool m_model_loaded = false; - bool m_flip = false; - }; -}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/physical_device.cppm b/atlas/drivers/vulkan/physical_device.cppm deleted file mode 100644 index 1238f3e3..00000000 --- a/atlas/drivers/vulkan/physical_device.cppm +++ /dev/null @@ -1,232 +0,0 @@ -module; - -#include -#include - -#define GLFW_INCLUDE_VULKAN -#if _WIN32 -#define VK_USE_PLATFORM_WIN32_KHR -#include -#define GLFW_EXPOSE_NATIVE_WIN32 -#include -#include -#else -#include -#include -#endif - -export module atlas.drivers.vulkan.physical_device; - -import atlas.logger; -import atlas.drivers.vulkan.utilities; - -export namespace atlas::vulkan { - struct surface_properties { - VkSurfaceCapabilitiesKHR surface_capabilities; - VkSurfaceFormatKHR surface_format; - }; - - /** - * @brief vulkan-specific implementation wrapper around VkPhysicalDevice - * - * Wrapper that constructs a single physical device that provides API's that - * can be used to query specific information for your specific physical - * device - * - * A physical device represents your current hardware GPU and allows for the - * ability to enumerate information to check for compatibility on the - * current GPU - */ - class physical_device { - struct queue_family_indices { - uint32_t graphics = -1; - uint32_t compute = -1; - uint32_t transfer = -1; - }; - - public: - physical_device() = default; - - /** - * @brief constructs a new vulkan physical device - * - * @param p_instance requires a VkInstance to create a VkPhysicalDevice - * handle - */ - physical_device(const VkInstance& p_instance) { - uint32_t device_count = 0; - vkEnumeratePhysicalDevices(p_instance, &device_count, nullptr); - - if (device_count == 0) { - console_log_fatal("Device Count is {} and no devices found!!!", - device_count); - return; - } - - std::vector physical_drivers(device_count); - vkEnumeratePhysicalDevices( - p_instance, &device_count, physical_drivers.data()); - - for (const auto& device : physical_drivers) { - VkPhysicalDeviceProperties device_properties; - VkPhysicalDeviceFeatures device_features; - vkGetPhysicalDeviceProperties(device, &device_properties); - vkGetPhysicalDeviceFeatures(device, &device_features); -#if defined(__APPLE__) - // Apple silicon chips are integrated GPUs - // Prefer integrated GPU over discrete GPU on macOS - if (device_properties.deviceType == - VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { - m_physical_driver = device; - break; - } -#else - // Prefer discrete GPU over integrated GPU on other platforms - // (Linux, Windows) - if (device_properties.deviceType == - VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { - m_physical_driver = device; - break; - } -#endif - } - - uint32_t queue_family_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties( - m_physical_driver, &queue_family_count, nullptr); - m_queue_family_properties.resize(queue_family_count); - - vkGetPhysicalDeviceQueueFamilyProperties( - m_physical_driver, - &queue_family_count, - m_queue_family_properties.data()); - - m_queue_indices = select_queue_family_indices(); - } - - ~physical_device() = default; - - /** - * @brief gives you the queue families that are supported - * - * @return queue_family_indices are the indices of the specific queue's - * that are compatible on current hardware specifications - */ - [[nodiscard]] queue_family_indices read_queue_family_indices() const { - return m_queue_indices; - } - - [[nodiscard]] VkPhysicalDeviceMemoryProperties memory_properties() - const { - VkPhysicalDeviceMemoryProperties physical_memory_properties; - vkGetPhysicalDeviceMemoryProperties(m_physical_driver, - &physical_memory_properties); - return physical_memory_properties; - } - - /** - * @return uint32_t is the index to the presentation index of the - * specific presentation queue - */ - [[nodiscard]] uint32_t read_presentation_index( - const VkSurfaceKHR& p_surface) { - uint32_t presentation_index = -1; - VkBool32 compatible = VK_FALSE; - uint32_t i = 0; - for (const auto& queue_family : m_queue_family_properties) { - if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - vk_check(vkGetPhysicalDeviceSurfaceSupportKHR( - m_physical_driver, i, p_surface, &compatible), - "vkGetPhysicalDeviceSurfaceSupportKHR"); - - if (compatible) { - presentation_index = i; - } - } - i++; - } - - return presentation_index; - } - - /** - * @brief querying surface properties based on the currently specified - * VkSurfaceKHR handle created - */ - [[nodiscard]] surface_properties get_surface_properties( - const VkSurfaceKHR& p_surface) { - vk_check(vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - m_physical_driver, - p_surface, - &m_surface_properties.surface_capabilities), - "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); - - uint32_t format_count = 0; - std::vector formats; - vk_check(vkGetPhysicalDeviceSurfaceFormatsKHR( - m_physical_driver, p_surface, &format_count, nullptr), - "vkGetPhysicalDeviceSurfaceFormatsKHR"); - - formats.resize(format_count); - - vk_check( - vkGetPhysicalDeviceSurfaceFormatsKHR( - m_physical_driver, p_surface, &format_count, formats.data()), - "vkGetPhysicalDeviceSurfaceFormatsKHR"); - - for (const auto& format : formats) { - if (format.format == VK_FORMAT_B8G8R8A8_SRGB && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - m_surface_properties.surface_format = format; - } - } - - m_surface_properties.surface_format = formats[0]; - - return m_surface_properties; - } - - /** - * @brief Allows for treating vk_physical_device as a VkPhysicalDevice - * handle - * - * Simplifies using this same class for creating other vulkan - * metaobjects - */ - operator VkPhysicalDevice() { return m_physical_driver; } - - /** - * @brief Allows for treating vk_physical_device as a VkPhysicalDevice - * handle - * - * Simplifies using this same class for creating other vulkan - * metaobjects - */ - operator VkPhysicalDevice() const { return m_physical_driver; } - - private: - queue_family_indices select_queue_family_indices() { - VkPhysicalDeviceMemoryProperties physical_device_memory_properties; - vkGetPhysicalDeviceMemoryProperties( - m_physical_driver, &physical_device_memory_properties); - physical_device::queue_family_indices indices; - int i = 0; - - for (const auto& queue_family : m_queue_family_properties) { - if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - indices.graphics = i; - break; - } - i++; - } - - return indices; - } - - private: - VkPhysicalDevice m_physical_driver = nullptr; - queue_family_indices m_queue_indices{}; - std::vector m_queue_family_properties{}; - surface_properties m_surface_properties{}; - }; -}; diff --git a/atlas/drivers/vulkan/render_context.cppm b/atlas/drivers/vulkan/render_context.cppm new file mode 100644 index 00000000..de80a8e9 --- /dev/null +++ b/atlas/drivers/vulkan/render_context.cppm @@ -0,0 +1,573 @@ +module; + +#include +#include +#include +#include +#include + +#include +#include +#define GLM_FORCE_RADIANS +#include +#include +#define GLM_ENABLE_EXPERIMENTAL +#include + +export module atlas.drivers.vulkan:render_context; + +import :stb_image; +import :graphics_context; +import :environment_map; +import :gpu_uniforms; + +import atlas.core.scene; +import atlas.drivers.importer; +import atlas.core.utilities; + +import vk; + +export namespace atlas { + + /** + * + * @brief Context that translates the ECS rendering-specific components to + * GPU-visible resources + * + * Manages the dispatching of task workloads to performing data transfers + * and draw calls. + * + */ + class render_context { + public: + render_context() = default; + render_context(/*NOLINT*/ std::shared_ptr p_context, + VkFormat p_color_format, + VkFormat p_depth_format) { + m_physical = p_context->physical_device(); + m_device = p_context->logical_device(); + m_color_format = p_color_format; + m_depth_format = p_depth_format; + + // Vertex Attributes Parameters + std::array attribute_entries = { + vk::vertex_attribute_entry{ + .location = 0, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, position), + }, + vk::vertex_attribute_entry{ + .location = 1, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, color), + }, + vk::vertex_attribute_entry{ + .location = 2, + .format = vk::format::rg32_sfloat, + .stride = offsetof(vk::vertex_input, uv), + }, + vk::vertex_attribute_entry{ + .location = 3, + .format = vk::format::rgb32_sfloat, + .stride = offsetof(vk::vertex_input, normals), + } + }; + std::array attributes = { + vk::vertex_attribute{ + .binding = 0, + .entries = attribute_entries, + .stride = sizeof(vk::vertex_input), + .input_rate = vk::input_rate::vertex, + }, + }; + std::array shader_sources = { + vk::shader_source{ + .filename = "builtin.shaders/pbr.vert.spv", + .stage = vk::shader_stage::vertex, + }, + vk::shader_source{ + .filename = "builtin.shaders/pbr.frag.spv", + .stage = vk::shader_stage::fragment, + }, + }; + + // To render triangle, we do not need to set any vertex attributes + vk::shader_resource_info shader_info = { + .sources = shader_sources, + }; + m_shader_resource = vk::shader_resource(*m_device, shader_info); + m_shader_resource.vertex_attributes(attributes); + + // Configuring Descriptor Set 0 -- specify to vk::pipeline + // Descriptor Set 0 + uint32_t max_descriptors = 1000; + std::array entries_set1 = { + vk::descriptor_entry{ + // layout (set = 0, binding = 1) uniform sampler2D textures[]; + .type = vk::descriptor_type::combined_image_sampler, + .binding_point = { + .binding = 1, + .stage = vk::shader_stage::fragment, + }, + .descriptor_count = max_descriptors, + .flags = vk::descriptor_bind_flags::partially_bound_bit | + vk::descriptor_bind_flags::update_after_bind, + }, + vk::descriptor_entry{ + // layout (set = 0, binding = 2) uniform sampler2D environment_map; + .type = vk::descriptor_type::combined_image_sampler, + .binding_point = { + .binding = 2, + .stage = vk::shader_stage::fragment, + }, + .descriptor_count = 1, + .flags = vk::descriptor_bind_flags::partially_bound_bit | + vk::descriptor_bind_flags::update_after_bind, + } + }; + + // layout(set = 0, ...) + vk::descriptor_layout set0_layout = { + .slot = 0, + .max_sets = max_descriptors, + .entries = + entries_set1, // descriptor layout entries description + .descriptor_counts = + std::span(&max_descriptors, 1), + }; + m_set0_resource = vk::descriptor_resource( + *m_device, + set0_layout, + vk::descriptor_layout_flags::update_after_bind_pool); + + std::array + color_blend_attachments = { + vk::color_blend_attachment_state{}, + }; + + std::array dynamic_states = { + vk::dynamic_state::viewport, + vk::dynamic_state::scissor, + }; + + m_format = static_cast(p_color_format); + uint32_t vertex_mask = + static_cast(vk::shader_stage::vertex); + uint32_t fragment_mask = + static_cast(vk::shader_stage::fragment); + uint32_t stage_mask = vertex_mask | fragment_mask; + m_stage = static_cast(stage_mask); + vk::push_constant_range range = { + .stage = m_stage, + .offset = 0, + .range = sizeof(push_constant_data), + }; + + VkDescriptorSetLayout descriptor0_layout = m_set0_resource.layout(); + vk::pipeline_params pipeline_configuration = { + .use_render_pipeline = true, + .color_attachment_formats = std::span(&m_format, 1), + .depth_format = static_cast(p_depth_format), + .stencil_format = static_cast(p_depth_format), + .renderpass = nullptr, + .shader_modules = m_shader_resource.handles(), + .vertex_attributes = m_shader_resource.vertex_attributes(), + .vertex_bind_attributes = m_shader_resource.vertex_bind_attributes(), + .descriptor_layouts = std::span(&descriptor0_layout, 1), + .color_blend = { + .attachments = color_blend_attachments, + }, + .depth_stencil_enabled = true, + .dynamic_states = dynamic_states, + .push_constants = std::span(&range, 1), + }; + m_main_pipeline = vk::pipeline(*m_device, pipeline_configuration); + + vk::buffer_parameters uniform_params = { + .memory_mask = m_physical->memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), + .usage = vk::buffer_usage::uniform_buffer_bit | + vk::buffer_usage::shader_device_address_bit, + .allocate_flags = + vk::memory_allocate_flags::device_address_bit_khr, + }; + + m_scene_uniforms = vk::dyn::buffer( + *m_device, sizeof(scene_uniforms), uniform_params); + + // We are setting to the maximum of objects that should be managed + // in this uniform buffer This uniform buffer is responsible for + // managing the model matrices of every object in a given scene. + uint32_t max_objects = 10'000; + m_object_model_uniforms = vk::dyn::buffer( + *m_device, sizeof(objects_uniform) * max_objects, uniform_params); + + // configuring uniforms for point lights + m_lighting_uniforms = vk::dyn::buffer( + *m_device, sizeof(light_scene_ubo), uniform_params); + + // Index 0 will default to a white texture + vk::image_extent extent = { + .width = 1, + .height = 1, + }; + std::array white_color = { 0xff, 0xff, 0xff, 0xff }; + m_gpu_textures.emplace_back( + *m_device, + extent, + white_color, + m_physical->memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit)); + } + + void prebake() { + flecs::query<> all_meshes = + m_world->query_builder().build(); + + all_meshes.each([this](flecs::entity p_entity) { + const mesh_source* src = p_entity.get(); + + vk::buffer_parameters vertex_params = { + .memory_mask = m_physical->memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), + .usage = vk::buffer_usage::transfer_dst_bit | + vk::buffer_usage::vertex_buffer_bit, + }; + + vk::buffer_parameters index_params = { + .memory_mask = m_physical->memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), + .usage = vk::buffer_usage::index_buffer_bit, + }; + + // importing .obj 3d models here + obj_importer importer(src->model_path, src->flip); + gpu_mesh_data gpu_mesh{}; + gpu_mesh.vertex = vk::vertex_buffer( + *m_device, importer.vertices(), vertex_params); + gpu_mesh.index = + vk::index_buffer(*m_device, importer.indices(), index_params); + gpu_mesh.has_indices_buffer = + (importer.indices().size() >= 0) ? true : false; + gpu_mesh.vertices_size = importer.vertices().size(); + gpu_mesh.indices_size = importer.indices().size(); + + m_meshes.emplace(p_entity.id(), gpu_mesh); + + vk::texture_params config_texture = { + .memory_mask = m_physical->memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_cached_bit), + }; + // Loading texture and setting up VkSampler and VkImageView + stb_image diffuse_img = stb_image(src->diffuse, config_texture); + stb_image specular_img = + stb_image(src->specular, config_texture); + + // Reminder: Use diffuse_idx + gpu_material material = {}; + if (!src->diffuse.empty()) { + material.diffuse_idx = m_texture_slot_index++; + m_gpu_textures.emplace_back( + *m_device, &diffuse_img, config_texture); + } + + if (!src->specular.empty()) { + material.specular_idx = m_texture_slot_index++; + m_gpu_textures.emplace_back( + *m_device, &specular_img, config_texture); + } + + m_material_table.emplace(p_entity.id(), material); + }); + + // Preparing the texture data before we update descriptor set 0 + // Storing all of our texture via one contiguous array of textures + for (auto& image : m_gpu_textures) { + vk::write_image viking_room_texture = { + .sampler = image.image().sampler(), + .view = image.image().image_view(), + .layout = vk::image_layout::shader_read_only_optimal, + }; + m_gpu_images.emplace_back(viking_room_texture); + } + + // Ensure that we load the environment + // We should never load an invalid environment + if (m_world->has()) { + const environment* environment_data = + m_world->get(); + m_environment_map = environment_map(m_device, + m_physical.value(), + environment_data->filepath, + m_color_format, + m_depth_format); + } + else { + std::array black_color = { 0.f, 0.f, 0.f, 0.f }; + m_environment_map = + environment_map(m_device, + m_physical.value(), + black_color, + vk::image_extent{ .width = 1, .height = 1 }, + m_color_format, + m_depth_format); + } + + vk::write_image environment_image = { + .sampler = m_environment_map.sampler(), + .view = m_environment_map.image_view(), + .layout = vk::image_layout::shader_read_only_optimal, + }; + std::array set0_samples = { + // layout(set = 0, binding = 1) sampler2D[] + vk::write_image_descriptor{ + .dst_binding = 1, + .sample_images = m_gpu_images, + }, + // layout(set = 0, binding = 2) sampler2D environment; + vk::write_image_descriptor{ + .dst_binding = 2, + .sample_images = + std::span(&environment_image, 1), + } + }; + + m_set0_resource.update({}, set0_samples); + } + + void begin(const glm::mat4& p_proj, const glm::mat4& p_view) { + // Calculating skybox projection and view + // m_skybox_proj_view = p_proj * glm::mat4(glm::mat3(p_view)); + m_projection = p_proj; + m_view = p_view; + + // querying for objects with point lights + flecs::query all_point_lights = + m_world->query_builder().build(); + + int index = 0; + light_scene_ubo scene_point_lights{}; + all_point_lights.each( + [&index, &scene_point_lights](flecs::entity p_entity, + point_light& p_light) { + const transform* t = p_entity.get(); + p_light.position = t->position; + + scene_point_lights.point_lights[index] = { + .position = glm::vec4(p_light.position, 1.f), + .color = p_light.color, + .attenuation = p_light.attenuation, + .constant = p_light.constant, + .linear = p_light.linear, + .quadratic = p_light.quadratic, + .ambient = p_light.ambient, + .diffuse = p_light.diffuse, + .specular = p_light.specular, + }; + + index++; + }); + + scene_point_lights.num_lights = index; + + m_lighting_uniforms.transfer( + std::span(&scene_point_lights, 1)); + + m_main_pipeline.bind(*m_current_command); + + flecs::query<> all_meshes = + m_world->query_builder().build(); + + // Camera projection/view matrices calculated for worldspace + // calculation + scene_uniforms scene_ubo = { + .view = p_view, + .proj = p_proj, + .camera_pos = m_camera_pos, + }; + + m_scene_uniforms.transfer( + std::span(&scene_ubo, 1)); + + // Calculating model matrix based on object's transforms + // specifications (pos, scale, rotation) + all_meshes.each([this](flecs::entity p_entity) { + const transform* t = p_entity.get(); + glm::mat4 model = glm::mat4(1.f); + model = glm::translate(model, t->position); + + glm::mat4 rotation_mat = glm::mat4(glm::quat(t->rotation)); + model *= rotation_mat; + model = glm::scale(model, t->scale); + + if (m_model_matrices_lookup.contains(p_entity.id())) { + // hash table to lookup specific index, using the entitys + // main ID has a hash key This way we can use the hash value + // as the location in the index to modify that model matrix. + m_model_matrices[m_model_matrices_lookup[p_entity.id()]] = + model; + } + else { + // Add model matrix if non existant in the array + m_model_matrices.push_back(model); + + // Keeping track of the location to that model matrix for + // book keeping. + m_model_matrices_lookup.emplace( + p_entity.id(), m_model_matrix_index_count++); + } + }); + + m_object_model_uniforms.transfer(std::span( + m_model_matrices.data(), m_model_matrices.size())); + + const VkDescriptorSet set0 = m_set0_resource; + m_current_command->bind_descriptors( + m_main_pipeline.layout(), + VK_PIPELINE_BIND_POINT_GRAPHICS, + std::span(&set0, 1)); + } + + void end() { + flecs::query<> all_meshes = + m_world->query_builder().build(); + all_meshes.each([this](flecs::entity p_entity) { + // Retrieving the buffer address that can be looked up from the + // glsl shader + const uint64_t scene_ubo_address = + m_scene_uniforms.get_device_address(); + const uint64_t objects_ubo_address = + m_object_model_uniforms.get_device_address(); + const uint64_t lighting_address = + m_lighting_uniforms.get_device_address(); + push_constant_data push = { + .scene_address = scene_ubo_address, + .model_mat_array_address = objects_ubo_address, + .model_idx = static_cast( + m_model_matrices_lookup[p_entity.id()]), + .diffuse_idx = static_cast( + m_material_table[p_entity.id()].diffuse_idx), + .specular_idx = static_cast( + m_material_table[p_entity.id()].specular_idx), + .point_light_address = lighting_address, + }; + + m_main_pipeline.push_constant( + *m_current_command, push, m_stage, 0); + + // TODO: Use Vulkan Indirect Command Draw call for this to + // reduce draw calls + const auto& mesh = m_meshes[p_entity.id()]; + const VkBuffer vertex = mesh.vertex; + uint64_t offset = 0; + m_current_command->bind_vertex_buffers( + std::span(&vertex, 1), + std::span(&offset, 1)); + if (mesh.has_indices_buffer) { + m_current_command->bind_index_buffers32(mesh.index); + vkCmdDrawIndexed( + *m_current_command, mesh.indices_size, 1, 0, 0, 0); + } + else { + vkCmdDraw(*m_current_command, mesh.vertices_size, 1, 0, 0); + } + }); + + // Draw Environments + m_environment_map.begin(m_projection, m_view); + + m_environment_map.end(); + } + + void set_command(vk::command_buffer& p_command) { + m_current_command = &p_command; + m_environment_map.set_current_command(*m_current_command); + } + + void current_scene(flecs::world& p_world) { m_world = &p_world; } + + void destruct() { + m_scene_uniforms.reset(); + m_object_model_uniforms.reset(); + m_lighting_uniforms.reset(); + + m_environment_map.destruct(); + + // destroying vector + for (auto& image : m_gpu_textures) { + image.destruct(); + } + + for (auto& [id, mesh] : m_meshes) { + mesh.vertex.destruct(); + mesh.index.destruct(); + } + + m_set0_resource.destruct(); + m_shader_resource.destruct(); + m_main_pipeline.destruct(); + } + + void set_camera_pos(const glm::vec4& p_camera_pos) { + m_camera_pos = p_camera_pos; + } + + private: + glm::vec4 m_camera_pos = glm::vec4(1.f); + glm::mat4 m_projection; + glm::mat4 m_view; + uint32_t m_format; + VkFormat m_color_format; + VkFormat m_depth_format; + std::optional m_physical; + std::shared_ptr m_device; + vk::command_buffer* m_current_command = nullptr; + vk::shader_resource m_shader_resource; + vk::pipeline m_main_pipeline; + std::vector m_indirect_commands; + vk::descriptor_resource m_set0_resource; + + /** + * 3 Specific Buffers for accessing data + * 1.) Scene Uniform Buffer (proj/view) + * 2.) Object Uniforms (model matrix): Another use is for instancing + * having multiple mat4's referencing to instancing copies 3.) Material + * Uniforms (diffuse/specular/etc...) + */ + vk::dyn::buffer m_scene_uniforms; + // uniform buffer to write all of our objects mat4 model matrices in + vk::dyn::buffer m_object_model_uniforms; + vk::dyn::buffer m_lighting_uniforms; + + std::unordered_map m_meshes; + + uint64_t m_texture_slot_index = 1; + + // Represents the index to retrieve the location to access the model + // matrix + // inside of the vector array + uint64_t m_model_matrix_index_count = 0; + + // + std::unordered_map m_model_matrices_lookup; + std::vector m_model_matrices; + + // material lookups + // is to search for specific indices that + // correspond to various material surfaces indices to search inside of + // vector + std::unordered_map m_material_table; + std::vector m_gpu_textures; + std::vector m_gpu_images; + vk::shader_stage m_stage; + + flecs::world* m_world = nullptr; + + environment_map m_environment_map; + }; +}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/render_system.cppm b/atlas/drivers/vulkan/render_system.cppm deleted file mode 100644 index b60866ec..00000000 --- a/atlas/drivers/vulkan/render_system.cppm +++ /dev/null @@ -1,713 +0,0 @@ -module; - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -export module atlas.drivers.vulkan.render_system; -import atlas.drivers.renderer_system; - -import atlas.core.utilities; -import vk; -import atlas.core.scene; -import atlas.drivers.graphics_context; -import atlas.drivers.vulkan.instance_context; -import atlas.drivers.vulkan.physical_device; -import atlas.drivers.vulkan.device; -import atlas.drivers.vulkan.mesh; -import atlas.drivers.vulkan.shader_resource_group; -import atlas.core.scene.world; -import atlas.core.scene; -import atlas.drivers.vulkan.uniforms; -import atlas.drivers.vulkan.mesh; -import atlas.core.scene.components; -import atlas.drivers.vulkan.environment_map; - -export namespace atlas::vulkan { - /** - * @brief Something to consider for mesh loading. - * - * How will meshes get loaded? - * - * There are a few ways for considering for the base approach, which are: - * TODO: These are things to think about how this may happen because I want - * to make this lightweight in the sense the data isnt continuously being - * modified. Taking a looking at minimizing the loading state of vulkan - * implementation-specific meshes - * * While also making the way how mesh components are being added the - * same as before - * - Something to avoid is the entities containing the geometry data itself - * but being able to reference to their respective geometry data that are - * getting submitted to the GPU - * - * * Batching ID's into hash table that contains the actual geometry data - * * Using ID to search up the mesh loaded and cached into the map, then - * reuse that geometry whenever the uniforms are changed - * * This way we aren't reloading in the same mesh multiple times, treating - * the hash table as a slot of the mesh contained within that scene - * * Potentially std::map> m_geometries - * * Idea is the std::string is the geometries within this scene, the - * data format is: > - */ - class render_system : public renderer_system { - public: - render_system(ref p_context, - const window_params& p_params, - uint32_t p_image_size, - const std::string&) { - m_physical = instance_context::physical_driver(); - m_device = instance_context::logical_device(); - - m_window_extent = p_params; - m_image_count = p_image_size; - -#ifdef USE_SHADERC - console_log_info("shaderc enabled!!"); - std::array shader_sources = { - vk::shader_source{ - "builtin.shaders/test.vert", - vk::shader_stage::vertex, - }, - vk::shader_source { - "builtin.shaders/test.frag", - vk::shader_stage::fragment, - } - }; -#else - console_log_info("shaderc disabled!!"); - std::array shader_sources = { - vk::shader_source{ - "builtin.shaders/test.vert.spv", - vk::shader_stage::vertex, - }, - vk::shader_source{ - "builtin.shaders/test.frag.spv", - vk::shader_stage::fragment, - } - }; -#endif - std::array attribute_entries = { - vk::vertex_attribute_entry{ - .location = 0, - .format = vk::format::rgb32_sfloat, - .stride = offsetof(vk::vertex_input, position), - }, - vk::vertex_attribute_entry{ - .location = 1, - .format = vk::format::rgb32_sfloat, - .stride = offsetof(vk::vertex_input, color), - }, - vk::vertex_attribute_entry{ - .location = 2, - .format = vk::format::rgb32_sfloat, - .stride = offsetof(vk::vertex_input, normals), - }, - vk::vertex_attribute_entry{ - .location = 3, - .format = vk::format::rg32_sfloat, - .stride = offsetof(vk::vertex_input, uv), - } - }; - - std::array attribute = { - vk::vertex_attribute{ - // layout (set = 0, binding = 0) - .binding = 0, - .entries = attribute_entries, - .stride = sizeof(vk::vertex_input), - .input_rate = vk::input_rate::vertex, - }, - }; - - vk::shader_resource_info shader_info = { - .sources = shader_sources, - }; - - try { - m_shader_group = shader_resource_group(m_device, shader_info); - m_shader_group.vertex_attributes(attribute); - } - catch (std::runtime_error& e) { - console_log_error("Compilation Error!!"); - console_log_error("{}", e.what()); - } - // Setting global descriptor set 0 - std::vector set0_entries = { - vk::descriptor_entry{ - // specifies "layout (set = 0, binding = 0) uniform GlobalUbo" - .type = vk::buffer::uniform, - .binding_point = { - .binding = 0, - .stage = vk::shader_stage::vertex, - }, - .descriptor_count = 1, - }, - vk::descriptor_entry{ - // specifies "layout (set = 0, binding = 1) uniform light_ubo" - .type = vk::buffer::uniform, - .binding_point = { - .binding = 1, - .stage = vk::shader_stage::fragment, - }, - .descriptor_count = 1, - }, - }; - - // uint32_t image_count = image_count; - vk::descriptor_layout set0_layout = { - .slot = 0, - .max_sets = m_image_count, - .entries = set0_entries, - }; - m_global_descriptors = - vk::descriptor_resource(m_device, set0_layout); - - vk::uniform_params global_info = { - .phsyical_memory_properties = m_physical.memory_properties(), - .size_bytes = sizeof(global_ubo), - .debug_name = "\nm_global_uniforms\n", - .vkSetDebugUtilsObjectNameEXT = - instance_context::get_debug_object_name() - }; - m_global_uniforms = vk::uniform_buffer(m_device, global_info); - - // setting up our light uniforms as the global uniforms rather then - // per-object basis - vk::uniform_params light_ubo_params = { - .phsyical_memory_properties = m_physical.memory_properties(), - .size_bytes = sizeof(light_scene_ubo), - }; - m_point_light_uniforms = - vk::uniform_buffer(m_device, light_ubo_params); - - std::array binding0_uniforms = { - vk::write_buffer{ - .buffer = m_global_uniforms, - .offset = 0, - .range = m_global_uniforms.size_bytes(), - }, - }; - - std::array binding1_uniforms = { - vk::write_buffer{ - .buffer = m_point_light_uniforms, - .offset = 0, - .range = m_point_light_uniforms.size_bytes(), - }, - }; - - std::array set0_write_buffers = { - vk::write_buffer_descriptor{ - .dst_binding = 0, - .uniforms = binding0_uniforms, - }, - vk::write_buffer_descriptor{ - .dst_binding = 1, - .uniforms = binding1_uniforms, - } - }; - m_global_descriptors.update(set0_write_buffers); - - m_sets_layouts = { - m_global_descriptors.layout(), - }; - - vk::image_extent extent = { - .width = 1, - .height = 1, - }; - m_white_texture = - vk::texture(m_device, extent, m_physical.memory_properties()); - - p_context->submit_resource_free([this]() { - console_log_info("vulkan::render_system destructin invoked!!"); - m_white_texture.destroy(); - m_shader_group.destroy(); - m_global_descriptors.destroy(); - m_global_uniforms.destroy(); - m_point_light_uniforms.destroy(); - for (auto& [id, mesh] : m_cached_meshes) { - console_log_trace( - "Entity \"{}\" Destroyed in vk_renderer!!!", id); - mesh.destroy(); - } - - for (auto& [id, uniform] : m_mesh_geometry_set) { - uniform.destroy(); - } - - for (auto& [id, material_uniform] : m_mesh_material_set) { - material_uniform.destroy(); - } - - for (auto& [key, descriptor_map] : m_mesh_descriptors) { - for (auto& [descriptor_type, descriptor] : descriptor_map) { - descriptor.destroy(); - } - } - - m_skybox.destroy(); - m_main_pipeline.destroy(); - }); - - console_log_info( - "Vulkan-specific implementation constructed successfully!!!"); - } - - ~render_system() override = default; - - private: - void preload_assets(const vk::renderpass& p_renderpass) override { - m_final_renderpass = p_renderpass; - - // std::vector faces = { - // "assets/skybox/light_sky/right.png", - // "assets/skybox/light_sky/left.png", - // "assets/skybox/light_sky/top.png", - // "assets/skybox/light_sky/bottom.png", - // "assets/skybox/light_sky/front.png", - // "assets/skybox/light_sky/back.png" - // }; - // m_skybox = environment_map(m_device, faces, - // m_physical.memory_properties(), m_final_renderpass); std::string - - const environment* environment_data = - m_current_scene->get(); - m_skybox = - environment_map(m_device, - std::filesystem::path(environment_data->filepath), - m_physical.memory_properties(), - m_final_renderpass); - - flecs::query<> caching = - m_current_scene->query_builder().build(); - - caching.each([this](flecs::entity p_entity) { - const mesh_source* target = p_entity.get(); - mesh new_mesh(std::filesystem::path(target->model_path), - target->flip); - - // we do a check if the geometry uniform associated with this - // game object is valid - if (!m_mesh_geometry_set.contains(p_entity.id())) { - vk::uniform_params geo_info = { - .phsyical_memory_properties = - m_physical.memory_properties(), - .size_bytes = sizeof(material_uniform), - }; - m_mesh_geometry_set[p_entity.id()] = - vk::uniform_buffer(m_device, geo_info); - } - - // check if material is already associated with this particular - // game object - if (!m_mesh_material_set.contains(p_entity.id())) { - vk::uniform_params mat_info = { - .phsyical_memory_properties = - m_physical.memory_properties(), - .size_bytes = sizeof(material_metadata), - }; - m_mesh_material_set[p_entity.id()] = - vk::uniform_buffer(m_device, mat_info); - } - - new_mesh.add_diffuse(std::filesystem::path(target->diffuse)); - new_mesh.add_specular(std::filesystem::path(target->specular)); - - if (new_mesh.loaded()) { - m_cached_meshes.emplace(p_entity.id(), new_mesh); - - std::vector set1_entries = { - vk::descriptor_entry{ - // specifies "layout (set = 1, binding = 0) uniform geometry_uniform" - .type = vk::buffer::uniform, - .binding_point = { - .binding = 0, - .stage = vk::shader_stage::vertex, - }, - .descriptor_count = 1, - }, - vk::descriptor_entry{ - // specifies "layout (set = 1, binding = 1) uniform sampler2D diffuse_texture" - .type = vk::buffer::combined_image_sampler, - .binding_point = { - .binding = 1, - .stage = vk::shader_stage::fragment, - }, - .descriptor_count = 1, - }, - vk::descriptor_entry{ - // specifies "layout (set = 1, binding = 2) uniform sampler2D specular_texture" - .type = vk::buffer::combined_image_sampler, - .binding_point = { - .binding = 2, - .stage = vk::shader_stage::fragment, - }, - .descriptor_count = 1, - }, - vk::descriptor_entry{ - // specifies "layout (set = 1, binding = 3) uniform sampler2D material_ubo" - .type = vk::buffer::uniform, - .binding_point = { - .binding = 3, - .stage = vk::shader_stage::fragment, - }, - .descriptor_count = 1, - }, - }; - - vk::descriptor_layout set1_layout = { - .slot = 1, - .max_sets = m_image_count, - .entries = set1_entries, - }; - - m_mesh_descriptors[p_entity.id()].emplace( - "materials", - vk::descriptor_resource(m_device, set1_layout)); - - // specify to the vk::write_descriptor_buffer - std::array binding0_buffers = { - vk::write_buffer{ - .buffer = m_mesh_geometry_set[p_entity.id()], - .offset = 0, - .range = - m_mesh_geometry_set[p_entity.id()].size_bytes(), - } - }; - - std::array binding3_buffers = { - vk::write_buffer{ - .buffer = m_mesh_material_set[p_entity.id()], - .offset = 0, - .range = - m_mesh_material_set[p_entity.id()].size_bytes(), - } - }; - - std::vector - material_uniforms = { - // layout(set= 1, binding = 0) geometry_ubo - vk::write_buffer_descriptor{ - .dst_binding = 0, - .uniforms = binding0_buffers, - }, - // layout(set= 1, binding = 3) material_ubo - vk::write_buffer_descriptor{ - .dst_binding = 3, - .uniforms = binding3_buffers, - }, - }; - - // layout(set = 1, binding = 1) - // If the texture loaded successfully then we use that - // texture, otherwise utilize the default white texture - vk::sample_image diffuse = - m_cached_meshes[p_entity.id()].diffuse_loaded() - ? m_cached_meshes[p_entity.id()].diffuse() - : m_white_texture.image(); - - // layout(set = 1, binding = 2) - vk::sample_image specular = - m_cached_meshes[p_entity.id()].specular_loaded() - ? m_cached_meshes[p_entity.id()].specular() - : m_white_texture.image(); - - // writes to texture at layout(set = 1, binding = 1) - std::array binding1_images = { - vk::write_image{ - .sampler = diffuse.sampler(), - .view = diffuse.image_view(), - .layout = vk::image_layout::shader_read_only_optimal, - }, - }; - - // writes to texture at layout(set = 1, binding = 2) - std::array binding2_images = { - vk::write_image{ - .sampler = specular.sampler(), - .view = specular.image_view(), - .layout = vk::image_layout::shader_read_only_optimal, - }, - }; - - // vulkan image descriptors are for writing textures - std::vector - material_textures = { - // layout(set = 1, binding = 1) uniform sampler2D - vk::write_image_descriptor{ - .dst_binding = 1, - .sample_images = binding1_images, - }, - // layout(set = 1, binding = 2) uniform sampler2D - vk::write_image_descriptor{ - .dst_binding = 2, - .sample_images = binding2_images, - }, - }; - - m_mesh_descriptors[p_entity.id()]["materials"].update( - material_uniforms, material_textures); - - m_sets_layouts.push_back( - m_mesh_descriptors[p_entity.id()]["materials"].layout()); - } - }); - - std::vector modules = m_shader_group.handles(); - - std::array - color_blend_attachments = { - vk::color_blend_attachment_state{}, - }; - - std::array dynamic_states = { - vk::dynamic_state::viewport, vk::dynamic_state::scissor - }; - - vk::pipeline_params pipeline_configuration = { - .renderpass = m_final_renderpass, - .shader_modules = modules, - .vertex_attributes = m_shader_group.vertex_attributes(), - .vertex_bind_attributes = - m_shader_group.vertex_bind_attributes(), - .descriptor_layouts = m_sets_layouts, - .color_blend = { - .attachments = color_blend_attachments, - }, - .depth_stencil_enabled = true, - .dynamic_states = dynamic_states, - }; - m_main_pipeline = vk::pipeline(m_device, pipeline_configuration); - - console_log_warn("graphics pipeline = {}", m_main_pipeline.alive()); - } - - void start_frame(const vk::command_buffer& p_current, - const window_params& p_settings, - const vk::renderpass& p_renderpass, - const VkFramebuffer& p_framebuffer, - const glm::mat4& p_projection, - const glm::mat4& p_view, - uint32_t p_current_frame) override { - m_proj_view = p_projection * p_view; - m_skybox_proj_view = p_projection * glm::mat4(glm::mat3(p_view)); - - m_current_frame = p_current_frame; - m_final_renderpass = p_renderpass; - - std::array clear_values = {}; - - clear_values[0].color = m_color; - clear_values[1].depthStencil = { 1.f, 0 }; - m_window_extent = p_settings; - - VkRenderPassBeginInfo renderpass_begin_info = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .pNext = nullptr, - .renderPass = p_renderpass, - .renderArea = { - .offset = { - .x = 0, - .y = 0 - }, - .extent = { - .width = p_settings.width, - .height = p_settings.height - }, - }, - .clearValueCount = static_cast(clear_values.size()), - .pClearValues = clear_values.data() - }; - - m_current_command_buffer = p_current; - m_current_command_buffer.begin( - vk::command_usage::simulatneous_use_bit); - - VkViewport viewport = { - .x = 0.0f, - .y = 0.0f, - .width = static_cast(m_window_extent.width), - .height = static_cast(m_window_extent.height), - .minDepth = 0.0f, - .maxDepth = 1.0f, - }; - - vkCmdSetViewport(m_current_command_buffer, 0, 1, &viewport); - - VkRect2D scissor = { - .offset = { 0, 0 }, - .extent = { m_window_extent.width, m_window_extent.height }, - }; - - vkCmdSetScissor(m_current_command_buffer, 0, 1, &scissor); - - renderpass_begin_info.framebuffer = p_framebuffer; - - vkCmdBeginRenderPass(m_current_command_buffer, - &renderpass_begin_info, - VK_SUBPASS_CONTENTS_INLINE); - } - - void background_color(const glm::vec4& p_color) override { - m_color = { - { p_color.x, p_color.y, p_color.z, p_color.w }, - }; - } - - void post_frame() override { - // For now, using this. Will need to remove this before vulkan - // integration merging into dev This is for testing and to hopefully - // have a global_ubo for globalized uniforms - global_ubo global_frame_ubo = { .mvp = m_proj_view }; - - // TODO: Make to_bytes be part of utilities. This can be useful in - // sending the amount of bytes in batches for batch-rendering - // std::span bytes_data = to_bytes(global_frame_ubo); - // m_global_uniforms.update(bytes_data.data()); - m_global_uniforms.update(&global_frame_ubo); - - skybox_uniform skybox_ubo = { - .proj_view = m_skybox_proj_view, - }; - - m_skybox.update_uniform(skybox_ubo); - - // query all entities that have a point light - flecs::query query_point_lights = - m_current_scene->query_builder().build(); - - light_scene_ubo test_light = {}; - uint32_t index = 0; - query_point_lights.each( - [&index, &test_light](flecs::entity p_entity, - point_light& p_light) { - const transform* t = p_entity.get(); - p_light.position = t->position; - - test_light.light_sources[index] = { - .position = glm::vec4(p_light.position, 1.f), - .color = p_light.color, - .attenuation = p_light.attenuation, - .constant = p_light.constant, - .linear = p_light.linear, - .quadratic = p_light.quadratic, - .ambient = p_light.ambient, - .diffuse = p_light.diffuse, - .specular = p_light.specular, - }; - index += 1; - }); - test_light.num_lights = index; - - m_point_light_uniforms.update(&test_light); - - // query all objects with a specified 3d mesh source - flecs::query<> query_targets = - m_current_scene->query_builder().build(); - - m_main_pipeline.bind(m_current_command_buffer); - - // Bind global camera data here - m_global_descriptors.bind(m_current_command_buffer, - m_main_pipeline.layout()); - query_targets.each([this](flecs::entity p_entity) { - const transform* transform_component = - p_entity.get(); - const mesh_source* material_component = - p_entity.get(); - m_model = glm::mat4(1.f); - m_model = - glm::translate(m_model, transform_component->position); - m_model = glm::scale(m_model, transform_component->scale); - glm::mat4 rotation_mat4 = - glm::mat4(glm::quat(transform_component->rotation)); - - m_model *= rotation_mat4; - - // Mesh used for viking_room - replaced with std::map equivalent - geometry_uniform mesh_ubo = { .model = m_model, - .color = - material_component->color }; - - if (m_cached_meshes[p_entity.id()].loaded()) { - m_mesh_geometry_set[p_entity.id()].update(&mesh_ubo); - - material_metadata data = {}; - - if (p_entity.has()) { - data = *p_entity.get(); - } - m_mesh_material_set[p_entity.id()].update(&data); - - m_mesh_descriptors[p_entity.id()]["materials"].bind( - m_current_command_buffer, m_main_pipeline.layout()); - - m_cached_meshes[p_entity.id()].draw( - m_current_command_buffer); - } - }); - - m_skybox.bind(m_current_command_buffer); - m_skybox.draw(m_current_command_buffer); - - vkCmdEndRenderPass(m_current_command_buffer); - // Do not end the command buffer here when using offscreen + - // swapchain two-pass: the application will begin the swapchain - // render pass for ImGui, then end the command buffer. - // m_current_command_buffer.end(); - } - - void current_scene(ref p_scene_ctx) override { - m_current_scene = p_scene_ctx; - } - - void render_invalidate_mesh(uint32_t p_entity_id, - std::filesystem::path p_filename) override { - m_cached_meshes[p_entity_id].reload_mesh(p_filename); - } - - private: - VkDevice m_device = nullptr; - physical_device m_physical; - glm::mat4 m_proj_view; - glm::mat4 m_skybox_proj_view; - vk::renderpass m_final_renderpass; - window_params m_window_extent; - vk::command_buffer m_current_command_buffer{}; - VkClearColorValue m_color; - - uint32_t m_image_count = 0; - shader_resource_group m_shader_group; - vk::pipeline m_main_pipeline; - vk::descriptor_resource m_global_descriptors; - std::vector m_sets_layouts; - - std::map m_cached_meshes; - vk::uniform_buffer m_global_uniforms; - vk::uniform_buffer m_point_light_uniforms; - - // game object-specific meshes - std::map m_mesh_geometry_set; - // TODO: Make this into a material system, eventually - std::map m_mesh_material_set; - std::map> - m_mesh_descriptors; - uint32_t m_current_frame = 0; - glm::mat4 m_model = { 1.f }; - - vk::texture m_white_texture; - - environment_map m_skybox; - - ref m_current_scene; - }; -}; diff --git a/atlas/drivers/vulkan/shader_resource_group.cppm b/atlas/drivers/vulkan/shader_resource_group.cppm deleted file mode 100644 index 75b41916..00000000 --- a/atlas/drivers/vulkan/shader_resource_group.cppm +++ /dev/null @@ -1,442 +0,0 @@ -module; - -#include -#include -#include -#include -#include - -export module atlas.drivers.vulkan.shader_resource_group; - -import atlas.logger; -import vk; - -namespace atlas::vulkan { - // Reading the raw .spv binaries - static std::vector read_raw_spirv(const std::string& p_file) { - std::vector out_buffer; - std::ifstream ins(p_file, std::ios::ate | std::ios::binary); - - if (!ins) { - throw std::runtime_error("Cannot load in .spv files!!"); - } - - uint32_t file_size = (uint32_t)ins.tellg(); - out_buffer.resize(file_size); - ins.seekg(0); - ins.read(out_buffer.data(), file_size); - return out_buffer; - } - - //! @brief Ensure file reads are valid before reading raw .spv binaries - static std::vector compile_binary_shader_source( - const ::vk::shader_source& p_shader_source) { - - if (!std::filesystem::is_regular_file(p_shader_source.filename)) { - throw std::runtime_error("Cannot load .spv file"); - } - - return read_raw_spirv(p_shader_source.filename); - } - -#if ENABLE_SHADERC - static std::string read_shader_source_code(const std::string& p_filename) { - std::ifstream ins(p_filename, std::ios::ate | std::ios::binary); - - if (!ins.is_open()) { - console_log_warn("Could not open filename = {}", p_filename); - return { 'a' }; - } - - size_t file_size = (size_t)ins.tellg(); - std::string output; - output.resize(file_size); - ins.seekg(0); - ins.read(output.data(), static_cast(file_size)); - - return output; - } -#endif - - /** - * compiles source code from the shader directly without needing manual - * recompilation - * - * shaderc requires these parameters to compile - * text_source_code: the std::string version of the entire source code to - * compile type: shader stage this shader corresponds to filename: input - * filename text entry_point: the entry point to this shader options: - * compiler-specific options to enable when compiling the shader sources - */ -#if ENABLE_SHADERC - static std::vector compile_source_from_file( - const ::vk::shader_source& p_shader_source) { - shaderc::CompileOptions options; - options.SetTargetEnvironment(shaderc_target_env_vulkan, - shaderc_env_version_vulkan_1_3); - options.SetWarningsAsErrors(); - - shaderc_shader_kind type; - - switch (p_shader_source.stage) { - case ::vk::shader_stage::vertex: - type = shaderc_glsl_vertex_shader; - break; - case ::vk::shader_stage::fragment: - type = shaderc_glsl_fragment_shader; - break; - default: - throw std::runtime_error("shader_stage unspecified!~!!"); - } - - shaderc::Compiler compiler; - std::string text_source_code = - read_shader_source_code(p_shader_source.filename); - - // Prints out the text of the shader source code - // console_log_warn("Source Text Code!!!"); - // console_log_info("{}", text_source_code); - shaderc::CompilationResult result = - compiler.CompileGlslToSpv(text_source_code, - type, - p_shader_source.filename.c_str(), - "main", - options); - - std::vector blob; - - if (result.GetCompilationStatus() != - shaderc_compilation_status_success) { - throw std::runtime_error( - std::format("Shader Compilation Error! Failed with reason {}\n{}", - p_shader_source.filename, - result.GetErrorMessage()) - .c_str()); - } - - for (auto blob_chunk : result) { - blob.push_back(blob_chunk); - } - - return blob; - } -#endif - /** - * @brief resource group for loading shader sources that give you back - * VkShaderModule handles - * - * Responsibility is to load stages of shader sources whether that be - * through precompiler .spv files or through shaderc runtime shader - * compilation - * - * Responsibility is loading and streaming the amount of bytes from the - * compiled shader sources into the vulkan shader module handles - * - * resource groups up the creation and management of vulkan shader modules. - */ - export class shader_resource_group { - public: - shader_resource_group() = default; - /** - * @brief constructs a new shader_resource_group - * - * @param p_device is the logical device required to creating the vulkan - * shader module - * @param p_info has the properties such as specified shader sources to - * load/compile - */ - shader_resource_group(const VkDevice& p_device, - const ::vk::shader_resource_info& p_info) - : m_device(p_device) { - - // We go through all of the specified shader source and their - // specific stage Compile them through shader compiler or if - // provided a .spv, then we compile and read in the stream of bytes - // directly - for (size_t i = 0; i < p_info.sources.size(); i++) { - const vk::shader_source shader_src = p_info.sources[i]; - std::filesystem::path filepath = - std::filesystem::path(shader_src.filename); -#ifndef ENABLE_SHADERC - if (filepath.extension().string() == ".spv") { - std::vector blob = - compile_binary_shader_source(shader_src); - - if (blob.empty()) { - m_resource_valid = false; - throw std::runtime_error( - "Cannot load in vector " - "blob of compiled down data!!!"); - } - - create_module(blob, shader_src); - } -#endif - -#ifdef ENABLE_SHADERC - if (filepath.extension().string() != ".spv") { - std::string text_source_code = - read_shader_source_code(filepath.string()); - std::vector blob = - compile_source_from_file(shader_src); - create_module(blob, shader_src); - } -#endif - } - } - - ~shader_resource_group() = default; - - /** - * @return true if resources are valid, otherwise return false - */ - [[nodiscard]] bool valid() const { return m_resource_valid; } - - /** - * @brief sets the vertex attributes with the shader modules that gets - * used by ::vk::pipeline (graphics pipeline) - * - * @param p_attributes is the high-level specifications for setting up - * vertex attributes that correspond with these shaders - */ - void vertex_attributes( - std::span p_attributes) { - /* - -- These comments are a reminder to myself -- - - this function simplifies the need to separately define vertex - attributes and the vertex binding attributes as shown below: - - - vertex attributes specify the types of data within the vertex - - - vertex binding attribute specifies the rate of reading that - data layout specified by the vertex attributes - - - Interpret the following vertex attributes below with this - shader code with `layout(location = n)` specified where by default - these are set to binding zero by the shader - - layout(location = 0) in vec3 inPosition; - layout(location = 1) in vec3 inColor; - layout(location = 2) in vec3 inNormals; - layout(location = 3) in vec2 inTexCoords; - - m_shader_group.set_vertex_attributes(VkVertexInputAttributeDescription{ - { .location = 0, .binding = 0, .format = - VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vk::vertex, - position), - }, { .location = 1, .binding = 0, .format = - VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vk::vertex, color), - }, { .location = 2, .binding = 0, .format = - VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vk::vertex, normals), - }, { .location = 3, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, - .offset = offsetof(vk::vertex, uv), }, - }); - - m_shader_group.set_vertex_bind_attributes(VkVertexInputBindingDescription{ - {.binding = 0, .stride = sizeof(vk::vertex), .inputRate = - VK_VERTEX_INPUT_RATE_VERTEX,}, - }); - - Which gets handled in specifying the following below - */ - - m_vertex_binding_attributes.resize(p_attributes.size()); - - for (size_t i = 0; i < m_vertex_binding_attributes.size(); i++) { - // setting up vertex binding - const ::vk::vertex_attribute attribute = p_attributes[i]; - m_vertex_attributes.resize(attribute.entries.size()); - m_vertex_binding_attributes[i] = { .binding = attribute.binding, - .stride = attribute.stride, - .inputRate = to_input_rate( - attribute.input_rate) }; - - // then setting up the vertex attributes for the vertex data - // layouts - for (size_t j = 0; j < attribute.entries.size(); j++) { - const ::vk::vertex_attribute_entry entry = - attribute.entries[j]; - m_vertex_attributes[j] = { .location = entry.location, - .binding = attribute.binding, - .format = static_cast( - entry.format), - .offset = entry.stride }; - } - } - } - - /** - * @brief this gives you back the shader module handles along with each - * of their stages they have been compiled with - * - * Returns the vector to retain the shader modules that are needed by - * the graphics pipeline. - * - * It is required by vulkan specs the graphics pipeline to contain valid - * shader modules of the compiled shaders - * - * @return vector<::vk::shader_handle> - */ - [[nodiscard]] std::vector<::vk::shader_handle> handles() const { - return map_to_vector(); - } - - /** - * @return span - */ - [[nodiscard]] std::span - vertex_attributes() const { - return m_vertex_attributes; - } - - /** - * @return span - */ - [[nodiscard]] std::span - vertex_bind_attributes() const { - return m_vertex_binding_attributes; - } - - /** - * @brief explicit cleanup to the VkShaderModule handles created with - * this particular resource group - */ - void destroy() { - for (auto& [filename, shader_handle] : m_modules) { - if (shader_handle.module != nullptr) { - vkDestroyShaderModule( - m_device, shader_handle.module, nullptr); - } - } - } - - /** - * @brief ideally used for requesting for reload - * - * Planning to use this for invalidation when for runtime shader - * hot-reloading - * - * @note this is not used at the moment as shader runtime hot reloading - * is currently not supported. - */ - [[nodiscard]] bool reload_requested() const { - return m_reload_requested; - } - - private: - /** - * converts unordered_map to - * vector - */ - [[nodiscard]] std::vector<::vk::shader_handle> map_to_vector() const { - // Using C++'s std::views to extract all of the values in - // unordered_map to a - // vector that gets passed to graphics pipeline TEMP: - // Removing this. Will add this back in later. return (m_modules | - // std::views::values | - // std::ranges::to()); - std::vector<::vk::shader_handle> result; - - result.reserve(m_modules.size()); - - for (auto const& [name, handle] : m_modules) { - result.push_back(handle); - } - - return result; - } - - void create_module(std::span p_blob, - const ::vk::shader_source& p_source) { - VkShaderModuleCreateInfo shader_module_ci = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .codeSize = p_blob.size(), - .pCode = reinterpret_cast(p_blob.data()) - }; - - std::filesystem::path filepath(p_source.filename); - std::string filename = filepath.filename().string(); - - // Setting m_shader_module_handlers[i]'s stage and the - // VkShaderModule handle altogether construct this beforehand and - // then we are going set that shader module - m_modules.emplace(filename, ::vk::shader_handle{}); - ::vk::vk_check(vkCreateShaderModule(m_device, - &shader_module_ci, - nullptr, - &m_modules[filename].module), - "vkCreateShaderModule"); - m_modules[filename].stage = p_source.stage; - } - - void create_module(std::span p_blob, - const ::vk::shader_source& p_source) { - VkShaderModuleCreateInfo shader_module_ci = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .codeSize = p_blob.size_bytes(), - .pCode = p_blob.data() - }; - - // console_log_info("map key = {}", p_source.filename); - std::filesystem::path filepath(p_source.filename); - - std::string filename = filepath.filename().string(); - - console_log_info("Key = {}", filename); - - // Setting m_shader_module_handlers[i]'s stage and the - // VkShaderModule handle altogether construct this beforehand and - // then we are going set that shader module - m_modules.emplace(filename, ::vk::shader_handle{}); - ::vk::vk_check(vkCreateShaderModule(m_device, - &shader_module_ci, - nullptr, - &m_modules[filename].module), - "vkCreateShaderModule"); - m_modules[filename].stage = p_source.stage; - } - - /* - // TODO: Re-add this when shaderc works again. - void reload_shader(const ::vk::shader_source& p_source) { - console_log_info("p_source.filename = {}", p_source.filename); - if (m_modules[p_source.filename].module != nullptr) { - vkDestroyShaderModule( - m_device, m_modules[p_source.filename].module, nullptr); - } - - auto& handle = m_modules[p_source.filename]; - - std::filesystem::path filepath(p_source.filename); - std::string text_source_code = - read_shader_source_code(filepath.string()); - std::vector blob = compile_source_from_file(p_source); - std::span view_blob(blob.data(), blob.size()); - // create_module(blob, p_source); - VkShaderModuleCreateInfo shader_module_ci = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .codeSize = view_blob.size_bytes(), - .pCode = view_blob.data() - }; - - ::vk::vk_check(vkCreateShaderModule( - m_device, &shader_module_ci, nullptr, - &handle.module), "vkCreateShaderModule"); - } - */ - - private: - VkDevice m_device = nullptr; - std::vector m_vertex_attributes; - std::vector - m_vertex_binding_attributes; - bool m_resource_valid = false; - // shader module handles - std::unordered_map m_modules; - // ref m_watcher; - bool m_reload_requested = false; - }; -}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/stb_image.cppm b/atlas/drivers/vulkan/stb_image.cppm new file mode 100644 index 00000000..26fe7a7b --- /dev/null +++ b/atlas/drivers/vulkan/stb_image.cppm @@ -0,0 +1,91 @@ +module; + +#include +#include +#include +#include +#include + +#ifndef STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#include +#endif + +export module atlas.drivers.vulkan:stb_image; + +import vk; + +export namespace atlas { + + /** + * @brief Implementing image loading that utilizes stb_image to decode + * disk-based images into uncompressed streams of bytes. + * + * Provides size extents of uncompressed of the total image size. + * + */ + class stb_image : public vk::image { + public: + stb_image() = default; + + stb_image(std::string_view p_path, const vk::texture_params& p_params) { + image_load(p_path, p_params); + } + + ~stb_image() = default; + + protected: + bool image_load(std::string_view p_path, + vk::texture_params p_params) override { + int w = 0; + int h = 0; + int channels = 0; + + stbi_uc* image_pixel_data = + stbi_load(p_path.data(), &w, &h, &channels, STBI_rgb_alpha); + + if (!image_pixel_data) { + return false; + } + + const VkFormat texture_format = + static_cast(vk::format::r8g8b8a8_unorm); + int bytes_per_pixel = vk::bytes_per_texture_format(texture_format); + + m_extent = { + .width = static_cast(w), + .height = static_cast(h), + }; + + // Retrieving total size of bytes of the dimensions of the image and + // accounting for pixels of the image + uint32_t size_bytes = + m_extent.width * m_extent.height * bytes_per_pixel; + + // Retrieving total image size to the count of the image layers + uint32_t size = size_bytes * p_params.layer_count; + + m_bytes.reserve(size); + std::span bytes_view = + std::span(image_pixel_data, size); + + m_bytes.assign(bytes_view.begin(), bytes_view.end()); + + stbi_image_free(image_pixel_data); + + return true; + } + + [[nodiscard]] std::span image_read() const override { + return m_bytes; + } + + [[nodiscard]] vk::image_extent image_extent() const override { + return m_extent; + } + + private: + vk::image_extent m_extent{}; + std::vector m_bytes{}; + }; +}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/swapchain.cppm b/atlas/drivers/vulkan/swapchain.cppm deleted file mode 100644 index 66fbc51a..00000000 --- a/atlas/drivers/vulkan/swapchain.cppm +++ /dev/null @@ -1,352 +0,0 @@ -module; - -#include -#include -#include - -export module atlas.drivers.vulkan.swapchain; - -import vk; - -// import atlas.logger; -// import atlas.core.utilities.types; -import atlas.core.utilities; -import atlas.drivers.vulkan.instance_context; -import atlas.drivers.vulkan.physical_device; -import atlas.drivers.vulkan.device; -import atlas.drivers.vulkan.utilities; - -export namespace atlas::vulkan { - /** - * @name vk_swapchain - * @brief High-level abstraction of a vulkan swapchain - * @brief ref will return the vk_swapchain directly - * @brief ref returning vk_swapchain will need to be changed - */ - class swapchain { - public: - swapchain() = default; - - /** - * @brief Constructs a new vulkan swapchain with a window settings to - * apply to this swapchain - * @param p_surface passing in the surface handler for swapchain uses - */ - swapchain(const VkSurfaceKHR& p_surface, const window_params& p_params) - : m_current_surface_handler(p_surface) - , m_window_params(p_params) - , m_current_surface(p_surface) { - m_physical = instance_context::physical_driver(); - m_driver = instance_context::logical_device(); - - create(); - - console_log_info_tagged("vulkan", - "swapchain created successfully!!!"); - } - - //! @return uint32_t the next available image to present acquired - uint32_t read_acquired_image() { - m_present_to_queue.wait_idle(); - - // uint32_t frame_idx = m_present_to_queue.acquired_frame(); - uint32_t frame_idx = m_present_to_queue.acquire_next_image(); - if (m_present_to_queue.out_of_date()) { - invalidate(); - m_present_to_queue.out_of_date(false); - frame_idx = m_present_to_queue.acquire_next_image(); - } - - return frame_idx; - } - - //! @return current active command buffer being processed - [[nodiscard]] vk::command_buffer active_command( - uint32_t p_frame_index) { - return m_swapchain_command_buffers[p_frame_index]; - } - - [[nodiscard]] VkFramebuffer active_framebuffer(uint32_t p_frame) const { - return m_swapchain_framebuffers[p_frame]; - } - - [[nodiscard]] vk::renderpass swapchain_renderpass() const { - return m_final_renderpass; - } - - [[nodiscard]] window_params settings() const { return m_window_params; } - - [[nodiscard]] uint32_t image_size() const { return m_image_size; } - - [[nodiscard]] surface_properties data() const { - return m_surface_properties; - } - - void destroy() { - vkDeviceWaitIdle(m_driver); - - for (size_t i = 0; i < m_swapchain_framebuffers.size(); i++) { - m_swapchain_framebuffers[i].destroy(); - } - - m_final_renderpass.destroy(); - - m_present_to_queue.destroy(); - - for (size_t i = 0; i < m_swapchain_command_buffers.size(); i++) { - m_swapchain_command_buffers[i].destroy(); - } - - for (uint32_t i = 0; i < m_swapchain_depth_images.size(); i++) { - m_swapchain_depth_images[i].destroy(); - } - - for (uint32_t i = 0; i < m_swapchain_images.size(); i++) { - m_swapchain_images[i].destroy(); - } - - vkDestroySwapchainKHR(m_driver, m_swapchain_handler, nullptr); - } - - void submit(std::span p_commands) { - m_present_to_queue.submit_async(p_commands); - } - - [[nodiscard]] ::vk::sample_image active_image(uint32_t p_index) const { - return m_swapchain_images[p_index]; - } - - operator VkSwapchainKHR() const { return m_swapchain_handler; } - - operator VkSwapchainKHR() { return m_swapchain_handler; } - - void present(const uint32_t& p_current_frame) { - m_present_to_queue.present_frame(p_current_frame); - if (m_present_to_queue.out_of_date()) { - invalidate(); - m_present_to_queue.out_of_date(false); - } - } - - private: - void invalidate() { - destroy(); - create(); - } - - void create() { - // surface properties are always updated from the physical device - // so they are valid should the swapchain be recreated - m_surface_properties = - m_physical.get_surface_properties(m_current_surface); - m_window_params.width = - m_surface_properties.surface_capabilities.currentExtent.width; - m_window_params.height = - m_surface_properties.surface_capabilities.currentExtent.height; - - //! @note Setting up presentation stuff - // request what our minimum image count is - uint32_t request_min_image_count = - select_images_size(m_surface_properties.surface_capabilities); - - m_swapchain_extent = - m_surface_properties.surface_capabilities.currentExtent; - - // setting our presentation properties - uint32_t present_index = - m_physical.read_presentation_index(m_current_surface_handler); - - VkSwapchainCreateInfoKHR swapchain_ci = { - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .surface = m_current_surface_handler, - .minImageCount = request_min_image_count, - .imageFormat = m_surface_properties.surface_format.format, - .imageColorSpace = - m_surface_properties.surface_format.colorSpace, - // use physical device surface formats to getting the right - // formats in vulkan - .imageExtent = m_swapchain_extent, - .imageArrayLayers = 1, - .imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT), - .queueFamilyIndexCount = 1, - .pQueueFamilyIndices = &present_index, - .preTransform = - m_surface_properties.surface_capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = VK_PRESENT_MODE_FIFO_KHR, - .clipped = true - }; - - vk_check(vkCreateSwapchainKHR( - m_driver, &swapchain_ci, nullptr, &m_swapchain_handler), - "vkCreateSwapchainKHR"); - - //!@brief querying images available - uint32_t image_count = 0; - vkGetSwapchainImagesKHR( - m_driver, - m_swapchain_handler, - &image_count, - nullptr); // used to get the amount of images - std::vector images(image_count); - vkGetSwapchainImagesKHR( - m_driver, - m_swapchain_handler, - &image_count, - images.data()); // used to store in the images - - // Creating Images - m_swapchain_images.resize(image_count); - m_image_size = image_count; - m_swapchain_depth_images.resize(image_count); - - VkFormat depth_format = m_driver.depth_format(); - - for (uint32_t i = 0; i < m_swapchain_images.size(); i++) { - ::vk::image_params color_image_config = { - .extent = { m_swapchain_extent.width, - m_swapchain_extent.height, }, - .format = m_surface_properties.surface_format.format, - .aspect = ::vk::image_aspect_flags::color_bit, - .usage = vk::image_usage::color_attachment_bit, - .mip_levels = 1, - .layer_count = 1, - .phsyical_memory_properties = m_physical.memory_properties(), - - }; - - m_swapchain_images[i] = - ::vk::sample_image(m_driver, images[i], color_image_config); - - ::vk::image_params depth_image_config = { - .extent = { m_swapchain_extent.width, - m_swapchain_extent.height, }, - .format = depth_format, - .aspect = ::vk::image_aspect_flags::depth_bit, - .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - .mip_levels = 1, - .layer_count = 1, - .phsyical_memory_properties = m_physical.memory_properties(), - }; - - m_swapchain_depth_images[i] = - ::vk::sample_image(m_driver, depth_image_config); - } - - // command buffers - - m_swapchain_command_buffers.resize(image_count); - - for (size_t i = 0; i < m_swapchain_command_buffers.size(); i++) { - ::vk::command_params settings = { - .levels = ::vk::command_levels::primary, - // .queue_index = - // enumerate_swapchain_settings.present_index, - .queue_index = 0, - .flags = ::vk::command_pool_flags::reset, - }; - - m_swapchain_command_buffers[i] = - ::vk::command_buffer(m_driver, settings); - } - - std::array<::vk::attachment, 2> renderpass_attachments = { - ::vk::attachment{ - .format = m_surface_properties.surface_format.format, - .layout = ::vk::image_layout::color_optimal, - .samples = ::vk::sample_bit::count_1, - .load = ::vk::attachment_load::clear, - .store = ::vk::attachment_store::store, - .stencil_load = ::vk::attachment_load::clear, - .stencil_store = ::vk::attachment_store::dont_care, - .initial_layout = ::vk::image_layout::undefined, - .final_layout = ::vk::image_layout::present_src_khr, - }, - ::vk::attachment{ - .format = depth_format, - .layout = ::vk::image_layout::depth_stencil_optimal, - .samples = ::vk::sample_bit::count_1, - .load = ::vk::attachment_load::clear, - .store = ::vk::attachment_store::dont_care, - .stencil_load = ::vk::attachment_load::dont_care, - .stencil_store = ::vk::attachment_store::dont_care, - .initial_layout = ::vk::image_layout::undefined, - .final_layout = ::vk::image_layout::depth_stencil_optimal, - }, - }; - m_final_renderpass = - ::vk::renderpass(m_driver, renderpass_attachments); - - // creating framebuffers - m_swapchain_framebuffers.resize(m_swapchain_images.size()); - - for (uint32_t i = 0; i < m_swapchain_images.size(); i++) { - - std::array - image_attachments = { - m_swapchain_images[i].image_view(), - m_swapchain_depth_images[i].image_view() - }; - - vk::framebuffer_params framebuffer_info = { - .renderpass = m_final_renderpass, - .views = image_attachments, - .extent = m_swapchain_extent - }; - m_swapchain_framebuffers[i] = - vk::framebuffer(m_driver, framebuffer_info); - } - - vk::queue_params present_queue_params{ - .family = 0, - .index = 0, - }; - m_present_to_queue = ::vk::device_present_queue( - m_driver, m_swapchain_handler, present_queue_params); - console_log_info("m_present_to_queue initialized!!!"); - console_log_info("m_presesnt_to_queue.alive() = {}", - (m_present_to_queue != nullptr)); - } - - uint32_t select_images_size( - const VkSurfaceCapabilitiesKHR& p_surface_capabilities) { - uint32_t requested_images = - p_surface_capabilities.minImageCount + 1; - uint32_t final_image_count = 0; - - if ((p_surface_capabilities.maxImageCount > 0) and - (requested_images > p_surface_capabilities.maxImageCount)) { - final_image_count = p_surface_capabilities.maxImageCount; - } - else { - final_image_count = requested_images; - } - - return final_image_count; - } - - private: - physical_device m_physical{}; - device m_driver{}; - VkSurfaceKHR m_current_surface_handler = nullptr; - VkSwapchainKHR m_swapchain_handler = nullptr; - VkExtent2D m_swapchain_extent{}; - window_params m_window_params{}; - - uint32_t m_image_size = 0; - - VkSurfaceKHR m_current_surface = nullptr; - surface_properties m_surface_properties{}; - std::vector m_swapchain_command_buffers{}; - std::vector m_swapchain_framebuffers; - - //! @brief setting up images - std::vector m_swapchain_images; - std::vector m_swapchain_depth_images; - - vk::renderpass m_final_renderpass; - - vk::device_present_queue m_present_to_queue; - }; -}; diff --git a/atlas/drivers/vulkan/uniforms.cppm b/atlas/drivers/vulkan/uniforms.cppm deleted file mode 100644 index 79c786ee..00000000 --- a/atlas/drivers/vulkan/uniforms.cppm +++ /dev/null @@ -1,75 +0,0 @@ -module; - -#include -#include - -export module atlas.drivers.vulkan.uniforms; - -import vk; - -export namespace atlas::vulkan { - struct vertex_input { - glm::vec3 position; - glm::vec3 color; - glm::vec3 normals; - glm::vec2 uv; - - bool operator==(const vertex_input& other) const { - return position == other.position and color == other.color and - uv == other.uv and normals == other.normals; - } - }; - - //! @brief Going to remove this - //! @brief This is being used by descriptor sets and vk_renderer - //! TODO: Modify vk_descriptor_set and vk_renderer and add uniforms.hpp - //! inside renderer/ (dir) for used across vk_renderer and the renderer - struct camera_ubo { - glm::mat4 projection{ 1.f }; - glm::mat4 view{ 1.f }; - }; - - //! @brief Just for testing purposes for sending this struct over to the - //! shader - struct global_ubo { - glm::mat4 mvp = { 1.f }; - }; - - /** - * @brief material is going to define properties about how a scene object - * itself gets rendered - * - */ - struct geometry_uniform { - glm::mat4 model{ 1.f }; - glm::vec4 color{ 1.f }; - }; - - /** - * @brief Represents a vulkan specific mateiral to pass in two textures and - * offset for handling shininess - */ - struct material_uniform { - float shininess = 1.f; - vk::texture diffuse; - vk::texture specular; - }; - - struct point_light_ubo { - glm::vec4 position; // this is provided by the transform - glm::vec4 color = { 1.f, 1.f, 1.f, 1.f }; - float attenuation = 1.f; - float constant = 1.f; - float linear = 1.f; - float quadratic = 1.f; - - glm::vec4 ambient = glm::vec4(1.f); - glm::vec4 diffuse = glm::vec4(1.f); - glm::vec4 specular = glm::vec4(1.f); - }; - - struct light_scene_ubo { - alignas(16) uint32_t num_lights; - alignas(16) std::array light_sources; - }; -}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/utilities.cppm b/atlas/drivers/vulkan/utilities.cppm index ee23cf15..f7cb0ec1 100644 --- a/atlas/drivers/vulkan/utilities.cppm +++ b/atlas/drivers/vulkan/utilities.cppm @@ -4,7 +4,8 @@ module; #include export module atlas.drivers.vulkan.utilities; -import atlas.logger; + +import atlas.core.utilities; export namespace atlas { namespace vulkan { diff --git a/atlas/drivers/vulkan/vulkan.cppm b/atlas/drivers/vulkan/vulkan.cppm new file mode 100644 index 00000000..4aaae17e --- /dev/null +++ b/atlas/drivers/vulkan/vulkan.cppm @@ -0,0 +1,9 @@ +module; + +export module atlas.drivers.vulkan; + +export import :window; +export import :graphics_context; +export import :render_context; +export import :imgui_context; +export import :stb_image; \ No newline at end of file diff --git a/atlas/drivers/vulkan/window.cppm b/atlas/drivers/vulkan/window.cppm new file mode 100644 index 00000000..21d8e88c --- /dev/null +++ b/atlas/drivers/vulkan/window.cppm @@ -0,0 +1,163 @@ +module; + +#include +#include +#include +#include +#include + +#define GLFW_INCLUDE_VULKAN +#if _WIN32 +#define VK_USE_PLATFORM_WIN32_KHR +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include +#else +#include +#include +#endif + +export module atlas.drivers.vulkan:window; + +import atlas.core.utilities; +import vk; +import :graphics_context; + +export namespace atlas { + + class window { + public: + window() = default; + window(/*NOLINT*/ std::shared_ptr p_context, + const window_params& p_params) + : m_device(p_context->logical_device()) { + m_instance = p_context->instance_handle(); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + m_window = glfwCreateWindow(static_cast(p_params.width), + static_cast(p_params.height), + p_params.name.c_str(), + nullptr, + nullptr); + + glfwMakeContextCurrent(m_window); + + m_surface = std::make_shared( + p_context->instance_handle(), m_window); + + int framebuffer_width = 0; + int framebuffer_height = 0; + glfwGetFramebufferSize( + m_window, &framebuffer_width, &framebuffer_height); + + // Weird issue where the frame buffer size is different then the + // window size. Causing majority of the portion of the window to + // render pink pixels, indicating an error. + m_params.width = static_cast(framebuffer_width); + m_params.height = static_cast(framebuffer_height); + + std::println("Window created with extent: {}x{}", + m_params.width, + m_params.height); + + vk::swapchain_params swapchain_params = { + .width = static_cast(m_params.width), + .height = static_cast(m_params.height), + .present_index = 0, + }; + + m_surface_properties = p_context->physical_device().request_surface( + *m_surface, VK_FORMAT_B8G8R8A8_UNORM); + + m_swapchain = + std::make_shared(*p_context->logical_device(), + *m_surface, + swapchain_params, + m_surface_properties); + + center_window(); + vk::queue_params present_params = { + .family = 0, + .index = 0, + }; + m_present_queue = vk::device_present_queue( + *p_context->logical_device(), *m_swapchain, present_params); + } + + ~window() { + // At the end of the lifetime of this window, we can destroy any + // resources that any of the concurrent resources this window + // owns is no longer using + m_surface->destruct(); + glfwDestroyWindow(m_window); + } + + [[nodiscard]] std::span request_images() const { + return m_swapchain->get_images(); + } + + [[nodiscard]] uint32_t acquire_next_frame() { + return m_present_queue.acquire_next_image(); + } + + void destruct() { + // Any dependent resources that must be invoked + // before the primary resources like VkSurfaceKHR + // are destructed + m_swapchain->destruct(); + m_present_queue.destruct(); + } + + [[nodiscard]] GLFWwindow* glfw_window() const { return m_window; } + + std::shared_ptr swapchain_handle() { + return m_swapchain; + } + + [[nodiscard]] vk::device_present_queue present_queue() const { + return m_present_queue; + } + + [[nodiscard]] vk::surface_params surface_properties() const { + return m_surface_properties; + } + + void center_window() { + int window_width = 0; + int window_height = 0; + glfwGetWindowSize(m_window, &window_width, &window_height); + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + int width = (mode->width / 2) - (window_width / 2); + int height = (mode->height / 2) - (window_height / 2); + glfwSetWindowPos(m_window, width, height); + } + + void submit(std::span p_commands) { + m_present_queue.submit_async(p_commands); + } + + void present(uint32_t p_frame_idx) { + m_present_queue.present_frame(p_frame_idx); + } + + [[nodiscard]] bool available() const { + return !glfwWindowShouldClose(m_window); + } + + [[nodiscard]] window_params extent() const { return m_params; } + + private: + vk::instance m_instance; + std::shared_ptr m_device = nullptr; + std::shared_ptr m_surface; + std::shared_ptr m_swapchain; + vk::surface_params m_surface_properties; + vk::device_present_queue m_present_queue; + GLFWwindow* m_window = nullptr; + window_params m_params{}; + }; +}; \ No newline at end of file diff --git a/atlas/drivers/vulkan/window_context.cppm b/atlas/drivers/vulkan/window_context.cppm deleted file mode 100644 index 49aa2325..00000000 --- a/atlas/drivers/vulkan/window_context.cppm +++ /dev/null @@ -1,135 +0,0 @@ -module; - -#include - -#define GLFW_INCLUDE_VULKAN -#if _WIN32 -#define VK_USE_PLATFORM_WIN32_KHR -#include -#define GLFW_EXPOSE_NATIVE_WIN32 -#include -#include -#else -#include -#include -#endif - -export module atlas.drivers.vulkan.window_context; - -// import atlas.logger; -// import atlas.core.utilities.types; -import atlas.core.utilities; -import vk; - -import atlas.window; -import atlas.drivers.graphics_context; -// import atlas.drivers.vulkan.instance_context; -import atlas.drivers.vulkan.utilities; -import atlas.drivers.vulkan.swapchain; - -export namespace atlas { - namespace vulkan { - /** - * @brief vulkan-backend implementation of the application-window - */ - class window_context : public window { - public: - window_context(ref p_context, - const window_params& p_params) - : m_params(p_params) { - - console_log_info("window_context constructed!!!"); - - if (!glfwVulkanSupported()) { - console_log_error("GLFW: Vulkan is not supported!!!"); - console_log_error("GLFW: Vulkan Supported = {}", - static_cast(glfwVulkanSupported())); - return; - } - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - - // m_instance = instance_context::handle(); - m_instance = p_context->handle(); - - m_window_handle = - glfwCreateWindow(static_cast(m_params.width), - static_cast(m_params.height), - m_params.name.c_str(), - nullptr, - nullptr); - - glfwMakeContextCurrent(m_window_handle); - - console_log_info("m_instance = {}", (m_instance == nullptr)); - - vk_check( - glfwCreateWindowSurface( - m_instance, m_window_handle, nullptr, &m_window_surface), - "glfwCreateWindowSurface"); - - center_window(); - - m_window_swapchain = swapchain(m_window_surface, m_params); - - p_context->submit_resource_free([this]() { - console_log_info("vulkan::window_context " - "submit_resource_free invokation!"); - m_window_swapchain.destroy(); - }); - } - - virtual ~window_context() { - if (m_window_surface != nullptr) { - vkDestroySurfaceKHR(m_instance, m_window_surface, nullptr); - } - glfwDestroyWindow(m_window_handle); - } - - protected: - [[nodiscard]] window_params get_params() const override { - return m_window_swapchain.settings(); - } - - [[nodiscard]] GLFWwindow* native_window() const override { - return m_window_handle; - } - - [[nodiscard]] uint32_t read_acquired_next_frame() override { - return m_window_swapchain.read_acquired_image(); - } - - [[nodiscard]] vulkan::swapchain window_swapchain() const override { - return m_window_swapchain; - } - - [[nodiscard]] vk::command_buffer current_active_command( - uint32_t p_frame_idx) override { - return m_window_swapchain.active_command(p_frame_idx); - } - - void present_frame(const uint32_t& p_current_frame) override { - m_window_swapchain.present(p_current_frame); - } - - private: - void center_window() { - GLFWmonitor* monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - uint32_t width = (mode->width / 2) - (m_params.width / 2); - uint32_t height = (mode->height / 2) - (m_params.height / 2); - glfwSetWindowPos(m_window_handle, - static_cast(width), - static_cast(height)); - } - - private: - GLFWwindow* m_window_handle = nullptr; - VkSurfaceKHR m_window_surface = nullptr; - window_params m_params; - VkInstance m_instance = nullptr; - swapchain m_window_swapchain; - }; - }; -}; \ No newline at end of file diff --git a/atlas/physics/physics_engine.cppm b/atlas/physics/physics_engine.cppm index 99717614..83831810 100644 --- a/atlas/physics/physics_engine.cppm +++ b/atlas/physics/physics_engine.cppm @@ -5,11 +5,11 @@ module; export module atlas.physics.engine; -import atlas.common; -import atlas.core.scene.components; +import atlas.core.utilities; +import atlas.core.scene; import atlas.core.event; import atlas.drivers.physics_context; -import atlas.drivers.jolt_cpp.context; +import atlas.drivers.jolt_cpp; namespace atlas::physics { diff --git a/atlas/renderer/context_loader.cppm b/atlas/renderer/context_loader.cppm deleted file mode 100644 index cc2836a5..00000000 --- a/atlas/renderer/context_loader.cppm +++ /dev/null @@ -1,28 +0,0 @@ -module; - -#include -#include - -export module atlas.renderer.context_loader; - -import atlas.core.utilities; - -import atlas.drivers.graphics_context; - -import atlas.drivers.vulkan.instance_context; - -export namespace atlas { - /** - * @brief construct a new graphics context and initializes that API - * @return shared_ptr - */ - ref initialize_context(const std::string& p_name, - graphics_api p_api) { - switch (p_api) { - case graphics_api::vulkan: - return create_ref(p_name); - default: - return nullptr; - } - } -}; \ No newline at end of file diff --git a/atlas/renderer/renderer.cppm b/atlas/renderer/renderer.cppm index ab1dfda5..0d646104 100644 --- a/atlas/renderer/renderer.cppm +++ b/atlas/renderer/renderer.cppm @@ -5,27 +5,4 @@ module; export module atlas.renderer; -import atlas.common; -import atlas.drivers.renderer_system; -import atlas.drivers.vulkan.render_system; -import atlas.common; -import atlas.graphics_api; -import atlas.drivers.graphics_context; -import atlas.core.utilities.types; - -export namespace atlas { - ref initialize_renderer( - ref p_context, - graphics_api p_api, - const window_params& p_window_extent, - uint32_t p_image_size, - const std::string& p_name) { - switch (p_api) { - case graphics_api::vulkan: - return create_ref( - p_context, p_window_extent, p_image_size, p_name); - default: - return nullptr; - } - } -}; \ No newline at end of file +export namespace atlas {}; \ No newline at end of file diff --git a/builtin.shaders/compile.bat b/builtin.shaders/compile.bat index d6fd90fe..7bd159b6 100644 --- a/builtin.shaders/compile.bat +++ b/builtin.shaders/compile.bat @@ -1,4 +1,6 @@ -glslc.exe builtin.shaders/test.vert -o builtin.shaders/test.vert.spv -glslc.exe builtin.shaders/test.frag -o builtin.shaders/test.frag.spv +@REM glslc.exe builtin.shaders/test.vert -o builtin.shaders/test.vert.spv +@REM glslc.exe builtin.shaders/test.frag -o builtin.shaders/test.frag.spv +glslc.exe builtin.shaders/pbr.vert -o builtin.shaders/pbr.vert.spv +glslc.exe builtin.shaders/pbr.frag -o builtin.shaders/pbr.frag.spv echo Finished Compiling GLSL Shaders \ No newline at end of file diff --git a/builtin.shaders/pbr.frag b/builtin.shaders/pbr.frag new file mode 100644 index 00000000..da09d0d0 --- /dev/null +++ b/builtin.shaders/pbr.frag @@ -0,0 +1,220 @@ +#version 450 + +#extension GL_EXT_nonuniform_qualifier : require +#extension GL_EXT_buffer_reference : require +#extension GL_EXT_scalar_block_layout : require + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoords; +layout(location = 2) in vec3 fragNormals; +layout(location = 3) in flat int fragDiffuseIdx; +layout(location = 4) in flat int fragSpecularIdx; +layout(location = 5) in vec3 FragPos; // contains world position + +layout(location = 0) out vec4 outColor; + +layout(set = 0, binding = 1) uniform sampler2D textures[]; +layout(set = 0, binding = 2) uniform sampler2D environment_map; // used for IBL + +struct point_light { + vec4 position; + vec4 color; + float attenuation; + float constant; + float linear; + float quadratic; + + vec4 ambient; // 4th channel is the intensity value + vec4 diffuse; + vec4 specular; +}; + +layout(buffer_reference, scalar) buffer readonly SceneUniforms { + mat4 view; + mat4 proj; + vec4 camera_pos; +}; + +const int max_point_lights = 1000; +layout(buffer_reference, scalar) buffer readonly PointLightsUniforms { + int num_lights; + int pad_0; // 4 + int pad_1; // 8 + int pad_2; // 12 + point_light point_lights[max_point_lights]; +}; + +layout(buffer_reference, scalar) buffer ObjectsTable { + mat4 model[]; +}; + +layout(push_constant) uniform Constants { + SceneUniforms global_ubo; + ObjectsTable objects; + int model_matrix_idx; + int diffuse_idx; + int specular_idx; + PointLightsUniforms lights; +} push_const; + +const vec2 invAtan = vec2(0.1591, 0.3183); +vec2 SampleEquirectangular(vec3 v) { + vec3 direction = normalize(v); + vec2 uv = vec2(atan(direction.z, direction.x), asin(direction.y)); + uv *= invAtan; + uv += 0.5; + return uv; +} + +vec3 calc_point_light(point_light light, vec3 normal, vec3 fragPos, vec3 view_dir) { + vec3 light_pos = vec3(light.position); + vec3 dir_to_light = normalize(light_pos - fragPos); + + float diff = max(dot(normal, dir_to_light), 0.0); + + // float material_shininess = 1.0f; + float roughness = 0.5f; + float material_shininess = mix(128.0, 1.0, roughness); + + vec3 reflect_dir = reflect(-dir_to_light, normal); + + float spec = pow(max(dot(view_dir, reflect_dir), 0.0), material_shininess); + + float dist = length(light_pos - fragPos); + float attenuation = light.attenuation / (light.constant + light.linear * dist + light.quadratic * pow(dist, 2)); + + + vec3 ambient = light.ambient.rgb * vec3(texture(textures[nonuniformEXT(fragDiffuseIdx)], fragTexCoords)); + // vec3 diffuse = light.diffuse.xyz * diff * vec3(texture(diffuse_texture, fragTexCoords)); + // vec3 specular = light.specular.xyz * spec * vec3(texture(specular_texture, fragTexCoords)); + vec3 diffuse = light.diffuse.xyz * diff * vec3(texture(textures[fragDiffuseIdx], fragTexCoords)); + vec3 specular = light.specular.xyz * spec * vec3(texture(textures[fragSpecularIdx], fragTexCoords)); + + ambient *= attenuation; + diffuse *= attenuation; + specular *= attenuation; + + return (ambient + diffuse + specular); +} + + + +const float PI = 3.14159265359; +float DistributionGGX(vec3 N, vec3 H, float roughness) { + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float nom = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return nom / denom; +} + +float GeometrySchlickGGX(float NdotV, float roughness) { + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return nom / denom; +} + +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} + +vec3 fresnelSchlick(float cosTheta, vec3 F0) { + return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); +} + + +void main() { + SceneUniforms ubo = push_const.global_ubo; + + + vec4 diffuse_texture = texture(textures[nonuniformEXT(fragDiffuseIdx)], fragTexCoords); + vec4 specular_texture = texture(textures[nonuniformEXT(fragSpecularIdx)], fragTexCoords); + vec3 albedo = (fragColor.rgb * diffuse_texture.rgb); + vec3 final_color = (albedo * diffuse_texture.rgb) * 0.1; + + float roughness = 0.2; + float metallic = 0.2; + float ao = 0.5; + + vec3 F0 = vec3(0.04); + F0 = mix(F0, albedo, metallic); + + // vec3 view_pos = vec3(inverse(ubo.view)[3]); + // vec3 view_dir = normalize(ubo.camera_pos.xyz - FragPos); + + // N + vec3 normal = normalize(fragNormals); + + // V + vec3 view_dir = normalize(ubo.camera_pos.xyz - FragPos); + + // vec3 albedo = diffuse.rgb; + // vec3 albedo = fragColor.rgb; + // vec3 final_color = (albedo * diffuse.rgb) * 0.1; + + PointLightsUniforms lights = push_const.lights; + + int num_point_lights = int(min(lights.num_lights, max_point_lights)); + + vec3 Lo = vec3(0.0); + for(int i = 0; i < num_point_lights; i++) { + point_light src = lights.point_lights[i]; + + // L + vec3 dir_to_light = normalize(src.position.xyz - FragPos); + vec3 H = normalize(dir_to_light + view_dir); + float dist = length(src.position.xyz - FragPos); + // float attenuation = 1.0 / (dist * dist); + float attenuation = src.attenuation / (src.constant + src.linear * dist + src.quadratic * pow(dist, 2)); + vec3 radiance = src.color.rgb * src.color.a * attenuation; + + // cook-torrance brdf + float NDF = DistributionGGX(normal, H, roughness); + float G = GeometrySmith(normal, view_dir, dir_to_light, roughness); + vec3 F = fresnelSchlick(max(dot(H, view_dir) , 0.0), F0); + + vec3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(normal, view_dir), 0.0) * max(dot(normal, dir_to_light), 0.0) + 0.0001; + vec3 specular = numerator / denominator * specular_texture.rgb; + + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + kD *= 1.0 - metallic; + + float NdotL = max(dot(normal, dir_to_light), 0.0); + + Lo += calc_point_light(src, fragNormals, FragPos, dir_to_light) * (src.color.rgb * src.color.a); + // vec3 direct_ambient = src.ambient.rgb * albedo * attenuation; + Lo += (kD * albedo / PI + specular) * radiance * NdotL; + } + + float max_texture_mip_levels = 0.0; + vec3 kS = fresnelSchlick(max(dot(normal, view_dir), 0.0), F0); + vec3 kD = 1.0 - kS; + kD *= 1.0 - metallic; + vec2 environment_uv = SampleEquirectangular(normal); + // vec3 irradiance = texture(environment_map, environment_uv).rgb; + vec3 irradiance = textureLod(environment_map, environment_uv, max_texture_mip_levels).rgb; + vec3 diffuse = irradiance * albedo; + vec3 ambient = (kD * diffuse.rgb) * ao; + vec3 color = ambient + Lo; + + color = color / (color + vec3(1.0)); + color = pow(color, vec3(1.0/2.2)); + + outColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/builtin.shaders/pbr.frag.spv b/builtin.shaders/pbr.frag.spv new file mode 100644 index 00000000..c974e556 Binary files /dev/null and b/builtin.shaders/pbr.frag.spv differ diff --git a/builtin.shaders/pbr.vert b/builtin.shaders/pbr.vert new file mode 100644 index 00000000..7c15f697 --- /dev/null +++ b/builtin.shaders/pbr.vert @@ -0,0 +1,101 @@ +#version 450 + +#extension GL_EXT_buffer_reference : require +#extension GL_EXT_scalar_block_layout : require + +/* + +layout(location = 3) out MaterialData { + int diffuse_idx; + int specular_idx; + int roughness_idx; + int normal_idx; + int parallax_idx; +} material_output; + +*/ + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec2 inTexCoords; +layout(location = 3) in vec3 inNormals; + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoords; +layout(location = 2) out vec3 fragNormals; +layout(location = 3) out flat int fragDiffuseIdx; +layout(location = 4) out flat int fragSpecularIdx; +layout(location = 5) out vec3 FragPos; + +// struct material { +// int diffuse_idx; +// int specular_idx; +// }; + +// layout(bufer_reference, scalar) buffer readonly MaterialUniforms { +// material materials[]; +// }; + +layout(buffer_reference, scalar) buffer readonly SceneUniforms { + mat4 view; + mat4 proj; + vec4 camera_pos; +}; + +struct point_light { + vec4 position; + vec4 color; + + float attenuation; + float constant; + float linear; + float quadratic; + + vec4 ambient; // 4th channel is the intensity value + vec4 diffuse; + vec4 specular; +}; + +const int max_point_lights = 1000; +layout(buffer_reference, scalar) buffer readonly PointLightsUniforms { + int num_lights; + int pad_0; // 4 + int pad_1; // 8 + int pad_2; // 12 + point_light light_sources[max_point_lights]; +}; + +layout(buffer_reference, scalar) buffer ObjectsTable { + mat4 model[]; +}; + +layout(push_constant) uniform Constants { + SceneUniforms global_ubo; + ObjectsTable objects; + int model_matrix_idx; + int diffuse_idx; + int specular_idx; + PointLightsUniforms point_lights; +} push_const; + + + +void main() { + SceneUniforms ubo = push_const.global_ubo; + ObjectsTable object = push_const.objects; + + // retrieve our 3D objects local position within the world + vec4 world_position = object.model[push_const.model_matrix_idx] * vec4(inPosition, 1.0); + + // gl_Position = ubo.proj * ubo.view * object.model[push_const.model_matrix_idx] * vec4(inPosition, 1.0); + gl_Position = ubo.proj * ubo.view * world_position; + fragColor = inColor; + fragTexCoords = inTexCoords; + // fragNormals = mat3(object.model[push_const.model_matrix_idx]) * inNormals; + // mat3 normal_mat = transpose(inverse(mat3(object.model[push_const.model_matrix_idx]))); + fragNormals = inNormals; + // fragNormals = normal_mat * inNormals; + fragDiffuseIdx = push_const.diffuse_idx; + fragSpecularIdx = push_const.specular_idx; + FragPos = world_position.xyz; +} \ No newline at end of file diff --git a/builtin.shaders/pbr.vert.spv b/builtin.shaders/pbr.vert.spv new file mode 100644 index 00000000..122b0982 Binary files /dev/null and b/builtin.shaders/pbr.vert.spv differ diff --git a/builtin.shaders/skybox/skybox.frag b/builtin.shaders/skybox/skybox.frag index 99ddf02e..838e7f5e 100644 --- a/builtin.shaders/skybox/skybox.frag +++ b/builtin.shaders/skybox/skybox.frag @@ -1,6 +1,6 @@ #version 450 -layout (location=0) in vec3 TexCoords; // Direction vector from vertex shader +layout (location=0) in vec3 fragDirectionCoords; // Direction vector from vertex shader layout (location=0) out vec4 out_Color; @@ -29,7 +29,7 @@ vec2 SampleEquirectangular(vec3 v) { void main() { // Get the 2D UV coordinate from the 3D direction - vec2 uv = SampleEquirectangular(TexCoords); + vec2 uv = SampleEquirectangular(fragDirectionCoords); // Sample the HDR map vec3 color = texture(cubeSampler, uv).rgb; diff --git a/builtin.shaders/skybox/skybox.frag.spv b/builtin.shaders/skybox/skybox.frag.spv index 1dd6d547..0c0ce0e3 100644 Binary files a/builtin.shaders/skybox/skybox.frag.spv and b/builtin.shaders/skybox/skybox.frag.spv differ diff --git a/builtin.shaders/skybox/skybox.vert b/builtin.shaders/skybox/skybox.vert index 4a3a7f3c..6238bc16 100644 --- a/builtin.shaders/skybox/skybox.vert +++ b/builtin.shaders/skybox/skybox.vert @@ -1,18 +1,26 @@ #version 460 +#extension GL_EXT_buffer_reference : require +#extension GL_EXT_scalar_block_layout : require + layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inColor; layout(location = 2) in vec3 inNormals; layout(location = 3) in vec2 inTexCoords; -layout (location=0) out vec3 TexCoords; +layout (location=0) out vec3 fragDirectionCoords; -layout (set = 0, binding = 0) readonly uniform UniformBuffer { +layout(buffer_reference, scalar) buffer readonly SceneEnvironmentUniforms { mat4 view_proj; -} ubo; +}; + +layout(push_constant) uniform Constants { + SceneEnvironmentUniforms global_environment; +} push_const; void main() { - TexCoords = inPosition; + fragDirectionCoords = inPosition; + SceneEnvironmentUniforms ubo = push_const.global_environment; vec4 pos = ubo.view_proj * vec4(inPosition, 1.0); gl_Position = pos.xyww; } \ No newline at end of file diff --git a/builtin.shaders/skybox/skybox.vert.spv b/builtin.shaders/skybox/skybox.vert.spv index d76d5b28..899c4948 100644 Binary files a/builtin.shaders/skybox/skybox.vert.spv and b/builtin.shaders/skybox/skybox.vert.spv differ diff --git a/builtin.shaders/test.frag b/builtin.shaders/test.frag deleted file mode 100644 index b56bf390..00000000 --- a/builtin.shaders/test.frag +++ /dev/null @@ -1,120 +0,0 @@ -#version 460 - -layout(location = 0) in vec4 fragColor; -layout(location = 1) in vec3 fragNormals; -layout(location = 2) in vec2 fragTexCoords; -layout(location = 3) in vec4 materialColor; -layout(location = 4) in vec3 FragPos; - -layout(location = 0) out vec4 outColor; - -struct directional_light { - vec3 direction; - vec3 view_position; - vec4 ambient; // 4th channel represents the intensity - vec4 diffuse; - vec4 specular; - vec4 color; -}; - -struct point_light { - vec4 position; - vec4 color; - float attenuation; - float constant; - float linear; - float quadratic; - vec4 ambient; // 4th channel is the intensity value - vec4 diffuse; - vec4 specular; -}; - -// we should only ever have a max of 1000 point lights in a given scene -const int max_point_lights = 1000; - -layout(set = 0, binding = 1) uniform light_ubo { - int num_lights; - point_light sources[max_point_lights]; -} light_src; - - -layout(set = 1, binding = 1) uniform sampler2D diffuse_texture; -layout(set = 1, binding = 2) uniform sampler2D specular_texture; - -layout(set = 1, binding = 3) uniform material_ubo { - vec4 ambient; - vec4 diffuse; - vec4 specular; - float shininess; -} material; - -vec3 calc_dir_light(directional_light light, vec3 normal, vec3 view_dir) { - vec3 light_dir = normalize(-light.direction); - - // diffuse shading - float diff = max(dot(normal, light_dir), 0.0); - - // specular shading - vec3 reflect_dir = reflect(-light_dir, normal); - float spec = pow(max(dot(view_dir, reflect_dir), 0.0), material.shininess); - - // final result computation - // because of alignment we set the ambient, diffuse, specular to vec3 and - // use the 4th channel as the intensity values at least for ambient strength - vec3 ambient_offset = light.ambient.rgb * light.ambient.a; - vec3 diffuse_offset = light.diffuse.rgb * light.diffuse.a; - vec3 specular_offset = light.specular.rgb; - vec3 ambient = ambient_offset * vec3(texture(diffuse_texture, fragTexCoords)); - vec3 diffuse = (diffuse_offset * light.color.rgb) * diff * vec3(texture(diffuse_texture, fragTexCoords)); - vec3 specular = specular_offset * spec * vec3(texture(specular_texture, fragTexCoords)); - - return (ambient + diffuse + specular); -} - -vec3 calc_point_light(point_light light, vec3 normal, vec3 fragPos, vec3 view_dir) { - vec3 light_pos = vec3(light.position); - vec3 dir_to_light = normalize(light_pos - fragPos); - - float diff = max(dot(normal, dir_to_light), 0.0); - - vec3 reflect_dir = reflect(-dir_to_light, normal); - - float spec = pow(max(dot(view_dir, reflect_dir), 0.0), material.shininess); - - float dist = length(light_pos - fragPos); - float attenuation = light.attenuation / (light.constant + light.linear * dist + light.quadratic * pow(dist, 2)); - - vec3 ambient = light.ambient.rgb * vec3(texture(diffuse_texture, fragTexCoords)); - vec3 diffuse = - light.diffuse.xyz * diff * vec3(texture(diffuse_texture, fragTexCoords)); - vec3 specular = light.specular.xyz * spec * vec3(texture(specular_texture, fragTexCoords)); - - ambient *= attenuation; - diffuse *= attenuation; - specular *= attenuation; - - return (ambient + diffuse + specular); -} - -void main() { - - // default ambience is used if there are no point lights assigned in a given scene - vec3 default_ambience = (vec3(texture(diffuse_texture, fragTexCoords)) * fragColor.rgb) * 0.1; - vec3 result = default_ambience; - - // we only want to select the most minimal size of point lights. - // if we have 2 point lights out of 1000, we iterate 2 point lights - // if the cases that we try to have 1005 point lights, we only iterate the 1000'th point light - // since that is how much we allocated to iterate that many point lights - int num_point_lights = int(min(light_src.num_lights, max_point_lights)); - - // iterate through all of the point lights in a given environment - for (int i = 0; i < num_point_lights; i++) { - point_light source_light = light_src.sources[i]; - vec3 view_pos = source_light.position.xyz; - vec3 dir_to_light = normalize(view_pos - FragPos.xyz); - result += calc_point_light(source_light, fragNormals, FragPos, dir_to_light) * (source_light.color.rgb * source_light.color.a); - } - - outColor = vec4(result, 1.0); -} \ No newline at end of file diff --git a/builtin.shaders/test.frag.spv b/builtin.shaders/test.frag.spv deleted file mode 100644 index d3341913..00000000 Binary files a/builtin.shaders/test.frag.spv and /dev/null differ diff --git a/builtin.shaders/test.vert b/builtin.shaders/test.vert deleted file mode 100644 index ebd6260b..00000000 --- a/builtin.shaders/test.vert +++ /dev/null @@ -1,45 +0,0 @@ -#version 460 - -#extension GL_EXT_nonuniform_qualifier : enable // Required for descriptor indexing - -layout(location = 0) in vec3 inPosition; -layout(location = 1) in vec3 inColor; -layout(location = 2) in vec3 inNormals; -layout(location = 3) in vec2 inTexCoords; - -layout(location = 0) out vec4 fragColor; -layout(location = 1) out vec3 fragNormals; -layout(location = 2) out vec2 fragTexCoords; -layout(location = 3) out vec4 materialColor; -layout(location = 4) out vec3 FragPos; - -layout (set = 0, binding = 0) uniform UniformBuffer { - mat4 proj_view; -} ubo; - -// To create a set=1, you just create another vk::descriptor_set object after the first descriptor set, because thats automatic. -layout (set = 1, binding = 0) uniform geometry_ubo { - mat4 model; - vec4 color; // base color for object (NOTE: if materialColor uses this, we get error because we do not have a specific descriptor set for this layout yet, come back after getting food) -} geometry_src; - -void main() { - // FragPos = material_src.model * vec4(inPositoin, 1.0); - vec4 pos_to_world = geometry_src.model * vec4(inPosition, 1.0); - - // vec3 normalize_mat = normalize(mat3(ubo.proj_view) * inNormals); - mat3 normalize_worldspace = mat3(transpose(inverse(geometry_src.model))); - - - vec3 normal = normalize(normalize_worldspace * inNormals); - - gl_Position = ubo.proj_view * pos_to_world; - - // FragPos = vec3(geometry_src.model * vec4(inPosition, 1.0)); - FragPos = pos_to_world.xyz; - // gl_Position = (ubo.proj_view * geometry_src.model) * vec4(inPosition, 1.0); - fragColor = vec4(inColor, 1.0); - fragTexCoords = inTexCoords; - fragNormals = normal; - materialColor = geometry_src.color; -} \ No newline at end of file diff --git a/builtin.shaders/test.vert.spv b/builtin.shaders/test.vert.spv deleted file mode 100644 index e7b11cca..00000000 Binary files a/builtin.shaders/test.vert.spv and /dev/null differ diff --git a/conanfile.py b/conanfile.py index c4b66b59..83fc4cd6 100644 --- a/conanfile.py +++ b/conanfile.py @@ -32,7 +32,7 @@ def requirements(self): self.requires("joltphysics/5.2.0") if self.options.enable_shaderc: self.requires("shaderc/2025.3") - self.requires("imguidocking/3.0") + self.requires("imguidocking/4.0") self.requires("flecs/4.0.4") self.requires("glfw/3.4") self.requires("spdlog/1.16.0") @@ -40,7 +40,7 @@ def requirements(self): self.requires("yaml-cpp/0.8.0") # Vulkan-related headers and includes packages - self.requires("vulkan-cpp/5.0") + self.requires("vulkan-cpp/6.2") self.requires("tinyobjloader/2.0.0-rc10") self.requires("stb/cci.20230920") diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 5d61fefd..7c1e02fe 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -1,24 +1,6 @@ cmake_minimum_required(VERSION 4.0) project(editor CXX) -# build_application( -# SOURCES -# application.cpp - -# PACKAGES -# glfw3 -# Vulkan -# glm -# spdlog - - -# LINK_PACKAGES -# atlas -# glfw -# Vulkan::Vulkan -# glm::glm -# spdlog::spdlog -# ) add_executable(${PROJECT_NAME} application.cpp) @@ -26,9 +8,13 @@ target_sources(editor PUBLIC FILE_SET CXX_MODULES TYPE CXX_MODULES FILES + editor.cppm editor_world.cppm level_scene.cppm + level_scene2.cppm content_browser_panel.cppm + icon.cppm + utilities.cppm ) find_package(glfw3 REQUIRED) diff --git a/editor/application.cpp b/editor/application.cpp index b69e8e75..d4a5d206 100644 --- a/editor/application.cpp +++ b/editor/application.cpp @@ -3,40 +3,47 @@ #include import atlas.application; -import atlas.common; +import atlas.core.utilities; import atlas.core.level_streamer; +import atlas.drivers.vulkan; import atlas.core.event; -import editor_world; - -import atlas.drivers.graphics_context; +import editor; class editor_application : public atlas::application { public: - editor_application(atlas::ref p_context, - const atlas::application_settings& p_settings, - atlas::event::bus& p_bus) - : atlas::application(std::move(p_context), p_settings, p_bus) { + editor_application( + /*NOLINT*/ std::shared_ptr p_context, + const atlas::application_settings& p_settings, + atlas::event::bus& p_bus) + : atlas::application(p_context, p_settings, p_bus) { - m_world = - atlas::create_ref("Editor World", p_bus, m_stream); + m_world = std::make_shared( + p_context, "Editor World", p_bus, m_stream); current_world(m_world); } + // ~editor_application() { + // m_world->destruct(); + // } + ~editor_application() = default; + private: - atlas::ref m_world; + std::shared_ptr m_world; atlas::level_streamer m_stream; }; atlas::ref initialize_application( - /*NOLINT*/ atlas::ref p_contetxt, + /*NOLINT*/ std::shared_ptr p_context, atlas::event::bus& p_bus) { atlas::application_settings settings = { - .name = "Editor", - .width = 1510, - .height = 877, + .extent = { + .width = 1510, + .height = 877, + .name = "Editor", + }, .background_color = { 0.f, 0.f, 0.f, 0.f }, }; - return create_ref(p_contetxt, settings, p_bus); + return create_ref(p_context, settings, p_bus); } \ No newline at end of file diff --git a/editor/content_browser_panel.cppm b/editor/content_browser_panel.cppm index c65a57fe..a1143252 100644 --- a/editor/content_browser_panel.cppm +++ b/editor/content_browser_panel.cppm @@ -1,66 +1,34 @@ module; +#include #include #include #include #include #include -export module content_browser; +export module editor:content_browser; -import atlas.logger; -import atlas.drivers.vulkan.instance_context; -import atlas.drivers.vulkan.imgui_context; +import atlas.core.utilities; import vk; +import :icon; export class content_browser_panel { public: - content_browser_panel() { - vk::texture_info config_texture = { - .phsyical_memory_properties = - atlas::vulkan::instance_context::physical_driver() - .memory_properties(), - .filepath = std::filesystem::path("assets/icons/FileIcon.png") - }; - m_file_icon = vk::texture( - atlas::vulkan::instance_context::logical_device(), config_texture); - if (!m_file_icon.loaded()) { - console_log_info("Play Button Could not be loaded!!"); - } - config_texture = { .phsyical_memory_properties = - atlas::vulkan::instance_context::physical_driver() - .memory_properties(), - .filepath = std::filesystem::path( - "assets/icons/DirectoryIcon.png") }; - m_directory_icon = vk::texture( - atlas::vulkan::instance_context::logical_device(), config_texture); - if (!m_directory_icon.loaded()) { - console_log_info("Stop Button Could not be loaded!!"); - } - config_texture = { .phsyical_memory_properties = - atlas::vulkan::instance_context::physical_driver() - .memory_properties(), - .filepath = - std::filesystem::path("assets/icons/Back.png") }; - m_back_icon = vk::texture( - atlas::vulkan::instance_context::logical_device(), config_texture); - if (!m_back_icon.loaded()) { - console_log_info("Stop Button Could not be loaded!!"); - } + content_browser_panel() = default; + + content_browser_panel(std::shared_ptr p_device, + uint32_t p_memory_properties) { + /*NOLINT*/ m_device = p_device; - m_file_icon_id = static_cast(ImGui_ImplVulkan_AddTexture( - m_file_icon.image().sampler(), - m_file_icon.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - m_directory_icon_id = - static_cast(ImGui_ImplVulkan_AddTexture( - m_directory_icon.image().sampler(), - m_directory_icon.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - m_back_icon_id = static_cast(ImGui_ImplVulkan_AddTexture( - m_back_icon.image().sampler(), - m_back_icon.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); + m_directory_icon = ui::experimental::icon( + m_device, p_memory_properties, "assets/icons/DirectoryIcon.png"); + + m_file_icon = ui::experimental::icon( + m_device, p_memory_properties, "assets/icons/FileIcon.png"); + + m_back_icon = ui::experimental::icon( + m_device, p_memory_properties, "assets/icons/Back.png"); } void run() { @@ -69,8 +37,9 @@ public: // if(ImGui::Button("<-")){ // m_current_directory = m_current_directory.parent_path(); // } - if (ImGui::ImageButton( - "##BackButton", m_back_icon_id, ImVec2(10, 10))) { + if (ImGui::ImageButton("##BackButton", + m_back_icon.texture_id(), + ImVec2(10, 10))) { m_current_directory = m_current_directory.parent_path(); } } @@ -80,13 +49,13 @@ public: float thumbnail_size = 86.96f; // originally 128.f float cell_size = thumbnail_size + padding; - float panelWidth = ImGui::GetContentRegionAvail().x; - int columnCount = (int)(panelWidth / cell_size); + float panel_width = ImGui::GetContentRegionAvail().x; + int column_count = static_cast(panel_width / cell_size); - if (columnCount < 1) - columnCount = 1; + if (column_count < 1) + column_count = 1; - ImGui::Columns(columnCount, 0, false); + ImGui::Columns(column_count, nullptr, false); // @note First, list all files in directory // @@ -105,16 +74,11 @@ public: std::string filename = relative_path.filename().string(); ImGui::PushID(filename.c_str()); - // Ref icon = dir_entry.is_directory() ? - // _directoryIcon : _fileIcon; - ImTextureID icon = dir_entry.is_directory() - ? m_directory_icon_id - : m_file_icon_id; + VkDescriptorSet icon = dir_entry.is_directory() + ? m_directory_icon.texture_id() + : m_file_icon.texture_id(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - // ImGui::ImageButton(reinterpret_cast(icon->getRendererID()), {thumbnail_size, thumbnail_size}, - // { 0, 1 }, { 1, 0}); ImGui::ImageButton("##Button", icon, ImVec2(thumbnail_size, thumbnail_size), @@ -122,11 +86,11 @@ public: { 0, 1 }); if (ImGui::BeginDragDropSource()) { - std::string itemPath = relative_path.string(); - // @note keep in mind sizeof(itemPath) is in bytes + std::string item_path = relative_path.string(); + // @note keep in mind sizeof(item_path) is in bytes ImGui::SetDragDropPayload("CONTENT_BROWSER_ITEM", - itemPath.c_str(), - itemPath.size()); + item_path.c_str(), + item_path.size()); ImGui::EndDragDropSource(); } @@ -145,10 +109,6 @@ public: ImGui::PopID(); } - // ImGui::Columns(1); - // ImGui::SliderFloat("Thumnail Size", &thumbnail_size, 16, 512); - // ImGui::SliderFloat("Padding", &padding, 0, 32); - ImGui::End(); } } @@ -160,13 +120,11 @@ public: } private: - vk::texture m_file_icon; - vk::texture m_directory_icon; - vk::texture m_back_icon; - ImTextureID m_file_icon_id; - ImTextureID m_directory_icon_id; - ImTextureID m_back_icon_id; - const std::filesystem::path m_asset_path = + std::shared_ptr m_device; + ui::experimental::icon m_back_icon; + ui::experimental::icon m_directory_icon; + ui::experimental::icon m_file_icon; + std::filesystem::path m_asset_path = std::filesystem::current_path() / "assets"; std::filesystem::path m_current_directory = m_asset_path; }; \ No newline at end of file diff --git a/editor/editor.cppm b/editor/editor.cppm new file mode 100644 index 00000000..49dc3745 --- /dev/null +++ b/editor/editor.cppm @@ -0,0 +1,10 @@ +module; + +export module editor; + +export import :world; +export import :level_scene; +// export import :level_scene2; +export import :icon; +// export import :content_browser; +// export import :utilities; \ No newline at end of file diff --git a/editor/editor_world.cppm b/editor/editor_world.cppm index a8f6f9ef..16606299 100644 --- a/editor/editor_world.cppm +++ b/editor/editor_world.cppm @@ -1,40 +1,498 @@ module; #include +#include -export module editor_world; +#include +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +#include +#include +#include +#include +#include + +export module editor:world; import atlas.core.utilities; +import atlas.core.scene; import atlas.core.scene.world; import atlas.core.event; -import atlas.drivers.renderer_system; -import atlas.core.scene.uuid; import atlas.core.level_streamer; -import atlas.core.scene; -import level_scene; +import atlas.core.ui; +import atlas.physics.engine; + +import :level_scene; +import :icon; +import :utilities; +import :content_browser; +// import :level_scene2; + +import atlas.core.editor; +import atlas.core.serialize; +import atlas.physics.engine; +import vk; + +enum scene_runtime : uint8_t { edit, play }; /** * @brief editor_world is where a lot of the editor logic will be handled */ export class editor_world final : public atlas::world { public: - editor_world(const std::string& p_tag, + editor_world(/*NOLINT*/ std::shared_ptr p_context, + const std::string& p_tag, atlas::event::bus& p_bus, atlas::level_streamer& p_level_streamer) - : atlas::world(p_tag, p_level_streamer) { - + : atlas::world(p_tag, p_level_streamer) + , m_bus(&p_bus) { + m_device = p_context->logical_device(); // Create defualt scene to level streamer // Does polymorphic allocations for these customized scenes default_custom_scene("LevelScene", p_bus); + // Experimental for loading a second scene. + // create_scene("Level Scene 2", p_bus); + // Set what our current scene is // TODO: Probably have `default_custom_scene() set this current("LevelScene"); - console_log_error("editor_world initialized successfully!!!"); + m_current_scene = this->current(); + + m_editor_dockspace.fullscreen(false); + m_editor_dockspace.dockspace_open(true); + + m_host_bit = p_context->physical_device().memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_coherent_bit); + // Initializing icon. + m_play_icon = ui::experimental::icon( + m_device, m_host_bit, "assets/icons/PlayButton.png"); + + if (!m_play_icon.loaded()) { + std::println("m_play_icon not loaded!"); + } + + m_stop_icon = + ui::experimental::icon(m_device, + p_context->physical_device().memory_properties( + vk::memory_property::host_visible_bit | + vk::memory_property::host_coherent_bit), + "assets/icons/StopButton.png"); + + if (!m_stop_icon.loaded()) { + std::println("m_stop_icon not loaded!"); + } + + m_content_browser = content_browser_panel(m_device, m_host_bit); + + atlas::register_start(this, &editor_world::preload_assets); + atlas::register_update(this, &editor_world::update); + atlas::register_physics(this, &editor_world::physics_update); + atlas::register_ui(this, &editor_world::ui_update); + atlas::register_post(this, &editor_world::unload_assets); } ~editor_world() override = default; + void preload_assets() { + m_deserializer_test = atlas::serializer(); + + if (!m_deserializer_test.load("LevelScene", *m_current_scene)) { + console_log_error("Could not load yaml file LevelScene!!!"); + } + + m_physics_engine = atlas::physics::engine(*m_current_scene, *m_bus); + } + + void update(float p_delta_time) { m_delta_time = p_delta_time; } + + void ui_update() { + // setting up the dockspace UI widgets at the window toolbar + if (m_editor_dockspace.begin()) { + m_editor_menu.begin(); + + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Save")) { + // m_deserializer_test.save("LevelScene"); + } + + ImGui::Separator(); + + if (ImGui::MenuItem("Exit")) { + // glfwSetWindowShouldClose(atlas::application::close(), + // true); + } + + ImGui::EndMenu(); + } + m_editor_menu.end(); + + ImGuiID dockspace_id = ImGui::GetID("Dockspace Demo"); + ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver); + if (ImGui::Begin("Viewport")) { + ImVec2 viewport_size = ImGui::GetContentRegionAvail(); + // ImGui::Image(m_viewport_image_id, + // {static_cast(m_extent.width), + // static_cast(m_extent.height)}); + if (atlas::g_viewport_image_id == nullptr) { + console_log_error("atlas::vulkan::g_viewport_image_id is " + "nullptr!!!!!!!!!!!!!!!!!!!"); + } + ImGui::Image(atlas::g_viewport_image_id, viewport_size); + ImGui::End(); + } + + scene_heirarchy_panel(); + + properties_panel(); + + materials_editor_panel(); + + m_content_browser.run(); + + ui_toolbar(); + + m_editor_dockspace.end(); + } + } + + void scene_heirarchy_panel() { + if (ImGui::Begin("Scene Heirarchy")) { + m_current_scene->defer_begin(); + + auto query_all_transforms = + m_current_scene->query_builder().build(); + + query_all_transforms.each([&](flecs::entity p_entity, + atlas::transform&) { + // We set the imgui flags for our scene heirarchy panel + // TODO -- Make the scene heirarchy panel a separate class that + // is used for specify the layout and other UI elements here + ImGuiTreeNodeFlags flags = + ((m_selected_entity == p_entity) ? ImGuiTreeNodeFlags_Selected + : 0) | + ImGuiTreeNodeFlags_OpenOnArrow; + flags |= ImGuiTreeNodeFlags_SpanAvailWidth; + flags |= ImGuiWindowFlags_Popup; + flags |= ImGuiTreeNodeFlags_AllowItemOverlap; + + bool opened = ImGui::TreeNodeEx(p_entity.name().c_str(), flags); + + if (ImGui::IsItemClicked()) { + m_selected_entity = p_entity; + } + + bool delete_entity = false; + if (ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("Delete Entity")) { + delete_entity = true; + } + ImGui::EndPopup(); + } + + if (delete_entity) { + m_selected_entity.destruct(); + } + + ImGui::SameLine(); + ImGui::TextDisabled("(%llu)", p_entity.id()); + + if (opened) { + flags = ImGuiTreeNodeFlags_OpenOnArrow | + ImGuiTreeNodeFlags_SpanAvailWidth; + auto query_children_builder = + m_current_scene->query_builder() + .with(flecs::ChildOf, p_entity) + .build(); + int32_t child_count = query_children_builder.count(); + + // // Only show children in scene heirarchy panel if there + // are children entities + if (child_count > 0) { + m_selected_entity.children([&](flecs::entity p_child) { + opened = + ImGui::TreeNodeEx(p_child.name().c_str(), flags); + if (opened) { + if (ImGui::IsItemClicked()) { + m_selected_entity = p_child; + } + ImGui::TreePop(); + } + }); + } + + ImGui::TreePop(); + } + }); + + m_current_scene->defer_end(); + + ImGui::End(); + } + } + + void properties_panel() { + if (ImGui::Begin("Properties")) { + if (m_selected_entity.is_alive()) { + ui_component_list(m_selected_entity); + + atlas::ui::draw_component( + "transform", + m_selected_entity, + [](atlas::transform* p_transform) { + atlas::ui::draw_vec3("Position", p_transform->position); + atlas::ui::draw_vec3("Scale", p_transform->scale); + atlas::ui::draw_vec3("Rotation", p_transform->rotation); + }); + + atlas::ui::draw_component( + "camera", + m_selected_entity, + [this](atlas::perspective_camera* p_camera) { + atlas::ui::draw_float("field of view", + p_camera->field_of_view); + ImGui::Checkbox("is_active", &p_camera->is_active); + ImGui::DragFloat("Speed", &m_movement_speed); + }); + + atlas::ui::draw_component( + "atlas::mesh_source", + m_selected_entity, + [](atlas::mesh_source* p_source) { + // if (ImGui::InputText( + // "Input Label", + // &p_source->model_path, + // ImGuiInputTextFlags_EnterReturnsTrue)) { + // console_log_info("mesh_src = {}", + // p_source->model_path); + // // atlas::event::mesh_reload reload_request = { + // // .entity_id = m_selected_entity.id(), + // // .filename = p_source->model_path, + // // }; + + // // if + // (std::filesystem::exists(p_source->model_path)) { + // // signal(reload_request); + // // } + // } + atlas::ui::draw_vec4("Color", p_source->color); + + // if (ImGui::Button("Reload Material")) { + // atlas::event::material_reload + // // reload_material_request = { + // // .entity_id = m_selected_entity.id(), + // // .diffuse = + // "assets/models/viking_room.png", + // // .specular = "", + // // }; + + // // signal(reload_material_request); + // } + }); + + atlas::ui::draw_component( + "Point Light", + m_selected_entity, + [](atlas::point_light* p_dir_light) { + ImGui::DragFloat4( + "Color", glm::value_ptr(p_dir_light->color), 0.01); + ImGui::DragFloat( + "Attenuation", &p_dir_light->attenuation, 0.001); + ImGui::DragFloat4( + "Ambient", glm::value_ptr(p_dir_light->ambient), 0.01); + ImGui::DragFloat4( + "Diffuse", glm::value_ptr(p_dir_light->diffuse), 0.01); + ImGui::DragFloat4("Specular", + glm::value_ptr(p_dir_light->specular), + 0.01); + ImGui::DragFloat( + "Constant", &p_dir_light->constant, 0.01); + ImGui::DragFloat("Linear", &p_dir_light->linear, 0.01); + ImGui::DragFloat( + "Quadratic", &p_dir_light->quadratic, 0.01); + }); + + atlas::ui::draw_component( + "Physics Body", + m_selected_entity, + [](atlas::physics_body* p_body) { + std::array items = { + "Static", + "Kinematic", + "Dynamic", + }; + + // Begin the combo box + if (ImGui::BeginCombo( + "Body Type", + items[p_body->body_movement_type].data())) { + for (int n = 0; n < 3; n++) { + // Check if the current item is selected + const bool is_selected = + (p_body->body_movement_type == n); + if (ImGui::Selectable(items[n].data(), + is_selected)) { + // Update the current type when a new item is + // selected + p_body->body_movement_type = + static_cast(n); + } + + // Set the initial focus when the combo box is + // first opened + if (is_selected) { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + + // physics body parameters + atlas::ui::draw_vec3("Linear Velocity", + p_body->linear_velocity); + atlas::ui::draw_vec3("Angular Velocity", + p_body->angular_velocity); + atlas::ui::draw_vec3("Force", p_body->force); + atlas::ui::draw_vec3("Impulse", p_body->impulse); + atlas::ui::draw_vec3("Torque", p_body->torque); + atlas::ui::draw_vec3("Center Mass", + p_body->center_mass_position); + }); + + atlas::ui::draw_component( + "Box Collider", + m_selected_entity, + [](atlas::box_collider* p_collider) { + atlas::ui::draw_vec3("Half Extent", + p_collider->half_extent); + }); + + atlas::ui::draw_component( + "Box Collider", + m_selected_entity, + [](atlas::sphere_collider* p_collider) { + atlas::ui::draw_float("Radius", p_collider->radius); + }); + + atlas::ui::draw_component( + "Box Collider", + m_selected_entity, + [](atlas::capsule_collider* p_collider) { + atlas::ui::draw_float("Half Height", + p_collider->half_height); + atlas::ui::draw_float("Radius", p_collider->radius); + }); + + atlas::ui::draw_component( + "Serialize", + m_selected_entity, + [](atlas::tag::serialize* p_serialize) { + ImGui::Checkbox("Enable", &p_serialize->enable); + }); + } + ImGui::End(); + } + } + + void materials_editor_panel() { + if (ImGui::Begin("Material Editor")) { + ImGui::End(); + } + } + + void ui_toolbar() { + ImGui::PushStyleVar( + ImGuiStyleVar_WindowPadding, + ImVec2(0, 2)); // @note ImVec making button not touch bottom + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 2)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + + auto& color = ImGui::GetStyle().Colors; + auto& button_hovered = color[ImGuiCol_ButtonHovered]; + auto& button_active = color[ImGuiCol_ButtonActive]; + ImGui::PushStyleColor( + ImGuiCol_ButtonHovered, + ImVec4(button_hovered.x, button_hovered.y, button_hovered.z, 0.5f)); + ImGui::PushStyleColor( + ImGuiCol_ButtonHovered, + ImVec4(button_active.x, button_active.y, button_active.z, 0.5f)); + + float button_size = 20.0f; + + if (ImGui::Begin("##toolbox")) { + VkDescriptorSet button_id = (m_scene_state == scene_runtime::edit) + ? m_play_icon.texture_id() + : m_stop_icon.texture_id(); + + /** + * @note GetWindowContentRegionMax().x is how much space is there + * for content (widgets) + * @note 0.5f is the offset for padding. + * @note takes button size and halves it and makes the offset the + * center of that tab. (centering buttons) + */ + ImGui::SameLine((ImGui::GetWindowContentRegionMax().x * 0.5f) - + (button_size * 0.5f)); + + if (ImGui::ImageButton("##Button", + button_id, + ImVec2{ button_size, button_size }, + ImVec2(0, 0), + ImVec2(1, 1))) { + if (m_scene_state == scene_runtime::edit) { + m_scene_state = scene_runtime::play; + m_physics_engine.start(); + } + else if (m_scene_state == scene_runtime::play) { + m_scene_state = scene_runtime::edit; + m_physics_engine.stop(); + + if (!m_deserializer_test.load("LevelScene", + *m_current_scene)) { + console_log_error( + "Could not load yaml file LevelScene!!!"); + } + } + } + + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(3); + ImGui::End(); + } + } + + void physics_update() { + if (m_scene_state == scene_runtime::play) { + m_physics_engine.update(m_delta_time); + } + } + + void unload_assets() { + // console_log_info("Unloading Assets"); + + m_play_icon.destroy(); + m_stop_icon.destroy(); + m_content_browser.destroy(); + } + private: + atlas::event::bus* m_bus = nullptr; + float m_delta_time; + atlas::physics::engine m_physics_engine; + atlas::serializer m_deserializer_test; + uint32_t m_host_bit = 0; + float m_movement_speed = 10.f; + flecs::entity m_selected_entity; + std::shared_ptr m_device; + scene_runtime m_scene_state = scene_runtime::edit; + std::shared_ptr m_current_scene; + atlas::ui::dockspace m_editor_dockspace; + atlas::ui::menu_item m_editor_menu; + ui::experimental::icon m_play_icon; + ui::experimental::icon m_stop_icon; + content_browser_panel m_content_browser; }; \ No newline at end of file diff --git a/editor/icon.cppm b/editor/icon.cppm new file mode 100644 index 00000000..be20bc53 --- /dev/null +++ b/editor/icon.cppm @@ -0,0 +1,85 @@ +module; + +#include +#include +#include +#include +#include +#include + +export module editor:icon; + +import atlas.core.utilities; +import vk; +import atlas.drivers.vulkan; + +export namespace ui::experimental { + /** + * @brief This is an experimental feature for setting up an image + * thumbnail-like abstraction + * TODO: This should be considered to being abstracted in another approach + * as this is a temporary solution for it. OR this could be the way we + * handle icons for the time being for simplicity. + */ + class icon { + public: + icon() = default; + icon(/*NOLINT*/ std::shared_ptr p_device, + uint32_t p_memory_properties, + const std::filesystem::path& p_filename) { + /*NOLINT*/ m_device = p_device; + vk::texture_params config_texture = { + // .memory_mask = physical_device.memory_properties( + // vk::memory_property::host_visible_bit | + // vk::memory_property::host_coherent_bit), + .memory_mask = p_memory_properties, + }; + + atlas::stb_image image(p_filename.string(), config_texture); + m_icon_image = vk::texture(*m_device, &image, config_texture); + + m_extent = image.extent(); + m_icon_image_id = ImGui_ImplVulkan_AddTexture( + m_icon_image.image().sampler(), + m_icon_image.image().image_view(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + + icon(/*NOLINT*/ std::shared_ptr p_device, + uint32_t p_memory_properties, + const vk::image_extent& p_extent, + std::span p_data) { + /*NOLINT*/ m_device = p_device; + m_extent = p_extent; + m_icon_image = + vk::texture(*m_device, p_extent, p_data, p_memory_properties); + m_icon_image_id = ImGui_ImplVulkan_AddTexture( + m_icon_image.image().sampler(), + m_icon_image.image().image_view(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + + ~icon() = default; + + [[nodiscard]] bool loaded() const { return m_icon_image.loaded(); } + + [[nodiscard]] uint32_t width() const { return m_extent.width; } + + [[nodiscard]] uint32_t height() const { return m_extent.height; } + + [[nodiscard]] VkDescriptorSet texture_id() const { + return m_icon_image_id; + } + + void destroy() { + m_icon_image.destruct(); + ImGui_ImplVulkan_RemoveTexture(m_icon_image_id); + } + + private: + std::shared_ptr m_device; + vk::image_extent m_extent{}; + vk::texture m_icon_image; + VkDescriptorSet m_icon_image_id; + }; +}; \ No newline at end of file diff --git a/editor/level_scene.cppm b/editor/level_scene.cppm index 7ebacf37..8d3ac496 100644 --- a/editor/level_scene.cppm +++ b/editor/level_scene.cppm @@ -1,284 +1,55 @@ module; +#include +#include +#include +#include + #include #define GLM_ENABLE_EXPERIMENTAL #include #include -#include #include #include #include -#include -#include -#include -export module level_scene; +export module editor:level_scene; -import atlas.core.utilities; import atlas.application; -import atlas.core.scene; -import atlas.core.scene.game_object; import atlas.core.event; -import atlas.core.scene.components; -import atlas.core.utilities.state; +import atlas.core.scene; +import atlas.core.utilities; import atlas.core.math; -import atlas.core.editor.dockspace; -import atlas.application; -import atlas.core.ui.widgets; -import atlas.core.editor.menu_item; -import atlas.core.serialize; -import atlas.physics.engine; -import atlas.drivers.vulkan.imgui_context; -import atlas.drivers.vulkan.instance_context; -import atlas.core.ui.widgets.imgui_stdlib; -import vk; -import content_browser; - -static void -ui_component_list(flecs::entity& p_selected_entity) { - std::string entity_name = p_selected_entity.name().c_str(); - std::string new_entity_name = ""; - atlas::ui::draw_input_text(new_entity_name, entity_name); - - p_selected_entity.set_name(new_entity_name.c_str()); - - ImGui::SameLine(); - ImGui::PushItemWidth(-1); - if (ImGui::Button("Add Component")) { - ImGui::OpenPopup("Add Component"); - } - - if (ImGui::BeginPopup("Add Component")) { - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Perspective Camera")) { - p_selected_entity.add< - flecs::pair>(); - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Mesh Source")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Material")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Point Light")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Serialize")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Physics Body")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Box Collider")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Sphere Collider")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - - if (!p_selected_entity.has()) { - if (ImGui::MenuItem("Capsule Collider")) { - p_selected_entity.add(); - ImGui::CloseCurrentPopup(); - } - } - ImGui::EndPopup(); - } - - ImGui::PopItemWidth(); -} - -enum scene_runtime { edit, play }; - -namespace ui::experimental { - /** - * @brief This is an experimental feature for setting up an image - * thumbnail-like abstraction - * TODO: This should be considered to being abstracted in another approach - * as this is a temporary solution for it. OR this could be the way we - * handle icons for the time being for simplicity. - */ - class icon { - public: - icon() = default; - icon(const std::filesystem::path& p_filename) { - vk::texture_info config_texture = { - .phsyical_memory_properties = - atlas::vulkan::instance_context::physical_driver() - .memory_properties(), - .filepath = p_filename - }; - m_icon_image = - vk::texture(atlas::vulkan::instance_context::logical_device(), - config_texture); - if (!m_icon_image.loaded()) { - console_log_info("Play Button Could not be loaded!!"); - } - m_icon_image_id = - static_cast(ImGui_ImplVulkan_AddTexture( - m_icon_image.image().sampler(), - m_icon_image.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - } - - icon(const vk::image_extent& p_extent) { - // vk::texture_info config_texture = { - // .phsyical_memory_properties = - // atlas::vulkan::instance_context::physical_driver().memory_properties(), - // .filepath = p_filename - // }; - m_icon_image = - vk::texture(atlas::vulkan::instance_context::logical_device(), - p_extent, - atlas::vulkan::instance_context::physical_driver() - .memory_properties()); - // if (!m_icon_image.loaded()) { - // console_log_info("Play Button Could not be loaded!!"); - // } - m_icon_image_id = - static_cast(ImGui_ImplVulkan_AddTexture( - m_icon_image.image().sampler(), - m_icon_image.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - } - - ~icon() { - // implicitly destroy - // destroy(); - } - - [[nodiscard]] uint32_t width() const { return m_icon_image.width(); } - - [[nodiscard]] uint32_t height() const { return m_icon_image.height(); } - - [[nodiscard]] ImTextureID texture_id() const { return m_icon_image_id; } - - void destroy() { m_icon_image.destroy(); } - - private: - vk::texture m_icon_image; - ImTextureID m_icon_image_id; - }; -}; - -// TODO: This is just a temporary solution for loading material texture icons to -// ImGui::Image This should be replaced with something like -// atlas::material_manager, eventually. -struct material { - ui::experimental::icon specular; - ui::experimental::icon diffuse; -}; export class level_scene final : public atlas::scene { public: level_scene(const std::string& p_name, atlas::event::bus& p_bus) : atlas::scene(p_name, p_bus) { - auto editor_camera = entity("Editor Camera"); - editor_camera - .add>(); - editor_camera.set({ + + m_editor_camera = entity("Editor Camera"); + m_editor_camera + ->add>(); + m_editor_camera->set({ .position = { 3.50f, 4.90f, 36.40f }, .scale{ 1.f }, }); - editor_camera.set({ + m_editor_camera->set({ .plane = { 0.1f, 5000.f }, .is_active = true, .field_of_view = 45.f, }); - atlas::game_object bob_object = entity("Bob"); - bob_object.add(); - - // @brief For now adding this in - // because we do not have a way to handle empty scenes - // so we are adding this in just to have a specific mesh associated with - // the renderer for the time being, just to make sure it works. atlas::game_object viking_room = entity("Viking Room"); - viking_room.add(); viking_room.set({ - .position = { -2.70f, 2.70, -8.30f }, + .position = { 5, 5, 0.f }, .rotation = { 2.30f, 95.90f, 91.80f }, - .scale{ 1.f }, - }); - - viking_room.set({ - .radius = 1.0f, - }); - - viking_room.set({ - .friction = 15.f, - .restitution = 0.3f, - .body_movement_type = atlas::dynamic, - }); - - atlas::game_object cube = entity("Aircraft"); - - cube.set({ - .position = { 0.f, 2.10f, -7.30f }, - .scale = { 0.9f, 0.9f, 0.9f }, + .scale{ 10.f }, }); - cube.set({ - .color = { 1.f, 1.f, 1.f, 1.f }, - // .model_path = "assets/models/E 45 Aircraft_obj.obj", - .model_path = "assets/backpack/backpack.obj", - .diffuse = "assets/backpack/diffuse.jpg", - .specular = "assets/backpack/specular.jpg" - // .diffuse = "assets/models/E-45-steel detail_2_col.jpg", - }); - - atlas::game_object robot_model = entity("Cube"); - robot_model.add(); - // robot_model.add(); - robot_model.set({ - .position = { -2.70, 3.50f, 4.10f }, - .scale = { 1.f, 1.f, 1.f }, - }); - - robot_model.set( - { .color = { 1.f, 1.f, 1.f, 1.f }, - .model_path = "assets/models/cube.obj", - .diffuse = "assets/models/container_diffuse.png", - .specular = "assets/models/container_specular.png" }); - - robot_model.set({ - .half_extent = { 1.f, 1.f, 1.f }, - }); - robot_model.set({ - // .restitution = 1.f, - .body_movement_type = atlas::dynamic, + viking_room.set({ + .model_path = "assets/models/viking_room.obj", + .diffuse = "assets/models/viking_room.png", }); atlas::game_object platform = entity("Platform"); @@ -297,797 +68,152 @@ public: .half_extent = { 15.f, 0.30f, 10.0f }, }); - atlas::game_object point_light = entity("Point Light 1"); - point_light.set({ + atlas::game_object backpack = entity("Backpack"); + + backpack.set({ .position = { 0.f, 2.10f, -7.30f }, .scale = { 0.9f, 0.9f, 0.9f }, }); - point_light.add(); - - // for(size_t i = 0; i < 26; i++) { - // auto obj = entity(std::format("Object #{}", i)); - // obj.set({ - // .restitution = 1.25f, - // .body_movement_type = atlas::dynamic, - // }); - - // obj.set( - // { - // .radius = 1.0f, - // }); - - // glm::vec3 pos = {float(0*1.4),float(0 * 1.4),float(0 * -3) }; - // obj.set({ - // .position = pos, - // .rotation = {.3f, 0.0f, 0.0f}, - // }); - - // obj.set({ - // .model_path = "assets/models/Ball OBJ.obj", - // .diffuse = "assets/models/clear.png", - // }); + backpack.set( + { .color = { 1.f, 1.f, 1.f, 1.f }, + .model_path = "assets/backpack/backpack.obj", + .diffuse = "assets/backpack/diffuse.jpg", + .specular = "assets/backpack/specular.jpg" }); + + // const size_t grid_width = 5; + // const float spacing = 5; + + // for(size_t i = 0; i < 50; i++) { + // atlas::game_object obj = entity(std::format("Object #{}", i)); + + // size_t col = i % grid_width; + // size_t row = i / grid_width; + + // glm::vec3 pos = { + // float(static_cast(col) * spacing), + // // 0.0f, + // float(static_cast(row) * -spacing), + // 0.f, + // }; + + // obj.set({ + // .position = pos, + // .rotation = {.3f, 0.0f, 0.0f}, + // }); + // obj.set({ + // .model_path = "assets/models/Ball OBJ.obj", + // .diffuse = "assets/models/clear.png", + // }); + + // obj.set({ + // .body_movement_type = atlas::body_type::dynamic, + // }); + // obj.set({ + // .radius = 1.f, + // }); // } - m_editor_dockspace.fullscreen(false); - m_editor_dockspace.dockspace_open(true); - - atlas::game_object gerald = entity("Gerald"); - gerald.add(); - - // TODO: Move this outside of level_scene - m_deserializer_test = atlas::serializer(); - - subscribe(this, - &level_scene::collision_enter); - atlas::register_start(this, &level_scene::start); atlas::register_physics(this, &level_scene::physics_update); atlas::register_update(this, &level_scene::on_update); - atlas::register_ui(this, &level_scene::on_ui_update); - - // Just loading a default icon that has a white texture - // TODO: This should be considered handled differently. - vk::image_extent extent = { - .width = 1, - .height = 1, - }; - m_default_material_icon.specular = ui::experimental::icon(extent); - m_default_material_icon.diffuse = ui::experimental::icon(extent); - - // TEMP: This is for testing if the triggered event only occurs once - // whenever a signal occurs. This should be moved to the internal - // application... OR the renderer - // trigger(this, &level_scene::reload_mesh); - - // @note checking to see what state we are in. (If playing/stopping) - // Ref icon = _sceneState == SceneState::Edit ? _iconPlay : - // _iconStop; - vk::texture_info config_texture = { - .phsyical_memory_properties = - atlas::vulkan::instance_context::physical_driver() - .memory_properties(), - .filepath = std::filesystem::path("assets/icons/PlayButton.png") - }; - m_play_button = vk::texture( - atlas::vulkan::instance_context::logical_device(), config_texture); - if (!m_play_button.loaded()) { - console_log_info("Play Button Could not be loaded!!"); - } - config_texture = { .phsyical_memory_properties = - atlas::vulkan::instance_context::physical_driver() - .memory_properties(), - .filepath = std::filesystem::path( - "assets/icons/StopButton.png") }; - m_stop_button = vk::texture( - atlas::vulkan::instance_context::logical_device(), config_texture); - if (!m_stop_button.loaded()) { - console_log_info("Stop Button Could not be loaded!!"); - } - - m_play_button_id = static_cast(ImGui_ImplVulkan_AddTexture( - m_play_button.image().sampler(), - m_play_button.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - m_stop_button_id = static_cast(ImGui_ImplVulkan_AddTexture( - m_stop_button.image().sampler(), - m_stop_button.image().image_view(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); - - atlas::vulkan::instance_context::submit_resource_free([this]() { - m_play_button.destroy(); - m_stop_button.destroy(); - for (auto& [key, value] : m_material_icons) { - value.specular.destroy(); - value.diffuse.destroy(); - } - - m_default_material_icon.specular.destroy(); - m_default_material_icon.diffuse.destroy(); - - m_content_browser.destroy(); - }); + atlas::register_ui(this, &level_scene::ui_update); } ~level_scene() override = default; - void start() { - m_deserializer_test = atlas::serializer(); - - if (!m_deserializer_test.load("LevelScene", *this)) { - console_log_error("Could not load yaml file LevelScene!!!"); - } - - flecs::world registry = *this; - - // TODO: Should consider having this be a custom UI property to the - // editor. - auto viking_room = entity("Viking Room"); - atlas::mesh_source* src = viking_room.get_mut(); - src->flip = true; - m_physics_engine = atlas::physics::engine(registry, *event_handle()); - } + void start() {} void on_update(float p_delta_time) { - auto query_cameras = - query_builder().build(); + atlas::transform* t = m_editor_camera->get_mut(); float dt = p_delta_time; - query_cameras.each([this, dt](atlas::perspective_camera& p_camera, - atlas::transform& p_transform) { - if (!p_camera.is_active) { - return; - } - - float default_speed = 10.f; // current default movement speed that - // does not applied modified speed - float rotation_speed = 1.f; - float velocity = default_speed * dt; - if (atlas::event::is_mouse_pressed(mouse_button_middle)) { - velocity = m_movement_speed * dt; - } - float rotation_velocity = rotation_speed * dt; - - glm::quat to_quaternion = atlas::to_quat(p_transform.quaternion); - - glm::vec3 up = glm::rotate(to_quaternion, atlas::math::up()); - glm::vec3 forward = - glm::rotate(to_quaternion, atlas::math::backward()); - glm::vec3 right = glm::rotate(to_quaternion, atlas::math::right()); - - if (atlas::event::is_key_pressed(key_left_shift)) { - p_transform.position += up * velocity; - } - - if (atlas::event::is_key_pressed(key_space)) { - p_transform.position -= up * velocity; - } - - if (atlas::event::is_key_pressed(key_w)) { - p_transform.position += forward * velocity; - } - if (atlas::event::is_key_pressed(key_s)) { - p_transform.position -= forward * velocity; - } - - if (atlas::event::is_key_pressed(key_d)) { - p_transform.position += right * velocity; - } - if (atlas::event::is_key_pressed(key_a)) { - p_transform.position -= right * velocity; - } - - if (atlas::event::is_key_pressed(key_q)) { - p_transform.rotation.y += rotation_velocity; - } - if (atlas::event::is_key_pressed(key_e)) { - p_transform.rotation.y -= rotation_velocity; - } - - p_transform.set_rotation(p_transform.rotation); - }); - } - - void on_ui_update() { - // setting up the dockspace UI widgets at the window toolbar - if (m_editor_dockspace.begin()) { - try { - m_editor_menu.begin(); - } - catch (const atlas::ui::menu_bar_exception& e) { - } - - if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Save")) { - // m_deserializer_test.save("LevelScene"); - } - - ImGui::Separator(); - - if (ImGui::MenuItem("Exit")) { - // glfwSetWindowShouldClose(atlas::application::close(), - // true); - } - - ImGui::EndMenu(); - } - - m_editor_menu.end(); - } - ImGuiID dockspace_id = ImGui::GetID("Dockspace Demo"); - ImGui::SetNextWindowDockID(dockspace_id, ImGuiCond_FirstUseEver); - if (ImGui::Begin("Viewport")) { - ImVec2 viewport_size = ImGui::GetContentRegionAvail(); - // ImGui::Image(m_viewport_image_id, - // {static_cast(m_extent.width), - // static_cast(m_extent.height)}); - if (atlas::vulkan::g_viewport_image_id == nullptr) { - console_log_error("atlas::vulkan::g_viewport_image_id is " - "nullptr!!!!!!!!!!!!!!!!!!!"); - } - ImGui::Image(atlas::vulkan::g_viewport_image_id, viewport_size); - ImGui::End(); + // movement speed -- higher the faster camera moves + float default_speed = 50.f; + float velocity = default_speed * dt; + if (atlas::event::is_mouse_pressed(mouse_button_middle)) { + velocity = m_movement_speed * dt; } - // if (ImGui::Begin("Viewport")) { - // // TODO: Consider doing this a different way, but not with - // static. - // // glm::vec2 viewport_panel_size = - // // glm::vec2{ atlas::application::params().width, - // // atlas::application::params().height }; - - // ImGui::End(); - // } - - defer_begin(); - auto query_builder = this->query_builder().build(); - - if (ImGui::Begin("Scene Heirarchy")) { - // @note right click on blank space - // @param string_id - // @param popup_flags - will be the mouse flag (0=right, 1=left) - if (atlas::ui::begin_popup_context_window(nullptr, 1, false)) { - if (ImGui::MenuItem("Create Empty Entity")) { - m_current_entity = entity("Empty Entity"); - } - ImGui::EndPopup(); - } - - query_builder.each([&](flecs::entity p_entity, atlas::transform&) { - // We set the imgui flags for our scene heirarchy panel - // TODO -- Make the scene heirarchy panel a separate class that - // is used for specify the layout and other UI elements here - ImGuiTreeNodeFlags flags = - ((m_selected_entity == p_entity) ? ImGuiTreeNodeFlags_Selected - : 0) | - ImGuiTreeNodeFlags_OpenOnArrow; - flags |= ImGuiTreeNodeFlags_SpanAvailWidth; - flags |= ImGuiWindowFlags_Popup; - flags |= ImGuiTreeNodeFlags_AllowItemOverlap; - - bool opened = ImGui::TreeNodeEx(p_entity.name().c_str(), flags); + glm::quat to_quaternion = atlas::to_quat(t->quaternion); - if (ImGui::IsItemClicked()) { - m_selected_entity = p_entity; - } + glm::vec3 up = glm::rotate(to_quaternion, atlas::math::up()); + glm::vec3 forward = glm::rotate(to_quaternion, atlas::math::backward()); + glm::vec3 right = glm::rotate(to_quaternion, atlas::math::right()); - bool delete_entity = false; - if (ImGui::BeginPopupContextItem()) { - if (ImGui::MenuItem("Delete Entity")) { - delete_entity = true; - } - ImGui::EndPopup(); - } - - if (delete_entity) { - m_selected_entity.destruct(); - } - - ImGui::SameLine(); - ImGui::TextDisabled("(%llu)", p_entity.id()); - - if (opened) { - flags = ImGuiTreeNodeFlags_OpenOnArrow | - ImGuiTreeNodeFlags_SpanAvailWidth; - auto query_children_builder = - this->query_builder() - .with(flecs::ChildOf, p_entity) - .build(); - int32_t child_count = query_children_builder.count(); - - // // Only show children in scene heirarchy panel if there - // are children entities - if (child_count > 0) { - m_selected_entity.children([&](flecs::entity p_child) { - opened = - ImGui::TreeNodeEx(p_child.name().c_str(), flags); - if (opened) { - if (ImGui::IsItemClicked()) { - m_selected_entity = p_child; - } - ImGui::TreePop(); - } - }); - } - - ImGui::TreePop(); - } - }); - - defer_end(); - ImGui::End(); + // Q = UP + if (atlas::event::is_key_pressed(key_q)) { + t->position += up * velocity; } - if (ImGui::Begin("Properties")) { - if (m_selected_entity.is_alive()) { - ui_component_list(m_selected_entity); - - atlas::ui::draw_component( - "transform", - m_selected_entity, - [](atlas::transform* p_transform) { - atlas::ui::draw_vec3("Position", p_transform->position); - atlas::ui::draw_vec3("Scale", p_transform->scale); - atlas::ui::draw_vec3("Rotation", p_transform->rotation); - }); - - atlas::ui::draw_component( - "camera", - m_selected_entity, - [this](atlas::perspective_camera* p_camera) { - atlas::ui::draw_float("field of view", - p_camera->field_of_view); - ImGui::Checkbox("is_active", &p_camera->is_active); - ImGui::DragFloat("Speed", &m_movement_speed); - }); - - atlas::ui::draw_component( - "atlas::mesh_source", - m_selected_entity, - [this](atlas::mesh_source* p_source) { - if (ImGui::InputText( - "Input Label", - &p_source->model_path, - ImGuiInputTextFlags_EnterReturnsTrue)) { - console_log_info("mesh_src = {}", - p_source->model_path); - atlas::event::mesh_reload reload_request = { - .entity_id = m_selected_entity.id(), - .filename = p_source->model_path, - }; - - if (std::filesystem::exists(p_source->model_path)) { - signal(reload_request); - } - } - atlas::ui::draw_vec4("Color", p_source->color); - - if (ImGui::Button("Reload Material")) { - atlas::event::material_reload - reload_material_request = { - .entity_id = m_selected_entity.id(), - .diffuse = "assets/models/viking_room.png", - .specular = "", - }; - - signal(reload_material_request); - } - }); - - atlas::ui::draw_component( - "material", - m_selected_entity, - [this](atlas::material_metadata* p_source) { - // We only want to load in our material textures If - // requested - // TODO: Move this log outside from the add component - // logic. This should be automatically done rather then - // explictly requested - if (!m_material_icons.contains(m_selected_entity.id())) { - if (m_selected_entity.has()) { - material new_mat = {}; - const auto* src = - m_selected_entity.get(); - console_log_info("Specular Path: {}", - src->specular); - if (std::filesystem::exists(src->specular)) { - new_mat.specular = ui::experimental::icon( - std::filesystem::path(src->specular)); - } - else { - console_log_info("Specular (white) Path"); - vk::image_extent extent = { .width = 1, - .height = 1 }; - new_mat.specular = - ui::experimental::icon(extent); - } - - if (std::filesystem::exists(src->diffuse)) { - console_log_info("Diffuse Path: {}", - src->diffuse); - new_mat.diffuse = ui::experimental::icon( - std::filesystem::path(src->diffuse)); - } - else { - console_log_info("Diffuse (white) Path"); - vk::image_extent extent = { .width = 1, - .height = 1 }; - new_mat.diffuse = - ui::experimental::icon(extent); - } - - m_material_icons.emplace(m_selected_entity.id(), - new_mat); - } - } - - float speed = 0.01f; - ImGui::DragFloat4( - "Ambient", glm::value_ptr(p_source->ambient), speed); - ImGui::DragFloat4( - "Diffuse", glm::value_ptr(p_source->diffuse), speed); - ImGui::DragFloat4( - "Specular", glm::value_ptr(p_source->specular), speed); - atlas::ui::draw_float("Shininess", p_source->shininess); - }); - - /* - atlas::ui::draw_component("Directional - Light", m_selected_entity, [](atlas::directional_light* - p_dir_light){ ImGui::DragFloat4("Direction", - glm::value_ptr(p_dir_light->direction)); ImGui::DragFloat4("View - Pos", glm::value_ptr(p_dir_light->view_position)); - ImGui::DragFloat4("Color", - glm::value_ptr(p_dir_light->color)); - ImGui::DragFloat4("Ambient", - glm::value_ptr(p_dir_light->ambient)); - ImGui::DragFloat4("Diffuse", - glm::value_ptr(p_dir_light->diffuse)); - ImGui::DragFloat4("Specular", - glm::value_ptr(p_dir_light->specular)); - }); - */ - - atlas::ui::draw_component( - "Point Light", - m_selected_entity, - [](atlas::point_light* p_dir_light) { - ImGui::DragFloat4( - "Color", glm::value_ptr(p_dir_light->color), 0.01); - ImGui::DragFloat( - "Attenuation", &p_dir_light->attenuation, 0.001); - ImGui::DragFloat4( - "Ambient", glm::value_ptr(p_dir_light->ambient), 0.01); - ImGui::DragFloat4( - "Diffuse", glm::value_ptr(p_dir_light->diffuse), 0.01); - ImGui::DragFloat4("Specular", - glm::value_ptr(p_dir_light->specular), - 0.01); - ImGui::DragFloat( - "Constant", &p_dir_light->constant, 0.01); - ImGui::DragFloat("Linear", &p_dir_light->linear, 0.01); - ImGui::DragFloat( - "Quadratic", &p_dir_light->quadratic, 0.01); - }); - - atlas::ui::draw_component( - "Physics Body", - m_selected_entity, - [](atlas::physics_body* p_body) { - std::array items = { - "Static", - "Kinematic", - "Dynamic", - }; - std::string combo_preview = - items[p_body->body_movement_type]; - - // Begin the combo box - if (ImGui::BeginCombo("Body Type", - combo_preview.data())) { - for (int n = 0; n < 3; n++) { - // Check if the current item is selected - const bool is_selected = - (p_body->body_movement_type == n); - if (ImGui::Selectable(items[n].data(), - is_selected)) { - // Update the current type when a new item is - // selected - p_body->body_movement_type = - static_cast(n); - } - - // Set the initial focus when the combo box is - // first opened - if (is_selected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - - // physics body parameters - atlas::ui::draw_vec3("Linear Velocity", - p_body->linear_velocity); - atlas::ui::draw_vec3("Angular Velocity", - p_body->angular_velocity); - atlas::ui::draw_vec3("Force", p_body->force); - atlas::ui::draw_vec3("Impulse", p_body->impulse); - atlas::ui::draw_vec3("Torque", p_body->torque); - atlas::ui::draw_vec3("Center Mass", - p_body->center_mass_position); - }); - - atlas::ui::draw_component( - "Box Collider", - m_selected_entity, - [](atlas::box_collider* p_collider) { - atlas::ui::draw_vec3("Half Extent", - p_collider->half_extent); - }); - - atlas::ui::draw_component( - "Box Collider", - m_selected_entity, - [](atlas::sphere_collider* p_collider) { - atlas::ui::draw_float("Radius", p_collider->radius); - }); - - atlas::ui::draw_component( - "Box Collider", - m_selected_entity, - [](atlas::capsule_collider* p_collider) { - atlas::ui::draw_float("Half Height", - p_collider->half_height); - atlas::ui::draw_float("Radius", p_collider->radius); - }); - - atlas::ui::draw_component( - "Serialize", - m_selected_entity, - [](atlas::tag::serialize* p_serialize) { - ImGui::Checkbox("Enable", &p_serialize->enable); - }); - } - - ImGui::End(); - - // Material Properties Panel - // TODO: Make this an abstraction to map out the materials - if (ImGui::Begin("Material Editor")) { - - // Specular - if (ImGui::BeginChild("Specular", ImVec2(150, 200), true)) { - if (m_material_icons.contains(m_selected_entity.id())) { - ImGui::Text("Specular"); - ImGui::Separator(); - const auto specular_icon = - m_material_icons[m_selected_entity.id()].specular; - ImGui::Text("size = %d x %d", - specular_icon.width(), - specular_icon.height()); - ImGui::Image(specular_icon.texture_id(), - ImVec2(128, 128)); - } - else { - const auto specular_icon = - m_default_material_icon.specular; - ImGui::Text("size = %d x %d", - specular_icon.width(), - specular_icon.height()); - ImGui::Image(specular_icon.texture_id(), - ImVec2(128, 128)); - } - ImGui::EndChild(); - - // Diffuse - ImGui::Spacing(); - if (ImGui::BeginChild("Diffuse", ImVec2(150, 200), true)) { - ImGui::Text("Diffuse"); - ImGui::Separator(); - if (m_material_icons.contains(m_selected_entity.id())) { - const auto diffuse_icon = - m_material_icons[m_selected_entity.id()].diffuse; - ImGui::Text("size = %d x %d", - diffuse_icon.width(), - diffuse_icon.height()); - ImGui::Image(diffuse_icon.texture_id(), - ImVec2(128, 128)); - } - else { - const auto diffuse_icon = - m_default_material_icon.diffuse; - ImGui::Text("size = %d x %d", - diffuse_icon.width(), - diffuse_icon.height()); - ImGui::Image(diffuse_icon.texture_id(), - ImVec2(128, 128)); - } - ImGui::EndChild(); - } - } - - ImGui::End(); - } - - // Note --- just added this temporarily for testing - // auto time = atlas::application::delta_time(); - - // if((int)(time * 10.0f) % 8 > 4) { - // m_blink = !m_blink; - // } - - // auto width = atlas::application::get_window().width(); - // auto height = atlas::application::get_window().height(); - - // ImGui::SetNextWindowPos(ImVec2(static_cast(width) * 0.5f, - // static_cast(height) * 0.5f), ImGuiCond_Always, - // ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(200, 20), - // ImGuiCond_Always); ImGuiWindowFlags flags = - // ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground | - // ImGuiWindowFlags_NoInputs; ImGui::SetNextWindowBgAlpha(0.f); - - // if(ImGui::Begin("Testing", nullptr, flags)) { - // ImGui::ProgressBar(10.f); - - // auto pos = ImGui::GetWindowPos(); - // pos.x += (float)width * 0.5f - 300.0f; - // pos.y += 50.0f; - // if(m_blink){ - // ImGui::GetForegroundDrawList()->AddText(m_font, 120.0f, - // pos, 0xffffffff, "Click to Play!"); - // } - - // ImGui::End(); - // } + // E = DOWN + if (atlas::event::is_key_pressed(key_e)) { + t->position -= up * velocity; } - ui_toolbar(); - - m_content_browser.run(); - - m_editor_dockspace.end(); - } - - void ui_toolbar() { - ImGui::PushStyleVar( - ImGuiStyleVar_WindowPadding, - ImVec2(0, 2)); // @note ImVec making button not touch bottom - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 2)); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - - auto& color = ImGui::GetStyle().Colors; - auto& buttonHovered = color[ImGuiCol_ButtonHovered]; - auto& buttonActive = color[ImGuiCol_ButtonActive]; - ImGui::PushStyleColor( - ImGuiCol_ButtonHovered, - ImVec4(buttonHovered.x, buttonHovered.y, buttonHovered.z, 0.5f)); - ImGui::PushStyleColor( - ImGuiCol_ButtonHovered, - ImVec4(buttonActive.x, buttonActive.y, buttonActive.z, 0.5f)); - - float button_size = 20.0f; - ImGui::Begin("##toolbox"); - - ImTextureID button_id = (m_scene_state == scene_runtime::edit) - ? m_play_button_id - : m_stop_button_id; - - // @note GetWindowContentRegionMax().x is how much space is there for - // content (widgets) - // @note 0.5f is the offset for padding. - // @note takes button size and halves it and makes the offset the center - // of that tab. (centering buttons) - ImGui::SameLine((ImGui::GetWindowContentRegionMax().x * 0.5f) - - (button_size * 0.5f)); - - if (ImGui::ImageButton("##Button", - button_id, - ImVec2{ button_size, button_size }, - ImVec2(0, 0), - ImVec2(1, 1))) { - if (m_scene_state == scene_runtime::edit) { - m_scene_state = scene_runtime::play; - m_physics_engine.start(); - } - else if (m_scene_state == scene_runtime::play) { - m_scene_state = scene_runtime::edit; - m_physics_engine.stop(); - reset_objects(); - } + if (atlas::event::is_key_pressed(key_w)) { + t->position += forward * velocity; } - - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(3); - ImGui::End(); - } - - void physics_update() { - // TODO: Replace delta_time with physics fixed-timestep instead - float dt = atlas::application::delta_time(); - auto viking_room = entity("Viking Room"); - - atlas::physics_body* sphere_body = - viking_room.get_mut(); - // U = +up - // J = -up - // H = +left - // L = -Left - if (atlas::event::is_key_pressed(key_space)) { - glm::vec3 linear_velocity = { 0.f, 10.0f, 0.f }; - sphere_body->linear_velocity = linear_velocity; - sphere_body->impulse = linear_velocity; + if (atlas::event::is_key_pressed(key_s)) { + t->position -= forward * velocity; } - if (atlas::event::is_key_pressed(key_j)) { - glm::vec3 angular_vel = { -10.f, 0.f, 0.f }; - sphere_body->angular_velocity = angular_vel; + if (atlas::event::is_key_pressed(key_d)) { + t->position += right * velocity; } - - if (atlas::event::is_key_pressed(key_h)) { - glm::vec3 angular_vel = { 10.f, 0.f, 0.f }; - sphere_body->angular_velocity = angular_vel; + if (atlas::event::is_key_pressed(key_a)) { + t->position -= right * velocity; } - if (atlas::event::is_key_pressed(key_l)) { - glm::vec3 angular_vel = { -0.1f, 0.f, 0.f }; - sphere_body->angular_velocity = angular_vel; + glm::vec2 current_cursor_pos = atlas::event::cursor_position(); + if (m_is_first_frame) { + m_last_cursor_pos = current_cursor_pos; + m_is_first_frame = false; } - if (m_scene_state == scene_runtime::play) { - m_physics_engine.update(dt); + if (atlas::event::is_mouse_pressed(mouse_button_middle)) { + atlas::event::set_cursor_mode(atlas::cursor_mode::disabled); + // sensitivity is how fast the cursor rotates + float mouse_sensitivity = 0.01; + glm::vec2 cursor_dt = current_cursor_pos - m_last_cursor_pos; + + m_yaw -= (cursor_dt.x * mouse_sensitivity); + m_pitch -= (cursor_dt.y * mouse_sensitivity); + + t->set_rotation(glm::vec3(m_pitch, m_yaw, 0.0f)); } - } - void reset_objects() { - if (!m_deserializer_test.load("LevelScene", *this)) { - console_log_error("Could not load yaml file LevelScene!!!"); + // The first frame when presseing left shift is to + // continue rotating the camera from where the original position left + // off + if (atlas::event::is_mouse_released(mouse_button_middle)) { + m_is_first_frame = true; + atlas::event::set_cursor_mode(atlas::cursor_mode::normal); } - } -private: - void collision_enter(atlas::event::collision_enter& p_event) { - console_log_warn("collision_enter event!!!"); - atlas::game_object e1 = entity(p_event.entity1); - atlas::game_object e2 = entity(p_event.entity2); + // Signal to trigger this kind of scene transition + // Experimental: This was used for testing. + // if(atlas::event::is_key_pressed(key_n)) { + // std::println("Signaling to transition to next_scene"); + // atlas::event::scene_transition scene_transition = { + // .next_scene = "Level Scene 2", + // }; + // signal(scene_transition); + // } - console_log_warn("Entity1 = {}", e1.name().c_str()); - console_log_warn("Entity2 = {}", e2.name().c_str()); + // Store for next frame + m_last_cursor_pos = current_cursor_pos; } - void collision_persisted(atlas::event::collision_persisted& p_event) { - console_log_warn("collision_persisted(p_event) invoked!!"); - atlas::game_object e1 = entity(p_event.entity1); - atlas::game_object e2 = entity(p_event.entity2); + void physics_update() {} - console_log_warn("Entity1 = {}", e1.name().c_str()); - console_log_warn("Entity2 = {}", e2.name().c_str()); - } + void ui_update() {} private: - atlas::serializer m_deserializer_test; - flecs::entity m_selected_entity; - - atlas::game_object_optional m_current_entity; + std::optional m_editor_camera; float m_movement_speed = 10.f; - - atlas::physics::engine m_physics_engine; - - atlas::ui::dockspace m_editor_dockspace; - atlas::ui::menu_item m_editor_menu; - // ui::experimental::icon m_default_icon; - material m_default_material_icon; - - scene_runtime m_scene_state = scene_runtime::edit; - vk::texture m_play_button; - vk::texture m_stop_button; - ImTextureID m_play_button_id; - ImTextureID m_stop_button_id; - - content_browser_panel m_content_browser; - - std::unordered_map m_material_icons; - - // Note -- Added this temporarily - // ImFont* m_font; + glm::vec2 m_last_cursor_pos{}; + float m_yaw = 0.f; + float m_pitch = 0.f; + bool m_is_first_frame = true; }; \ No newline at end of file diff --git a/editor/level_scene2.cppm b/editor/level_scene2.cppm new file mode 100644 index 00000000..962a8d55 --- /dev/null +++ b/editor/level_scene2.cppm @@ -0,0 +1,133 @@ +module; + +#include +#include +#include +#include + +#include +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +export module editor:level_scene2; + +import atlas.application; +import atlas.core.event; +import atlas.core.scene; +import atlas.core.utilities; +import atlas.core.math; + +// Creating this class for experimentation +export class level_scene2 final : public atlas::scene { +public: + level_scene2(const std::string& p_name, atlas::event::bus& p_bus) + : atlas::scene(p_name, p_bus) { + + m_editor_camera = entity("Editor Camera"); + m_editor_camera + ->add>(); + m_editor_camera->set({ + .position = { 3.50f, 4.90f, 36.40f }, + .scale{ 1.f }, + }); + m_editor_camera->set({ + .plane = { 0.1f, 5000.f }, + .is_active = true, + .field_of_view = 45.f, + }); + + atlas::game_object cube = entity("Cube"); + cube.set({ + .position = { -2.70f, 2.70, -8.30f }, + .rotation = { 2.30f, 95.90f, 91.80f }, + .scale{ 1.f }, + }); + + cube.set({ + .model_path = "assets/models/cube.obj", + .diffuse = "assets/models/container_diffuse.png", + }); + + atlas::register_start(this, &level_scene2::start); + atlas::register_physics(this, &level_scene2::physics_update); + atlas::register_update(this, &level_scene2::on_update); + } + + ~level_scene2() override = default; + + void start() {} + + void on_update(float p_delta_time) { + atlas::transform* t = m_editor_camera->get_mut(); + float dt = p_delta_time; + + // current default movement speed that does not applied modified speed + float default_speed = 10.f; + float rotation_speed = 1.f; + float velocity = default_speed * dt; + if (atlas::event::is_mouse_pressed(mouse_button_middle)) { + velocity = m_movement_speed * dt; + } + + float rotation_velocity = rotation_speed * dt; + + glm::quat to_quaternion = atlas::to_quat(t->quaternion); + + glm::vec3 up = glm::rotate(to_quaternion, atlas::math::up()); + glm::vec3 forward = glm::rotate(to_quaternion, atlas::math::backward()); + glm::vec3 right = glm::rotate(to_quaternion, atlas::math::right()); + + if (atlas::event::is_key_pressed(key_left_shift)) { + t->position += up * velocity; + } + + if (atlas::event::is_key_pressed(key_space)) { + t->position -= up * velocity; + } + + if (atlas::event::is_key_pressed(key_w)) { + t->position += forward * velocity; + } + if (atlas::event::is_key_pressed(key_s)) { + t->position -= forward * velocity; + } + + if (atlas::event::is_key_pressed(key_d)) { + t->position += right * velocity; + } + if (atlas::event::is_key_pressed(key_a)) { + t->position -= right * velocity; + } + + if (atlas::event::is_key_pressed(key_q)) { + t->rotation.y += rotation_velocity; + } + if (atlas::event::is_key_pressed(key_e)) { + t->rotation.y -= rotation_velocity; + } + + // Signal to trigger this kind of scene transition + if (atlas::event::is_key_pressed(key_n)) { + std::println("Signaling to transition to level scene"); + atlas::event::scene_transition scene_transition = { + .next_scene = "Level Scene", + }; + signal(scene_transition); + } + + t->set_rotation(t->rotation); + } + + // TODO: Have this physics_update be executed during the physics + // fixed-update framerate + void physics_update() {} + + // void on_signal(atlas::event::scene_transition& p_transition) { + // p_transition.next_scene = "Level Scene 2"; + // } + +private: + std::optional m_editor_camera; + float m_movement_speed = 10.f; +}; \ No newline at end of file diff --git a/editor/utilities.cppm b/editor/utilities.cppm new file mode 100644 index 00000000..f05f7e10 --- /dev/null +++ b/editor/utilities.cppm @@ -0,0 +1,95 @@ +module; + +#include +#include +#include +#include + +export module editor:utilities; +import atlas.core.ui; +import atlas.core.scene; + +export void +ui_component_list(flecs::entity& p_selected_entity) { + std::string entity_name = p_selected_entity.name().c_str(); + std::string new_entity_name = ""; + atlas::ui::draw_input_text(new_entity_name, entity_name); + + p_selected_entity.set_name(new_entity_name.c_str()); + + ImGui::SameLine(); + ImGui::PushItemWidth(-1); + if (ImGui::Button("Add Component")) { + ImGui::OpenPopup("Add Component"); + } + + if (ImGui::BeginPopup("Add Component")) { + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Perspective Camera")) { + p_selected_entity.add< + flecs::pair>(); + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Mesh Source")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Material")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Point Light")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Serialize")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Physics Body")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Box Collider")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Sphere Collider")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + + if (!p_selected_entity.has()) { + if (ImGui::MenuItem("Capsule Collider")) { + p_selected_entity.add(); + ImGui::CloseCurrentPopup(); + } + } + ImGui::EndPopup(); + } + + ImGui::PopItemWidth(); +} \ No newline at end of file diff --git a/imgui.ini b/imgui.ini index aceffcd7..d6b0e057 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][Debug##Default] ViewportPos=1901,-8 -ViewportId=0x9F5F46A1 +ViewportId=0x16723995 Size=1485,757 Collapsed=0 @@ -13,14 +13,14 @@ Collapsed=0 DockId=0x00000007,0 [Window][Viewport] -Pos=425,64 -Size=1085,615 +Pos=356,76 +Size=917,551 Collapsed=0 -DockId=0x0000000F,0 +DockId=0x00000010,0 [Window][Scene Heirarchy] Pos=0,19 -Size=423,429 +Size=354,429 Collapsed=0 DockId=0x0000000A,0 @@ -38,10 +38,10 @@ Size=1510,877 Collapsed=0 [Window][Content Browser] -Pos=425,681 -Size=1085,196 +Pos=356,629 +Size=917,248 Collapsed=0 -DockId=0x0000000D,0 +DockId=0x00000013,0 [Window][Dear ImGui Demo] ViewportPos=1937,14 @@ -54,32 +54,64 @@ ViewportPos=713,260 ViewportId=0x4AD707D2 Size=480,242 Collapsed=0 -DockId=0x0000000C,1 +DockId=0x6DCE998E,1 [Window][Properties] Pos=0,450 -Size=423,427 +Size=354,427 Collapsed=0 -DockId=0x0000000C,0 +DockId=0x0000000B,0 [Window][##toolbox] -Pos=425,19 -Size=1085,43 +Pos=356,19 +Size=917,55 +Collapsed=0 +DockId=0x0000000F,0 + +[Window][Materials Properties] +Pos=1088,143 +Size=399,201 +Collapsed=0 +DockId=0x00000002,0 + +[Window][Specular] +Pos=1035,305 +Size=399,202 +Collapsed=0 +DockId=0x00000012,0 + +[Window][Diffuse] +Pos=1035,106 +Size=399,197 Collapsed=0 -DockId=0x0000000E,0 +DockId=0x00000011,0 + +[Window][Material Editor] +Pos=1275,19 +Size=235,858 +Collapsed=0 +DockId=0x0000000D,0 [Docking][Data] -DockSpace ID=0x6DCE998E Window=0x091AB4BE Pos=965,301 Size=1510,858 Split=X - DockNode ID=0x00000003 Parent=0x6DCE998E SizeRef=423,858 Split=Y Selected=0x2182E8B1 - DockNode ID=0x0000000A Parent=0x00000003 SizeRef=751,429 HiddenTabBar=1 Selected=0x2182E8B1 - DockNode ID=0x0000000C Parent=0x00000003 SizeRef=751,427 HiddenTabBar=1 Selected=0x199AB496 - DockNode ID=0x00000008 Parent=0x6DCE998E SizeRef=1085,858 Split=X - DockNode ID=0x00000004 Parent=0x00000008 SizeRef=411,445 Split=Y Selected=0x2182E8B1 - DockNode ID=0x00000006 Parent=0x00000004 SizeRef=209,242 Split=Y Selected=0x199AB496 - DockNode ID=0x0000000B Parent=0x00000006 SizeRef=757,660 Split=Y Selected=0x13926F0B - DockNode ID=0x0000000E Parent=0x0000000B SizeRef=885,43 HiddenTabBar=1 Selected=0x804D7EB5 - DockNode ID=0x0000000F Parent=0x0000000B SizeRef=885,615 HiddenTabBar=1 Selected=0x13926F0B - DockNode ID=0x0000000D Parent=0x00000006 SizeRef=757,196 CentralNode=1 HiddenTabBar=1 Selected=0xBF096F38 - DockNode ID=0x00000007 Parent=0x00000004 SizeRef=209,511 Selected=0xB5796446 - DockNode ID=0x00000005 Parent=0x00000008 SizeRef=1096,445 Selected=0x13926F0B +DockNode ID=0x00000001 Pos=1240,208 Size=399,401 Split=Y + DockNode ID=0x00000002 Parent=0x00000001 SizeRef=399,201 Selected=0x920F10F9 + DockNode ID=0x00000009 Parent=0x00000001 SizeRef=399,198 Split=Y Selected=0xDCAC6044 + DockNode ID=0x00000011 Parent=0x00000009 SizeRef=399,197 Selected=0xD3AF05B3 + DockNode ID=0x00000012 Parent=0x00000009 SizeRef=399,202 Selected=0xDCAC6044 +DockSpace ID=0x6DCE998E Pos=965,301 Size=1510,858 Split=X HiddenTabBar=1 + DockNode ID=0x00000004 Parent=0x6DCE998E SizeRef=411,445 Split=Y Selected=0x2182E8B1 + DockNode ID=0x00000006 Parent=0x00000004 SizeRef=209,242 CentralNode=1 HiddenTabBar=1 Selected=0x199AB496 + DockNode ID=0x00000007 Parent=0x00000004 SizeRef=209,511 Selected=0xB5796446 + DockNode ID=0x00000005 Parent=0x6DCE998E SizeRef=1096,445 Selected=0x13926F0B +DockSpace ID=0x7FD4D3C2 Window=0xCEBF5101 Pos=965,301 Size=1510,858 Split=X + DockNode ID=0x0000000C Parent=0x7FD4D3C2 SizeRef=1273,858 Split=X + DockNode ID=0x00000003 Parent=0x0000000C SizeRef=354,858 Split=Y Selected=0x09F641C8 + DockNode ID=0x0000000A Parent=0x00000003 SizeRef=373,429 Selected=0x09F641C8 + DockNode ID=0x0000000B Parent=0x00000003 SizeRef=373,427 Selected=0x8C72BEA8 + DockNode ID=0x00000008 Parent=0x0000000C SizeRef=917,858 Split=Y + DockNode ID=0x0000000E Parent=0x00000008 SizeRef=898,608 Split=Y Selected=0xC450F867 + DockNode ID=0x0000000F Parent=0x0000000E SizeRef=898,55 HiddenTabBar=1 Selected=0x2B095A26 + DockNode ID=0x00000010 Parent=0x0000000E SizeRef=898,551 HiddenTabBar=1 Selected=0xC450F867 + DockNode ID=0x00000013 Parent=0x00000008 SizeRef=898,248 CentralNode=1 HiddenTabBar=1 Selected=0x3DF3100E + DockNode ID=0x0000000D Parent=0x7FD4D3C2 SizeRef=235,858 HiddenTabBar=1 Selected=0x3D0FF072 diff --git a/shaders/colorful_triangle/compile_shaders.sh b/shaders/colorful_triangle/compile_shaders.sh deleted file mode 100644 index 5aa7404c..00000000 --- a/shaders/colorful_triangle/compile_shaders.sh +++ /dev/null @@ -1,2 +0,0 @@ -glslc.exe simple_shader.vert -o simple_shader.vert.spv -glslc.exe simple_shader.frag -o simple_shader.frag.spv diff --git a/shaders/colorful_triangle/simple_shader.frag b/shaders/colorful_triangle/simple_shader.frag deleted file mode 100644 index b9810551..00000000 --- a/shaders/colorful_triangle/simple_shader.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 450 - - -layout(location = 0) in vec3 fragColor; - -layout(location = 0) out vec4 outColor; - -void main(){ - outColor = vec4(fragColor, 0.0); -} \ No newline at end of file diff --git a/shaders/colorful_triangle/simple_shader.frag.spv b/shaders/colorful_triangle/simple_shader.frag.spv deleted file mode 100644 index 43d2f81d..00000000 Binary files a/shaders/colorful_triangle/simple_shader.frag.spv and /dev/null differ diff --git a/shaders/colorful_triangle/simple_shader.vert b/shaders/colorful_triangle/simple_shader.vert deleted file mode 100644 index 07daf1a2..00000000 --- a/shaders/colorful_triangle/simple_shader.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 450 - -// vec2 positions[3] = vec2[]( -// vec2(0.0, -0.5), -// vec2(0.5, 0.5), -// vec2(-0.5, 0.5) -// ); - -layout(location = 0) in vec2 Position; -layout(location = 1) in vec3 Color; - -layout(location = 0) out vec3 fragColor; - -void main(){ - gl_Position = vec4(Position, 0.0, 1.0); - fragColor = Color; -} \ No newline at end of file diff --git a/shaders/colorful_triangle/simple_shader.vert.spv b/shaders/colorful_triangle/simple_shader.vert.spv deleted file mode 100644 index 75fe19c4..00000000 Binary files a/shaders/colorful_triangle/simple_shader.vert.spv and /dev/null differ diff --git a/shaders/cube_shader/cube_shader.frag b/shaders/cube_shader/cube_shader.frag deleted file mode 100644 index ea2eddbd..00000000 --- a/shaders/cube_shader/cube_shader.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 330 - -in vec4 color; -out vec4 outColor; - -void main() { - outColor = vec4(color); -} \ No newline at end of file diff --git a/shaders/cube_shader/cube_shader.vert b/shaders/cube_shader/cube_shader.vert deleted file mode 100644 index 547a9cae..00000000 --- a/shaders/cube_shader/cube_shader.vert +++ /dev/null @@ -1,14 +0,0 @@ -#version 330 - -uniform mat4 matVP; -uniform mat4 matGeo; - -layout (location = 0) in vec3 pos; -layout (location = 1) in vec3 normal; - -out vec4 color; - -void main() { - color = vec4(abs(normal), 1.0); - gl_Position = matVP * matGeo * vec4(pos, 1); -} \ No newline at end of file diff --git a/shaders/mouse_picking_shaders/compile_shaders.sh b/shaders/mouse_picking_shaders/compile_shaders.sh deleted file mode 100644 index 5aa7404c..00000000 --- a/shaders/mouse_picking_shaders/compile_shaders.sh +++ /dev/null @@ -1,2 +0,0 @@ -glslc.exe simple_shader.vert -o simple_shader.vert.spv -glslc.exe simple_shader.frag -o simple_shader.frag.spv diff --git a/shaders/mouse_picking_shaders/simple_shader.frag b/shaders/mouse_picking_shaders/simple_shader.frag deleted file mode 100644 index abb7c3fc..00000000 --- a/shaders/mouse_picking_shaders/simple_shader.frag +++ /dev/null @@ -1,49 +0,0 @@ -#version 450 - - -layout(location = 0) in vec3 fragColor; -layout(location = 0) out vec4 outColor; - - -// layout(push_constant) uniform Push { -// // mat4 Transform; // proj * view * model -// mat4 Projection; -// mat4 View; -// mat4 Model; -// vec3 LightTransform; -// } push; - -// layout(push_constant) uniform Push { -// // mat4 Transform; // proj * view -// mat4 Projection; -// mat4 View; -// mat4 Model; -// vec3 LightTransform; -// } push; -// we set our descriptor set to binding = 0 -// meaning that our descriptor set references to GlobalUbo -// layout(set= 0, binding = 0) uniform GlobalLightUbo { -// mat4 Model; // light model -// vec3 Direction; // light dir -// } light_ubo; - -layout(set = 0, binding = 0) uniform GlobalCameraUbo{ - mat4 Projection; - mat4 View; - mat4 Model; - vec3 LightTransform; - // vec4 Color; -} camera_ubo; - -layout(push_constant) uniform Push { - mat4 Projection; - mat4 View; - mat4 Model; - vec3 LightTransform; - vec4 Color; - vec2 MousePosition; -} push; - -void main(){ - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file diff --git a/shaders/mouse_picking_shaders/simple_shader.frag.spv b/shaders/mouse_picking_shaders/simple_shader.frag.spv deleted file mode 100644 index 95c42ae0..00000000 Binary files a/shaders/mouse_picking_shaders/simple_shader.frag.spv and /dev/null differ diff --git a/shaders/mouse_picking_shaders/simple_shader.vert b/shaders/mouse_picking_shaders/simple_shader.vert deleted file mode 100644 index 54abaf84..00000000 --- a/shaders/mouse_picking_shaders/simple_shader.vert +++ /dev/null @@ -1,78 +0,0 @@ -#version 450 - -//! @note Position and Color used in the vertex class. -layout(location = 0) in vec3 Position; -layout(location = 1) in vec3 Color; -layout(location = 2) in vec3 Normals; -layout(location = 3) in vec2 Uv; - - -layout(location = 0) out vec3 fragColor; - -// we set our descriptor set to binding = 0 -// meaning that our descriptor set references to GlobalUbo -// layout(set = 0, binding = 0) uniform GlobalLightUbo { -// mat4 Model; // light model -// vec3 Direction; // light dir -// } light_ubo; - -layout(set = 0, binding = 0) uniform GlobalCameraUbo{ - mat4 Projection; - mat4 View; - mat4 Model; - vec3 LightTransform; -} camera_ubo; - -layout(push_constant) uniform Push { - mat4 Projection; - mat4 View; - mat4 Model; - vec3 LightTransform; - vec4 Color; - vec2 MousePosition; -} push; - - - -vec3 dir_to_light = normalize(push.LightTransform); -const float AMBIENT = 0.2; - -/* -void main(){ - gl_Position = (push.Projection * push.View * push.Model) * vec4(Position, 1.0); - - vec3 normalize_world_space = normalize(mat3(push.Model) * Normals); - float LightIntensity = AMBIENT + max(dot(normalize_world_space, dir_to_light), 0); - - vec3 baseColor = LightIntensity * Color * push.Color.xyz; - - // VERY BASIC "PICKING" (Highly Inaccurate) - vec4 screenPos = gl_Position; - // vec4 screenPos = vec4(Position, 1.0); - screenPos.xyz /= screenPos.w; // Perspective divide - - vec2 fragScreenPos = screenPos.xy * 0.5 + 0.5; // NDC to screen space (0-1) - - float dist = length(fragScreenPos - push.MousePosition); // dist in screen space - - float threshold = 0.5; // Adjust this (very sensitive) - - if (dist < threshold) { - fragColor = baseColor; - } else { - // fragColor = baseColor; - fragColor = vec3(1.0, 0.0, 0.0); // Red highlight (or any effect you want) - } -} -*/ - - -void main(){ - gl_Position = (push.Projection * push.View * push.Model) * vec4(Position, 1.0); - - vec3 normalize_world_space = normalize(mat3(push.Model) * Normals); - - float LightIntensity = AMBIENT + max(dot(normalize_world_space, dir_to_light), 0); - - fragColor = LightIntensity * Color * push.Color.xyz; -} diff --git a/shaders/mouse_picking_shaders/simple_shader.vert.spv b/shaders/mouse_picking_shaders/simple_shader.vert.spv deleted file mode 100644 index d2b6e737..00000000 Binary files a/shaders/mouse_picking_shaders/simple_shader.vert.spv and /dev/null differ diff --git a/shaders/showcase_shaders/simple_shader.frag b/shaders/showcase_shaders/simple_shader.frag deleted file mode 100644 index 61421f18..00000000 --- a/shaders/showcase_shaders/simple_shader.frag +++ /dev/null @@ -1,24 +0,0 @@ -#version 450 - - -layout(location = 0) in vec3 fragColor; -layout(location = 0) out vec4 outColor; - - -// layout(push_constant) uniform Push { -// mat4 Transform; // proj * view * model -// mat4 ModelMatrix; -// vec3 LightTransform; -// } push; -layout(push_constant) uniform Push { - // mat4 Transform; // proj * view * model - mat4 Projection; - mat4 View; - mat4 ModelMatrix; - vec3 LightTransform; -} push; - -void main(){ - // outColor = vec4(fragColor, 0.0); - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file diff --git a/shaders/showcase_shaders/simple_shader.frag.spv b/shaders/showcase_shaders/simple_shader.frag.spv deleted file mode 100644 index 62b514e6..00000000 Binary files a/shaders/showcase_shaders/simple_shader.frag.spv and /dev/null differ diff --git a/shaders/showcase_shaders/simple_shader.vert b/shaders/showcase_shaders/simple_shader.vert deleted file mode 100644 index f74405bf..00000000 --- a/shaders/showcase_shaders/simple_shader.vert +++ /dev/null @@ -1,41 +0,0 @@ -#version 450 - -//! @note Position and Color used in the Vertex class. -layout(location = 0) in vec3 Position; -layout(location = 1) in vec3 Color; -layout(location = 2) in vec3 Normals; -layout(location = 3) in vec2 Uv; - - -layout(location = 0) out vec3 fragColor; - -layout(push_constant) uniform Push { - // mat4 Transform; // proj * view * model - mat4 Projection; - mat4 View; - mat4 ModelMatrix; - vec3 LightTransform; -} push; - -// const vec3 dir_to_light = normalize(vec3(1.0, -3.0, -1.0)); -// vec3 light_transform = vec3(1.0, -3.0, -1.0); -// const vec3 dir_to_light = normalize(vec3(1.0, -3.0, -1.0)); -// vec3 dir_to_light = normalize(push.LightTransform); -// const vec3 dir_to_light = normalize(); -vec3 dir_to_light = normalize(push.LightTransform); - -void main(){ - // -.5f is to temp fix the rolling issue with the sphere. - vec3 newPos = vec3(Position.x,Position.y-0.5f,Position.z); - // vec4 worldPositionSpace = push.ModelMatrix * vec4(newPos, 1.0); - mat4 transform = push.Projection * push.View * push.ModelMatrix; - // gl_Position = push.Transform * vec4(newPos,1.0); - gl_Position = transform * vec4(newPos, 1.0); - - // mat3 normal_mat = transpose(inverse(mat3(push.ModelMatrix))); - vec3 normalize_world_space = normalize(mat3(push.ModelMatrix) * Normals); - float LightIntensity = max(dot(normalize_world_space, dir_to_light), 0) / 1.5f; - - // fragColor = Color; - fragColor = LightIntensity * Color; -} \ No newline at end of file diff --git a/shaders/showcase_shaders/simple_shader.vert.spv b/shaders/showcase_shaders/simple_shader.vert.spv deleted file mode 100644 index 25d9d7b3..00000000 Binary files a/shaders/showcase_shaders/simple_shader.vert.spv and /dev/null differ diff --git a/shaders/sim_shader_transforms/simple_shader.frag b/shaders/sim_shader_transforms/simple_shader.frag deleted file mode 100644 index e4cd3031..00000000 --- a/shaders/sim_shader_transforms/simple_shader.frag +++ /dev/null @@ -1,19 +0,0 @@ -#version 450 - - -layout(location = 0) in vec3 fragColor; -layout(location = 0) out vec4 outColor; - - -layout(push_constant) uniform Push { - // mat4 Transform; // proj * view * model - mat4 Projection; - mat4 View; - mat4 Model; - vec3 LightTransform; -} push; - -void main(){ - // outColor = vec4(fragColor, 0.0); - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file diff --git a/shaders/sim_shader_transforms/simple_shader.frag.spv b/shaders/sim_shader_transforms/simple_shader.frag.spv deleted file mode 100644 index 937c4ba1..00000000 Binary files a/shaders/sim_shader_transforms/simple_shader.frag.spv and /dev/null differ diff --git a/shaders/sim_shader_transforms/simple_shader.vert b/shaders/sim_shader_transforms/simple_shader.vert deleted file mode 100644 index a2df0b74..00000000 --- a/shaders/sim_shader_transforms/simple_shader.vert +++ /dev/null @@ -1,38 +0,0 @@ -#version 450 - -//! @note Position and Color used in the Vertex class. -layout(location = 0) in vec3 Position; -layout(location = 1) in vec3 Color; -layout(location = 2) in vec3 Normals; -layout(location = 3) in vec2 Uv; - - -layout(location = 0) out vec3 fragColor; - -layout(push_constant) uniform Push { - // mat4 Transform; // proj * view - mat4 Projection; - mat4 View; - mat4 Model; - vec3 LightTransform; -} push; - -// const vec3 dir_to_light = normalize(vec3(1.0, -3.0, -1.0)); -// vec3 light_transform = vec3(1.0, -3.0, -1.0); -// const vec3 dir_to_light = normalize(vec3(1.0, -3.0, -1.0)); -// vec3 dir_to_light = normalize(push.LightTransform); -// const vec3 dir_to_light = normalize(); -vec3 dir_to_light = normalize(push.LightTransform); - -void main(){ - // vec4 worldPositionSpace = push.ModelMatrix * vec3(Position, 1.0); - mat4 transform = push.Projection * push.View; - gl_Position = transform * vec4(Position, 1.0); - - // mat3 normal_mat = transpose(inverse(mat3(push.ModelMatrix))); - vec3 normalize_world_space = normalize(mat3(push.Model) * Normals); - float LightIntensity = max(dot(normalize_world_space, dir_to_light), 0) / 1.5f; - - // fragColor = Color; - fragColor = LightIntensity * Color; -} \ No newline at end of file diff --git a/shaders/sim_shader_transforms/simple_shader.vert.spv b/shaders/sim_shader_transforms/simple_shader.vert.spv deleted file mode 100644 index b5ab4b74..00000000 Binary files a/shaders/sim_shader_transforms/simple_shader.vert.spv and /dev/null differ diff --git a/shaders/sim_shader_ubo_tutorial/simple_shader.frag b/shaders/sim_shader_ubo_tutorial/simple_shader.frag deleted file mode 100644 index 3a88cf83..00000000 --- a/shaders/sim_shader_ubo_tutorial/simple_shader.frag +++ /dev/null @@ -1,37 +0,0 @@ -#version 450 - - -layout(location = 0) in vec3 fragColor; -layout(location = 1) in vec3 fragPosWorld; -layout(location = 2) in vec3 fragNormalWorld; - -layout(location = 0) out vec4 outColor; - -layout(set = 0, binding = 0) uniform GlobalUbo { - mat4 ProjectionView; - vec4 AmbientLightColor; // w = intensity - vec3 LightPosition; - vec4 LightColor; // w - is light intensity -} ubo; - - -layout(push_constant) uniform Push { - mat4 Transform; // proj * view * model - mat4 ModelMatrix; - vec3 LightTransform; -} push; - -void main(){ - vec3 newPos = vec3(fragPosWorld.x, fragPosWorld.y, fragPosWorld.z); - vec3 dir_to_light = ubo.LightPosition; - - vec3 DirectionToLight = dir_to_light - newPos.xyz; - float attenuation = 1.0 / dot(DirectionToLight, DirectionToLight); - - vec3 LightColor = ubo.LightColor.xyz * ubo.LightColor.w; - vec3 AmbientLight = ubo.AmbientLightColor.xyz * ubo.AmbientLightColor.w * attenuation; - vec3 DiffuseLighting = LightColor * max(dot(fragNormalWorld, normalize(DirectionToLight)), 0); - - outColor = vec4((DiffuseLighting + AmbientLight) * fragColor, 1.0); - -} \ No newline at end of file diff --git a/shaders/sim_shader_ubo_tutorial/simple_shader.frag.spv b/shaders/sim_shader_ubo_tutorial/simple_shader.frag.spv deleted file mode 100644 index 6b5921a0..00000000 Binary files a/shaders/sim_shader_ubo_tutorial/simple_shader.frag.spv and /dev/null differ diff --git a/shaders/sim_shader_ubo_tutorial/simple_shader.vert b/shaders/sim_shader_ubo_tutorial/simple_shader.vert deleted file mode 100644 index 7df065f4..00000000 --- a/shaders/sim_shader_ubo_tutorial/simple_shader.vert +++ /dev/null @@ -1,38 +0,0 @@ -#version 450 - -//! @note Position and Color used in the Vertex class. -layout(location = 0) in vec3 Position; -layout(location = 1) in vec3 Color; -layout(location = 2) in vec3 Normals; -layout(location = 3) in vec2 Uv; - - -layout(location = 0) out vec3 fragColor; -layout(location = 1) out vec3 fragPosWorld; -layout(location = 2) out vec3 fragNormalWorld; - -layout(set = 0, binding = 0) uniform GlobalUbo { - mat4 ProjectionView; - vec4 AmbientLightColor; // w = intensity - vec3 LightPosition; - vec4 LightColor; // w - is light intensity -} ubo; - - -layout(push_constant) uniform Push { - mat4 Transform; // proj * view * model - mat4 ModelMatrix; - vec3 LightTransform; -} push; - - -void main(){ - vec3 newPos = vec3(Position.x, Position.y, Position.z); - gl_Position = push.Transform * vec4(newPos, 1.0); - - - fragNormalWorld = normalize(mat3(push.ModelMatrix) * vec3(Normals.x, Normals.y, Normals.z)); - fragPosWorld = Position.xyz; - fragColor = Color; - -} \ No newline at end of file diff --git a/shaders/sim_shader_ubo_tutorial/simple_shader.vert.spv b/shaders/sim_shader_ubo_tutorial/simple_shader.vert.spv deleted file mode 100644 index 30c27c46..00000000 Binary files a/shaders/sim_shader_ubo_tutorial/simple_shader.vert.spv and /dev/null differ diff --git a/shaders/simple_shader/compile_shaders.sh b/shaders/simple_shader/compile_shaders.sh deleted file mode 100644 index 5aa7404c..00000000 --- a/shaders/simple_shader/compile_shaders.sh +++ /dev/null @@ -1,2 +0,0 @@ -glslc.exe simple_shader.vert -o simple_shader.vert.spv -glslc.exe simple_shader.frag -o simple_shader.frag.spv diff --git a/shaders/simple_shader/simple_shader.frag b/shaders/simple_shader/simple_shader.frag deleted file mode 100644 index 156225cc..00000000 --- a/shaders/simple_shader/simple_shader.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 450 - - -// layout(location = 0) in vec3 fragColor; - -layout(location = 0) out vec4 outColor; - -layout(push_constant) uniform Push { - vec2 offset; - vec3 color; -} push; - -void main(){ - // outColor = vec4(fragColor, 0.0); - outColor = vec4(push.color, 0.0); -} \ No newline at end of file diff --git a/shaders/simple_shader/simple_shader.frag.spv b/shaders/simple_shader/simple_shader.frag.spv deleted file mode 100644 index f9f7271b..00000000 Binary files a/shaders/simple_shader/simple_shader.frag.spv and /dev/null differ diff --git a/shaders/simple_shader/simple_shader.vert b/shaders/simple_shader/simple_shader.vert deleted file mode 100644 index 243562cb..00000000 --- a/shaders/simple_shader/simple_shader.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 Position; -layout(location = 1) in vec3 Color; - -// layout(location = 0) out vec3 fragColor; - -layout(push_constant) uniform Push { - vec2 offset; - vec3 color; -} push; - -void main(){ - // gl_Position = vec4(Position, 0.0, 1.0); - gl_Position = vec4(Position + push.offset, 0.0, 1.0); - // fragColor = Color; -} \ No newline at end of file diff --git a/shaders/simple_shader/simple_shader.vert.spv b/shaders/simple_shader/simple_shader.vert.spv deleted file mode 100644 index 5b8a9757..00000000 Binary files a/shaders/simple_shader/simple_shader.vert.spv and /dev/null differ diff --git a/tests/entity_component_system.test.cppm b/tests/entity_component_system.test.cppm index 14a75636..4b62be9b 100644 --- a/tests/entity_component_system.test.cppm +++ b/tests/entity_component_system.test.cppm @@ -8,10 +8,9 @@ module; export module atlas.tests:entity_component_system; import atlas.core.scene; -import atlas.core.scene.game_object; -import atlas.core.math.types; +import atlas.core.math; import atlas.core.event; -import atlas.drivers.jolt_cpp.types; +import atlas.drivers.jolt_cpp; namespace atlas { /** diff --git a/tests/math.test.cppm b/tests/math.test.cppm index 4ec9c3f3..889ee3e4 100644 --- a/tests/math.test.cppm +++ b/tests/math.test.cppm @@ -5,8 +5,8 @@ module; #include export module atlas.tests:math; -import atlas.core.math.types; -import atlas.drivers.jolt_cpp.types; +import atlas.core.math; +import atlas.drivers.jolt_cpp; /** * @name MockTestTransform diff --git a/tests/scene.test.cppm b/tests/scene.test.cppm index 17092db4..fa0b8add 100644 --- a/tests/scene.test.cppm +++ b/tests/scene.test.cppm @@ -3,8 +3,6 @@ module; export module atlas.tests:scene; import atlas.core.scene; -import atlas.core.scene.game_object; -import atlas.core.scene.components; import atlas.core.event; export void