/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND #include #include #include #include #include #include "../lib/xdg-shell-client-protocol.h" #include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "../lib/fractional-scale-v1.h" #include "../lib/viewporter.h" #include #include #include #include #include #include #include #include #include #endif #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN #include "vulkan/vulkan.h" #endif export module Crafter.Graphics:Window; import std; import :Types; import :Rendertarget; import :Transform2D; import Crafter.Event; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN import :PipelineRTVulkan; #endif export namespace Crafter { #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN struct Semaphores { // Swap chain image presentation VkSemaphore presentComplete; // Command buffer submission and execution VkSemaphore renderComplete; }; #endif struct MouseElement; struct Window { FrameTime currentFrameTime; std::uint32_t width; std::uint32_t height; std::chrono::time_point lastFrameBegin; Event onClose; Event onUpdate; bool open = true; bool updating = false; bool heldkeys[static_cast(CrafterKeys::CrafterKeysMax)] = {}; Event onKeyDown[static_cast(CrafterKeys::CrafterKeysMax)]; Event onKeyHold[static_cast(CrafterKeys::CrafterKeysMax)]; Event onKeyUp[static_cast(CrafterKeys::CrafterKeysMax)]; Event onAnyKeyDown; Event onAnyKeyHold; Event onAnyKeyUp; Event onMouseRightClick; Event onMouseLeftClick; Event onMouseRightHold; Event onMouseLeftHold; Event onMouseRightRelease; Event onMouseLeftRelease; Event onMouseMove; Event onMouseEnter; Event onMouseLeave; Event onMouseScroll; Vector currentMousePos; Vector lastMousePos; Vector mouseDelta; bool mouseLeftHeld = false; bool mouseRightHeld = false; std::vector mouseElements; std::vector pendingMouseElements; Window(std::uint32_t width, std::uint32_t height); Window(std::uint32_t width, std::uint32_t height, const std::string_view title); Window(Window&) = delete; Window(Window&&) = delete; Window& operator=(const Window&) = delete; void StartSync(); void StartUpdate(); void StopUpdate(); void SetTitle(const std::string_view title); void Resize(std::uint32_t width, std::uint32_t height); void Render(); void Update(); #ifdef CRAFTER_TIMING std::chrono::nanoseconds totalUpdate; std::vector*, std::chrono::nanoseconds>> updateTimings; std::chrono::nanoseconds totalRender; std::chrono::nanoseconds vblank; std::chrono::nanoseconds totalFrame; std::chrono::time_point frameEnd; std::vector frameTimes; void LogTiming(); #endif #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND float scale; #ifdef CRAFTER_GRAPHICS_RENDERER_SOFTWARE Rendertarget renderer; #endif bool configured = false; xdg_toplevel* xdgToplevel = nullptr; wp_viewport* wpViewport = nullptr; wl_surface* surface = nullptr; wl_buffer* buffer = nullptr; wl_buffer* backBuffer = nullptr; xdg_surface* xdgSurface = nullptr; wl_callback* cb = nullptr; static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale); static void wl_surface_frame_done(void *data, wl_callback *cb, uint32_t time); static void xdg_toplevel_handle_close(void* data, xdg_toplevel*); static void xdg_surface_handle_configure(void* data, xdg_surface* xdg_surface, std::uint32_t serial); static void xdg_toplevel_configure(void*, xdg_toplevel*, std::int32_t, std::int32_t, wl_array*); constexpr static xdg_toplevel_listener xdg_toplevel_listener = { .configure = xdg_toplevel_configure, .close = xdg_toplevel_handle_close, }; constexpr static wl_callback_listener wl_callback_listener = { .done = wl_surface_frame_done, }; constexpr static xdg_surface_listener xdg_surface_listener = { .configure = xdg_surface_handle_configure, }; constexpr static wp_fractional_scale_v1_listener wp_fractional_scale_v1_listener = { .preferred_scale = xdg_surface_handle_preferred_scale, }; inline static wp_fractional_scale_v1* wp_scale = nullptr; #endif #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN std::vector descriptorsRt; template void SetPipelineRT() { rtPipeline = Pipeline::pipeline; rtPipelineLayout = Pipeline::pipelineLayout; raygenRegion = Pipeline::raygenRegion; missRegion = Pipeline::missRegion; hitRegion = Pipeline::hitRegion; callableRegion = Pipeline::callableRegion; } void SetPipelineRT(PipelineRTVulkan& pipeline); VkCommandBuffer StartInit(); void FinishInit(); void CreateSwapchain(); static constexpr std::uint8_t numFrames = 3; VkSurfaceKHR vulkanSurface = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE; VkFormat colorFormat; VkColorSpaceKHR colorSpace; VkImage images[numFrames]; VkImageView imageViews[numFrames]; std::thread thread; VkCommandBuffer drawCmdBuffers[numFrames]; VkSubmitInfo submitInfo; Semaphores semaphores; std::uint32_t currentBuffer = 0; VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkPipeline rtPipeline; VkPipelineLayout rtPipelineLayout; VkStridedDeviceAddressRegionKHR raygenRegion; VkStridedDeviceAddressRegionKHR missRegion; VkStridedDeviceAddressRegionKHR hitRegion; VkStridedDeviceAddressRegionKHR callableRegion; #endif }; }