/* 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 #ifdef CRAFTER_GRAPHICS_WINDOW_WIN32 #include #endif export module Crafter.Graphics:Window; import std; import :Types; import :Rendertarget; import :Transform2D; import Crafter.Event; export namespace Crafter { #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN struct Semaphores { // Swap chain image presentation VkSemaphore presentComplete; // Command buffer submission and execution VkSemaphore renderComplete; }; struct PipelineRTVulkan; struct DescriptorHeapVulkan; #endif struct MouseElement; struct Window { FrameTime currentFrameTime; std::uint32_t width; std::uint32_t height; std::chrono::time_point lastFrameBegin; Event onClose; Event onBeforeUpdate; 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 onTextInput; 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; Rendertarget cursorRenderer; Window() = default; 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(); void UpdateCursorImage(); void SetCusorImage(std::uint16_t sizeX, std::uint16_t sizeY); void SetCusorImageDefault(); #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_WIN32 HBITMAP cursorBitmap = nullptr; HCURSOR cursorHandle = nullptr; std::uint16_t cursorSizeX = 0; std::uint16_t cursorSizeY = 0; #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; wl_surface* cursorSurface = nullptr; wl_buffer* cursorWlBuffer = nullptr; std::uint32_t cursorBufferOldSize = 0; 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 VkCommandBuffer StartInit(); void FinishInit(); VkCommandBuffer GetCmd(); void EndCmd(VkCommandBuffer cmd); 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]; VkImageViewCreateInfo 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; PipelineRTVulkan* pipeline; DescriptorHeapVulkan* descriptorHeap; #endif }; }