diff options
| author | skal <pascal.massimino@gmail.com> | 2026-01-28 00:41:07 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-01-28 00:41:07 +0100 |
| commit | a7bcf5e9cd6884d010b5cec0146293a0515242fc (patch) | |
| tree | bcc07dd93e19c7b429363c8cac1e9866762f6e6e /src/platform.cc | |
| parent | 9dcf94ab01269311b4e5d39be23c95560904c626 (diff) | |
feat: Implement fullscreen, keyboard controls, and pulsating heptagon
This commit fulfills tasks 1 and 2, and adds a synchronized visual effect.
- **Fullscreen Mode**: Added '--fullscreen' command-line argument and dynamic toggling via 'F' key.
- **Keyboard Controls**: Implemented 'Esc' to exit and 'F' to toggle fullscreen in 'src/platform.cc'.
- **Synchronized Visuals**: Added a pulsating heptagon effect in 'src/gpu/gpu.cc' and 'src/gpu/shader.wgsl' that scales and changes color based on the real-time audio peak from the synth.
- **Refactor**: Abstracted platform-specific WebGPU surface creation into 'src/platform.cc' to keep 'src/gpu/gpu.cc' cross-platform.
- **Build System**: Corrected 'CMakeLists.txt' to properly link 'wgpu-native' and platform frameworks, and updated 'project_init.sh' to build the submodule.
- **Documentation**: Updated 'HOWTO.md' and 'PROJECT_CONTEXT.md' with new features and decisions.
Diffstat (limited to 'src/platform.cc')
| -rw-r--r-- | src/platform.cc | 137 |
1 files changed, 126 insertions, 11 deletions
diff --git a/src/platform.cc b/src/platform.cc index bfb566c..09cc7ac 100644 --- a/src/platform.cc +++ b/src/platform.cc @@ -1,11 +1,55 @@ #include "platform.h" + +#ifdef _WIN32 +#define GLFW_EXPOSE_NATIVE_WIN32 +#elif defined(__APPLE__) +#define GLFW_EXPOSE_NATIVE_COCOA +#else +#define GLFW_EXPOSE_NATIVE_X11 +#define GLFW_EXPOSE_NATIVE_WAYLAND +#endif + #include <GLFW/glfw3.h> +#include <GLFW/glfw3native.h> + +#ifdef __APPLE__ +#import <QuartzCore/CAMetalLayer.h> +#import <AppKit/NSWindow.h> +#import <AppKit/NSView.h> +#endif static GLFWwindow *window = nullptr; +static int windowed_x, windowed_y, windowed_w, windowed_h; +static bool g_is_fullscreen = false; -void platform_init() { +static void glfw_key_callback(GLFWwindow *cb_window, int key, int scancode, + int action, int mods) { + if (action == GLFW_PRESS) { + if (key == GLFW_KEY_ESCAPE) { + glfwSetWindowShouldClose(cb_window, GLFW_TRUE); + } else if (key == GLFW_KEY_F) { + platform_toggle_fullscreen(); + } + } +} + +void platform_init_window(bool fullscreen) { glfwInit(); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); window = glfwCreateWindow(1280, 720, "demo64k", nullptr, nullptr); + glfwSetKeyCallback(window, glfw_key_callback); + + g_is_fullscreen = fullscreen; + if (fullscreen) { + // Save current windowed mode dimensions before going fullscreen + glfwGetWindowPos(window, &windowed_x, &windowed_y); + glfwGetWindowSize(window, &windowed_w, &windowed_h); + + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, + mode->refreshRate); + } } void platform_shutdown() { @@ -13,18 +57,89 @@ void platform_shutdown() { glfwTerminate(); } -void platform_poll() { - glfwPollEvents(); -} +void platform_poll() { glfwPollEvents(); } -bool platform_should_close() { - return glfwWindowShouldClose(window); -} +bool platform_should_close() { return glfwWindowShouldClose(window); } + +void platform_toggle_fullscreen() { + g_is_fullscreen = !g_is_fullscreen; + if (g_is_fullscreen) { + glfwGetWindowPos(window, &windowed_x, &windowed_y); + glfwGetWindowSize(window, &windowed_w, &windowed_h); -GLFWwindow *platform_get_window() { - return window; + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, + mode->refreshRate); + } else { + glfwSetWindowMonitor(window, nullptr, windowed_x, windowed_y, windowed_w, + windowed_h, 0); + } } -double platform_get_time() { - return glfwGetTime(); +GLFWwindow *platform_get_window() { return window; } + +double platform_get_time() { return glfwGetTime(); } + +WGPUSurface platform_create_wgpu_surface(WGPUInstance instance) { +#if defined(GLFW_EXPOSE_NATIVE_COCOA) + id metal_layer = NULL; + NSWindow *ns_window = glfwGetCocoaWindow(window); + [ns_window.contentView setWantsLayer:YES]; + metal_layer = [CAMetalLayer layer]; + [ns_window.contentView setLayer:metal_layer]; + + WGPUSurfaceSourceMetalLayer metal_src = {}; + metal_src.chain.sType = WGPUSType_SurfaceSourceMetalLayer; + metal_src.layer = metal_layer; + + WGPUSurfaceDescriptor surface_desc = {}; + surface_desc.nextInChain = (const WGPUChainedStruct *)&metal_src; + + return wgpuInstanceCreateSurface(instance, &surface_desc); + +#elif defined(GLFW_EXPOSE_NATIVE_WIN32) + HWND hwnd = glfwGetWin32Window(window); + HINSTANCE hinstance = GetModuleHandle(NULL); + + WGPUSurfaceSourceWindowsHWND win_src = {}; + win_src.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; + win_src.hinstance = hinstance; + win_src.hwnd = hwnd; + + WGPUSurfaceDescriptor surface_desc = {}; + surface_desc.nextInChain = (const WGPUChainedStruct *)&win_src; + + return wgpuInstanceCreateSurface(instance, &surface_desc); + +#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_WAYLAND) + if (glfwGetPlatform() == GLFW_PLATFORM_X11) { + Display *x11_display = glfwGetX11Display(); + Window x11_window = glfwGetX11Window(window); + + WGPUSurfaceSourceXlibWindow x11_src = {}; + x11_src.chain.sType = WGPUSType_SurfaceSourceXlibWindow; + x11_src.display = x11_display; + x11_src.window = x11_window; + + WGPUSurfaceDescriptor surface_desc = {}; + surface_desc.nextInChain = (const WGPUChainedStruct *)&x11_src; + + return wgpuInstanceCreateSurface(instance, &surface_desc); + } else if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) { + struct wl_display *wayland_display = glfwGetWaylandDisplay(); + struct wl_surface *wayland_surface = glfwGetWaylandWindow(window); + + WGPUSurfaceSourceWaylandSurface wl_src = {}; + wl_src.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; + wl_src.display = wayland_display; + wl_src.surface = wayland_surface; + + WGPUSurfaceDescriptor surface_desc = {}; + surface_desc.nextInChain = (const WGPUChainedStruct *)&wl_src; + + return wgpuInstanceCreateSurface(instance, &surface_desc); + } +#endif + return nullptr; } |
