summaryrefslogtreecommitdiff
path: root/src/platform.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-01-28 00:41:07 +0100
committerskal <pascal.massimino@gmail.com>2026-01-28 00:41:07 +0100
commita7bcf5e9cd6884d010b5cec0146293a0515242fc (patch)
treebcc07dd93e19c7b429363c8cac1e9866762f6e6e /src/platform.cc
parent9dcf94ab01269311b4e5d39be23c95560904c626 (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.cc137
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;
}