summaryrefslogtreecommitdiff
path: root/src/platform.cc
blob: 8df9992f94fe39673d11ef1241a22161b8a5949e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// This file is part of the 64k demo project.
// It implements platform-specific windowing and input using GLFW.
// Handles fullscreen toggling and native surface creation for WebGPU.

#include "platform.h"
#include "glfw3webgpu.h"
#include <GLFW/glfw3.h>

// --- Callbacks ---

static void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    PlatformState* state = (PlatformState*)glfwGetWindowUserPointer(window);
    if (state) {
        state->width = width;
        state->height = height;
    }
}

static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    PlatformState* state = (PlatformState*)glfwGetWindowUserPointer(window);
    if (action == GLFW_PRESS) {
        if (key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) {
            glfwSetWindowShouldClose(window, GLFW_TRUE);
        } else if (key == GLFW_KEY_F) {
            if (state) platform_toggle_fullscreen(state);
        }
    }
}

// --- Public API Implementation ---

void platform_init(PlatformState* state, bool fullscreen, int* width_ptr, int* height_ptr) {
  if (width_ptr && height_ptr) {
      state->width = *width_ptr;
      state->height = *height_ptr;
  }

  glfwInit();
  glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
  state->window = glfwCreateWindow(state->width, state->height, "demo64k", nullptr, nullptr);
  
  // Store our state pointer in the window for callbacks
  glfwSetWindowUserPointer(state->window, state);
  
  // Immediately query the actual framebuffer size for high-DPI displays
  glfwGetFramebufferSize(state->window, &state->width, &state->height);

  glfwSetKeyCallback(state->window, glfw_key_callback);
  glfwSetFramebufferSizeCallback(state->window, framebuffer_size_callback);

  state->is_fullscreen = fullscreen;
  if (fullscreen) {
    glfwGetWindowPos(state->window, &state->windowed_x, &state->windowed_y);
    glfwGetWindowSize(state->window, &state->windowed_w, &state->windowed_h);

    GLFWmonitor* monitor = glfwGetPrimaryMonitor();
    const GLFWvidmode* mode = glfwGetVideoMode(monitor);
    glfwSetWindowMonitor(state->window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
  }
}

void platform_shutdown(PlatformState* state) {
  if (state->window) {
    glfwDestroyWindow(state->window);
  }
  glfwTerminate();
}

void platform_poll(PlatformState* state) {
  glfwPollEvents();
}

bool platform_should_close(PlatformState* state) {
  return glfwWindowShouldClose(state->window);
}

void platform_toggle_fullscreen(PlatformState* state) {
  state->is_fullscreen = !state->is_fullscreen;
  if (state->is_fullscreen) {
    glfwGetWindowPos(state->window, &state->windowed_x, &state->windowed_y);
    glfwGetWindowSize(state->window, &state->windowed_w, &state->windowed_h);

    GLFWmonitor* monitor = glfwGetPrimaryMonitor();
    const GLFWvidmode* mode = glfwGetVideoMode(monitor);
    glfwSetWindowMonitor(state->window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
  } else {
    glfwSetWindowMonitor(state->window, nullptr, state->windowed_x, state->windowed_y, state->windowed_w, state->windowed_h, 0);
  }
}

WGPUSurface platform_create_wgpu_surface(WGPUInstance instance, PlatformState* state) {
  return glfwCreateWindowWGPUSurface(instance, state->window);
}

// Note: platform_get_* functions are now inline in the header.
// platform_get_time() remains global.