0 | 0 |
const c = @import("c.zig");
|
1 | 1 |
const builtin = @import("builtin");
|
|
2 |
const debug = @import("std").debug;
|
|
3 |
const math = @import("std").math;
|
|
4 |
|
2 | 5 |
pub const ClientApi = enum {
|
3 | 6 |
Unknown,
|
4 | 7 |
OpenGL,
|
|
8 | 11 |
// Data
|
9 | 12 |
var g_Window: ?*c.GLFWwindow = null;
|
10 | 13 |
var g_ClientApi: ClientApi = .Unknown;
|
11 | |
var g_Time: f32 = 0.0;
|
|
14 |
var g_Time: f64 = 0.0;
|
12 | 15 |
var g_MouseJustPressed = [_]bool{ false } ** 5;
|
13 | 16 |
var g_MouseCursors = [_]?*c.GLFWcursor{ null } ** @enumToInt(c.ImGuiMouseCursor_COUNT);
|
14 | 17 |
var g_WantUpdateMonitors = true;
|
15 | 18 |
|
16 | 19 |
// Chain GLFW callbacks for main viewport:
|
17 | 20 |
// our callbacks will call the user's previously installed callbacks, if any.
|
18 | |
var g_PrevUserCallbackMousebutton: ?c.GLFWmousebuttonfun = null;
|
19 | |
var g_PrevUserCallbackScroll: ?c.GLFWscrollfun = null;
|
20 | |
var g_PrevUserCallbackKey: ?c.GLFWkeyfun = null;
|
21 | |
var g_PrevUserCallbackChar: ?c.GLFWcharfun = null;
|
|
21 |
var g_PrevUserCallbackMousebutton: c.GLFWmousebuttonfun = null;
|
|
22 |
var g_PrevUserCallbackScroll: c.GLFWscrollfun = null;
|
|
23 |
var g_PrevUserCallbackKey: c.GLFWkeyfun = null;
|
|
24 |
var g_PrevUserCallbackChar: c.GLFWcharfun = null;
|
22 | 25 |
|
23 | 26 |
pub fn Init(window: *c.GLFWwindow, install_callbacks: bool, client_api: ClientApi) void {
|
24 | 27 |
g_Window = window;
|
|
28 | 31 |
const io = c.igGetIO();
|
29 | 32 |
io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasMouseCursors); // We can honor GetMouseCursor() values (optional)
|
30 | 33 |
io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasSetMousePos); // We can honor io.WantSetMousePos requests (optional, rarely used)
|
31 | |
io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_PlatformHasViewports); // We can create multi-viewports on the Platform side (optional)
|
32 | |
if (@hasField(c, "GLFW_HAS_GLFW_HOVERED") and builtin.os == builtin.Os.windows) {
|
|
34 |
if (false) io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_PlatformHasViewports); // We can create multi-viewports on the Platform side (optional)
|
|
35 |
if (false and @hasField(c, "GLFW_HAS_GLFW_HOVERED") and builtin.os == builtin.Os.windows) {
|
33 | 36 |
io.*.BackendFlags |= @enumToInt(ImGuiBackendFlags_HasMouseHoveredViewport); // We can set io.MouseHoveredViewport correctly (optional, not easy)
|
34 | 37 |
}
|
35 | 38 |
io.*.BackendPlatformName = c"imgui_impl_glfw.zig";
|
|
61 | 64 |
// @TODO: Clipboard
|
62 | 65 |
// io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
63 | 66 |
// io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
64 | |
// io.ClipboardUserData = g_Window;
|
|
67 |
io.*.ClipboardUserData = g_Window;
|
65 | 68 |
|
66 | 69 |
g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR);
|
67 | 70 |
g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_TextInput)] = c.glfwCreateStandardCursor(c.GLFW_IBEAM_CURSOR);
|
|
87 | 90 |
// Our mouse update function expect PlatformHandle to be filled for the main viewport
|
88 | 91 |
const main_viewport = c.igGetMainViewport();
|
89 | 92 |
main_viewport.*.PlatformHandle = g_Window;
|
90 | |
if (builtin.os == builtin.Os.windows) {
|
|
93 |
if (builtin.os == builtin.Os.windows)
|
91 | 94 |
main_viewport.*.PlatformHandleRaw = c.glfwGetWin32Window(g_Window);
|
92 | |
}
|
93 | 95 |
|
94 | 96 |
// @TODO: Platform Interface (Viewport)
|
95 | |
// if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable != 0)
|
96 | |
// ImGui_ImplGlfw_InitPlatformInterface();
|
|
97 |
if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0)
|
|
98 |
unreachable;
|
|
99 |
// ImGui_ImplGlfw_InitPlatformInterface();
|
97 | 100 |
|
98 | 101 |
g_ClientApi = client_api;
|
99 | 102 |
}
|
|
111 | 114 |
|
112 | 115 |
pub fn NewFrame() void {
|
113 | 116 |
const io = c.igGetIO();
|
114 | |
// @TODO: assert font atlas
|
|
117 |
debug.assert(c.ImFontAtlas_IsBuilt(io.*.Fonts));
|
115 | 118 |
|
116 | 119 |
var w : c_int = undefined;
|
117 | 120 |
var h : c_int = undefined;
|
|
120 | 123 |
c.glfwGetWindowSize(g_Window, &w, &h);
|
121 | 124 |
c.glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
122 | 125 |
io.*.DisplaySize = c.ImVec2{ .x = @intToFloat(f32, w), .y = @intToFloat(f32, h) };
|
|
126 |
|
|
127 |
if (w > 0 and h > 0)
|
|
128 |
io.*.DisplayFramebufferScale = c.ImVec2{
|
|
129 |
.x = @intToFloat(f32, display_w) / @intToFloat(f32, w),
|
|
130 |
.y = @intToFloat(f32, display_h) / @intToFloat(f32, h),
|
|
131 |
};
|
|
132 |
if (g_WantUpdateMonitors)
|
|
133 |
UpdateMonitors();
|
|
134 |
|
|
135 |
// Setup time step
|
|
136 |
const current_time = c.glfwGetTime();
|
|
137 |
io.*.DeltaTime = if (g_Time > 0.0) @floatCast(f32, current_time - g_Time) else 1.0 / 60.0;
|
|
138 |
g_Time = current_time;
|
|
139 |
|
|
140 |
UpdateMousePosAndButtons();
|
|
141 |
UpdateMouseCursor();
|
|
142 |
|
|
143 |
UpdateGamepads();
|
|
144 |
}
|
|
145 |
|
|
146 |
fn UpdateMonitors() void {
|
|
147 |
// @TODO
|
|
148 |
}
|
|
149 |
|
|
150 |
fn UpdateMousePosAndButtons() void {
|
|
151 |
// Update buttons
|
|
152 |
const io = c.igGetIO();
|
|
153 |
for (io.*.MouseDown) |*isDown, i| {
|
|
154 |
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
|
155 |
isDown.* = g_MouseJustPressed[i] or c.glfwGetMouseButton(g_Window, @intCast(c_int, i)) != 0;
|
|
156 |
g_MouseJustPressed[i] = false;
|
|
157 |
}
|
|
158 |
|
|
159 |
// Update mouse position
|
|
160 |
const mouse_pos_backup = io.*.MousePos;
|
|
161 |
io.*.MousePos = c.ImVec2{ .x = math.f32_min, .y = math.f32_min };
|
|
162 |
io.*.MouseHoveredViewport = 0;
|
|
163 |
const platform_io = c.igGetPlatformIO();
|
|
164 |
var n : usize = 0;
|
|
165 |
while (n < @intCast(usize, platform_io.*.Viewports.Size)) : (n += 1) {
|
|
166 |
const viewport = platform_io.*.Viewports.Data[n];
|
|
167 |
const window = @ptrCast(*c.GLFWwindow, viewport.*.PlatformHandle);
|
|
168 |
const focused = c.glfwGetWindowAttrib(window, c.GLFW_FOCUSED) != 0;
|
|
169 |
if (focused) {
|
|
170 |
if (io.*.WantSetMousePos) {
|
|
171 |
c.glfwSetCursorPos(window, mouse_pos_backup.x - viewport.*.Pos.x, mouse_pos_backup.y - viewport.*.Pos.y);
|
|
172 |
} else {
|
|
173 |
var mouse_x : f64 = undefined;
|
|
174 |
var mouse_y : f64 = undefined;
|
|
175 |
c.glfwGetCursorPos(window, &mouse_x, &mouse_y);
|
|
176 |
if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0) {
|
|
177 |
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
|
178 |
var window_x : c_int = undefined;
|
|
179 |
var window_y : c_int = undefined;
|
|
180 |
c.glfwGetWindowPos(window, &window_x, &window_y);
|
|
181 |
io.*.MousePos = c.ImVec2{
|
|
182 |
.x = @floatCast(f32, mouse_x) + @intToFloat(f32, window_x),
|
|
183 |
.y = @floatCast(f32, mouse_y) + @intToFloat(f32, window_y),
|
|
184 |
};
|
|
185 |
} else {
|
|
186 |
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
|
187 |
io.*.MousePos = c.ImVec2{ .x = @floatCast(f32, mouse_x), .y = @floatCast(f32, mouse_y) };
|
|
188 |
}
|
|
189 |
}
|
|
190 |
|
|
191 |
for (io.*.MouseDown) |*isDown, i|
|
|
192 |
isDown.* = isDown.* or c.glfwGetMouseButton(window, @intCast(c_int, i)) != 0;
|
|
193 |
}
|
|
194 |
}
|
|
195 |
}
|
|
196 |
|
|
197 |
fn UpdateMouseCursor() void {
|
|
198 |
const io = c.igGetIO();
|
|
199 |
if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_NoMouseCursorChange) != 0
|
|
200 |
or c.glfwGetInputMode(g_Window, c.GLFW_CURSOR) == c.GLFW_CURSOR_DISABLED)
|
|
201 |
return;
|
|
202 |
|
|
203 |
const imgui_cursor = c.igGetMouseCursor();
|
|
204 |
const platform_io = c.igGetPlatformIO();
|
|
205 |
var n : usize = 0;
|
|
206 |
while (n < @intCast(usize, platform_io.*.Viewports.Size)) : (n += 1) {
|
|
207 |
const window = @ptrCast(*c.GLFWwindow, platform_io.*.Viewports.Data[n].*.PlatformHandle);
|
|
208 |
if (imgui_cursor == @enumToInt(c.ImGuiMouseCursor_None) or io.*.MouseDrawCursor) {
|
|
209 |
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
|
210 |
c.glfwSetInputMode(window, c.GLFW_CURSOR, c.GLFW_CURSOR_HIDDEN);
|
|
211 |
} else {
|
|
212 |
// Show OS mouse cursor
|
|
213 |
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
|
214 |
c.glfwSetCursor(window,
|
|
215 |
if (g_MouseCursors[@intCast(usize, imgui_cursor)]) |cursor| cursor
|
|
216 |
else g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)]);
|
|
217 |
c.glfwSetInputMode(window, c.GLFW_CURSOR, c.GLFW_CURSOR_NORMAL);
|
|
218 |
}
|
|
219 |
}
|
|
220 |
}
|
|
221 |
|
|
222 |
fn UpdateGamepads() void {
|
|
223 |
// @TODO
|
123 | 224 |
}
|
124 | 225 |
|
125 | 226 |
// GLFW Callbacks
|
126 | 227 |
extern fn Callback_MouseButton(window: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) void {
|
127 | |
// @TODO: delegate up
|
|
228 |
if (g_PrevUserCallbackMousebutton) |prev| {
|
|
229 |
prev(window, button, action, mods);
|
|
230 |
}
|
128 | 231 |
|
129 | 232 |
if (button < 0)
|
130 | 233 |
return;
|
|
135 | 238 |
}
|
136 | 239 |
|
137 | 240 |
extern fn Callback_Scroll(window: ?*c.GLFWwindow, dx: f64, dy: f64) void {
|
138 | |
// @TODO: delegate up
|
|
241 |
if (g_PrevUserCallbackScroll) |prev| {
|
|
242 |
prev(window, dx, dy);
|
|
243 |
}
|
139 | 244 |
|
140 | 245 |
const io = c.igGetIO();
|
141 | 246 |
io.*.MouseWheelH += @floatCast(f32, dx);
|
|
143 | 248 |
}
|
144 | 249 |
|
145 | 250 |
extern fn Callback_Key(window: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, modifiers: c_int) void {
|
146 | |
// @TODO: delegate up
|
|
251 |
if (g_PrevUserCallbackKey) |prev| {
|
|
252 |
prev(window, key, scancode, action, modifiers);
|
|
253 |
}
|
147 | 254 |
|
148 | 255 |
if (key < 0)
|
149 | 256 |
unreachable;
|
|
164 | 271 |
}
|
165 | 272 |
|
166 | 273 |
extern fn Callback_Char(window: ?*c.GLFWwindow, char: c_uint) void {
|
167 | |
// @TODO: delegate up
|
|
274 |
if (g_PrevUserCallbackChar) |prev| {
|
|
275 |
prev(window, char);
|
|
276 |
}
|
168 | 277 |
|
169 | 278 |
const io = c.igGetIO();
|
170 | 279 |
c.ImGuiIO_AddInputCharacter(io, char);
|