git.s-ol.nu zig-imgui / f0315f0
zig-fmt everything s-ol 2 years ago
5 changed file(s) with 738 addition(s) and 734 deletion(s). Raw diff Collapse all Expand all
00 zig-cache
1 imgui.ini
00 pub usingnamespace @cImport({
1 @cInclude("epoxy/gl.h");
2 @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", "1");
3 @cInclude("cimgui.h");
4 @cInclude("GLFW/glfw3.h");
1 @cInclude("epoxy/gl.h");
2 @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", "1");
3 @cInclude("cimgui.h");
4 @cInclude("GLFW/glfw3.h");
55 });
0 /// this is a port of cimgui/imgui/examples/imgui_impl_opengl3.cpp
01 const c = @import("c.zig");
12 const mem = @import("std").mem;
23 const math = @import("std").math;
45 const builtin = @import("builtin");
56
67 const OpenGLHasDrawWithBaseVertex = @hasField(c, "IMGUI_IMPL_OPENGL_ES2") or
7 @hasField(c, "IMGUI_IMPL_OPENGL_ES3");
8 @hasField(c, "IMGUI_IMPL_OPENGL_ES3");
89
910 // OpenGL Data
10 var g_GlslVersionString_buf : [32]u8 = undefined;
11 var g_GlslVersionString : []u8 = g_GlslVersionString_buf[0..0];
12
13 var g_FontTexture : c.GLuint = 0;
14 var g_ShaderHandle : c.GLuint = 0;
15 var g_VertHandle : c.GLuint = 0;
11 var g_GlslVersionString_buf: [32]u8 = undefined;
12 var g_GlslVersionString: []u8 = g_GlslVersionString_buf[0..0];
13
14 var g_FontTexture: c.GLuint = 0;
15 var g_ShaderHandle: c.GLuint = 0;
16 var g_VertHandle: c.GLuint = 0;
1617 var g_FragHandle: c.GLuint = 0;
17 var g_AttribLocationTex : c.GLint = 0;
18 var g_AttribLocationProjMtx : c.GLint = 0;
19 var g_AttribLocationVtxPos : c.GLint = 0;
20 var g_AttribLocationVtxUV : c.GLint = 0;
21 var g_AttribLocationVtxColor : c.GLint = 0;
22 var g_VboHandle : c.GLuint = 0;
23 var g_ElementsHandle : c.GLuint = 0;
18 var g_AttribLocationTex: c.GLint = 0;
19 var g_AttribLocationProjMtx: c.GLint = 0;
20 var g_AttribLocationVtxPos: c.GLint = 0;
21 var g_AttribLocationVtxUV: c.GLint = 0;
22 var g_AttribLocationVtxColor: c.GLint = 0;
23 var g_VboHandle: c.GLuint = 0;
24 var g_ElementsHandle: c.GLuint = 0;
2425
2526 pub fn Init() void {
26 const io = c.igGetIO();
27 io.*.BackendRendererName = c"imgui_impl_gl3.zig";
28 if (OpenGLHasDrawWithBaseVertex)
29 io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_RendererHasVtxOffset);
30 // @TODO: Viewports
31 // io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_RendererHasViewports);
32
33 // @TODO: GLSL versions?
34 // g_GlslVersionString = g_GlslVersionString_buf[0..glsl_version.len];
35 // mem.copy(u8, g_GlslVersionString, glsl_version);
36
37 // @FIXME: just for testing:
38 var tex : c.GLint = undefined;
39 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &tex);
40
41 // @TODO: Viewports
42 // if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0)
43 // InitPlatformInterface();
27 const io = c.igGetIO();
28 io.*.BackendRendererName = c"imgui_impl_gl3.zig";
29 if (OpenGLHasDrawWithBaseVertex)
30 io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_RendererHasVtxOffset);
31 // @TODO: Viewports
32 // io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_RendererHasViewports);
33
34 // @TODO: GLSL versions?
35 // g_GlslVersionString = g_GlslVersionString_buf[0..glsl_version.len];
36 // mem.copy(u8, g_GlslVersionString, glsl_version);
37
38 // @FIXME: just for testing:
39 var tex: c.GLint = undefined;
40 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &tex);
41
42 // @TODO: Viewports
43 // if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0)
44 // InitPlatformInterface();
4445 }
4546
4647 pub fn Shutdown() void {
47 // ImGui_ImplOpenGL3_ShutdownPlatformInterface();
48 DestroyDeviceObjects();
48 // ImGui_ImplOpenGL3_ShutdownPlatformInterface();
49 DestroyDeviceObjects();
4950 }
5051
5152 pub fn NewFrame() !void {
52 if (g_ShaderHandle == 0)
53 try CreateDeviceObjects();
53 if (g_ShaderHandle == 0)
54 try CreateDeviceObjects();
5455 }
5556
5657 fn CreateDeviceObjects() !void {
57 // back up GL state
58 var last_texture : c.GLint = undefined;
59 var last_array_buffer : c.GLint = undefined;
60 var last_vertex_array : c.GLint = undefined;
61
62 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &last_texture);
63 defer c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, last_texture));
64
65 c.glGetIntegerv(c.GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
66 c.glBindBuffer(c.GL_ARRAY_BUFFER, @intCast(c.GLuint, last_array_buffer));
67
68 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
69 c.glGetIntegerv(c.GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
70 defer if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
71 c.glBindVertexArray(@intCast(c.GLuint, last_vertex_array));
72
73 // @TODO: GLSL versions?
74 const vertex_shader_glsl : [*]const c.GLchar =
75 c\\#version 150
76 c\\uniform mat4 ProjMtx;
77 c\\in vec2 Position;
78 c\\in vec2 UV;
79 c\\in vec4 Color;
80 c\\out vec2 Frag_UV;
81 c\\out vec4 Frag_Color;
82 c\\void main()
83 c\\{
84 c\\ Frag_UV = UV;
85 c\\ Frag_Color = Color;
86 c\\ gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
87 c\\}
88 ;
89
90 const fragment_shader_glsl : [*]const c.GLchar =
91 c\\#version 150
92 c\\uniform sampler2D Texture;
93 c\\in vec2 Frag_UV;
94 c\\in vec4 Frag_Color;
95 c\\out vec4 Out_Color;
96 c\\void main()
97 c\\{
98 c\\ Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
99 c\\}
100 ;
101
102 // Create shaders / programs
103 g_VertHandle = c.glCreateShader(c.GL_VERTEX_SHADER);
104 c.glShaderSource(g_VertHandle, 1, &vertex_shader_glsl, null);
105 c.glCompileShader(g_VertHandle);
106 try CheckThing(.Shader, g_VertHandle, "vertex shader");
107
108 g_FragHandle = c.glCreateShader(c.GL_FRAGMENT_SHADER);
109 c.glShaderSource(g_FragHandle, 1, &fragment_shader_glsl, null);
110 c.glCompileShader(g_FragHandle);
111 try CheckThing(.Shader, g_FragHandle, "fragment shader");
112
113 g_ShaderHandle = c.glCreateProgram();
114 c.glAttachShader(g_ShaderHandle, g_VertHandle);
115 c.glAttachShader(g_ShaderHandle, g_FragHandle);
116 c.glLinkProgram(g_ShaderHandle);
117 try CheckThing(.Program, g_ShaderHandle, "shader program");
118
119 g_AttribLocationTex = c.glGetUniformLocation(g_ShaderHandle, c"Texture");
120 g_AttribLocationProjMtx = c.glGetUniformLocation(g_ShaderHandle, c"ProjMtx");
121 g_AttribLocationVtxPos = c.glGetAttribLocation(g_ShaderHandle, c"Position");
122 g_AttribLocationVtxUV = c.glGetAttribLocation(g_ShaderHandle, c"UV");
123 g_AttribLocationVtxColor = c.glGetAttribLocation(g_ShaderHandle, c"Color");
124
125 // Create buffers
126 c.glGenBuffers(1, &g_VboHandle);
127 c.glGenBuffers(1, &g_ElementsHandle);
128
129 CreateFontsTexture();
130 }
131
58 // back up GL state
59 var last_texture: c.GLint = undefined;
60 var last_array_buffer: c.GLint = undefined;
61 var last_vertex_array: c.GLint = undefined;
62
63 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &last_texture);
64 defer c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, last_texture));
65
66 c.glGetIntegerv(c.GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
67 c.glBindBuffer(c.GL_ARRAY_BUFFER, @intCast(c.GLuint, last_array_buffer));
68
69 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
70 c.glGetIntegerv(c.GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
71 defer if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
72 c.glBindVertexArray(@intCast(c.GLuint, last_vertex_array));
73
74 // @TODO: GLSL versions?
75 const vertex_shader_glsl: [*]const c.GLchar =
76 c\\#version 150
77 c\\uniform mat4 ProjMtx;
78 c\\in vec2 Position;
79 c\\in vec2 UV;
80 c\\in vec4 Color;
81 c\\out vec2 Frag_UV;
82 c\\out vec4 Frag_Color;
83 c\\void main()
84 c\\{
85 c\\ Frag_UV = UV;
86 c\\ Frag_Color = Color;
87 c\\ gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
88 c\\}
89 ;
90
91 const fragment_shader_glsl: [*]const c.GLchar =
92 c\\#version 150
93 c\\uniform sampler2D Texture;
94 c\\in vec2 Frag_UV;
95 c\\in vec4 Frag_Color;
96 c\\out vec4 Out_Color;
97 c\\void main()
98 c\\{
99 c\\ Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
100 c\\}
101 ;
102
103 // Create shaders / programs
104 g_VertHandle = c.glCreateShader(c.GL_VERTEX_SHADER);
105 c.glShaderSource(g_VertHandle, 1, &vertex_shader_glsl, null);
106 c.glCompileShader(g_VertHandle);
107 try CheckThing(.Shader, g_VertHandle, "vertex shader");
108
109 g_FragHandle = c.glCreateShader(c.GL_FRAGMENT_SHADER);
110 c.glShaderSource(g_FragHandle, 1, &fragment_shader_glsl, null);
111 c.glCompileShader(g_FragHandle);
112 try CheckThing(.Shader, g_FragHandle, "fragment shader");
113
114 g_ShaderHandle = c.glCreateProgram();
115 c.glAttachShader(g_ShaderHandle, g_VertHandle);
116 c.glAttachShader(g_ShaderHandle, g_FragHandle);
117 c.glLinkProgram(g_ShaderHandle);
118 try CheckThing(.Program, g_ShaderHandle, "shader program");
119
120 g_AttribLocationTex = c.glGetUniformLocation(g_ShaderHandle, c"Texture");
121 g_AttribLocationProjMtx = c.glGetUniformLocation(g_ShaderHandle, c"ProjMtx");
122 g_AttribLocationVtxPos = c.glGetAttribLocation(g_ShaderHandle, c"Position");
123 g_AttribLocationVtxUV = c.glGetAttribLocation(g_ShaderHandle, c"UV");
124 g_AttribLocationVtxColor = c.glGetAttribLocation(g_ShaderHandle, c"Color");
125
126 // Create buffers
127 c.glGenBuffers(1, &g_VboHandle);
128 c.glGenBuffers(1, &g_ElementsHandle);
129
130 CreateFontsTexture();
131 }
132132
133133 const CheckableThing = enum {
134 Shader,
135 Program,
134 Shader,
135 Program,
136136 };
137137 fn CheckThing(comptime thingType: CheckableThing, handle: c.GLuint, desc: []const u8) !void {
138 var status : c.GLint = undefined;
139 var log_length : c.GLint = undefined;
140 const getInfoLogFunc = switch (thingType) {
141 .Shader => blk: {
142 c.glGetShaderiv(handle, c.GL_COMPILE_STATUS, &status);
143 c.glGetShaderiv(handle, c.GL_INFO_LOG_LENGTH, &log_length);
144 break :blk c.glGetShaderInfoLog;
145 },
146 .Program => blk: {
147 c.glGetProgramiv(handle, c.GL_LINK_STATUS, &status);
148 c.glGetProgramiv(handle, c.GL_INFO_LOG_LENGTH, &log_length);
149 break :blk c.glGetProgramInfoLog;
150 },
151 };
152
153 if (log_length > 1)
154 {
155 var buf : [1024]u8 = undefined;
156 var length : c.GLsizei = undefined;
157 getInfoLogFunc(handle, buf.len, &length, &buf[0]);
158 debug.warn("{}\n", buf[0..@intCast(usize, length)]);
159 }
160
161 if (@intCast(c.GLboolean, status) == c.GL_FALSE) {
162 debug.warn("ERROR: CreateDeviceObjects: failed to compile/link {}! (with GLSL '{}')\n", desc, g_GlslVersionString);
163 return error.ShaderLinkError;
164 }
138 var status: c.GLint = undefined;
139 var log_length: c.GLint = undefined;
140 const getInfoLogFunc = switch (thingType) {
141 .Shader => blk: {
142 c.glGetShaderiv(handle, c.GL_COMPILE_STATUS, &status);
143 c.glGetShaderiv(handle, c.GL_INFO_LOG_LENGTH, &log_length);
144 break :blk c.glGetShaderInfoLog;
145 },
146 .Program => blk: {
147 c.glGetProgramiv(handle, c.GL_LINK_STATUS, &status);
148 c.glGetProgramiv(handle, c.GL_INFO_LOG_LENGTH, &log_length);
149 break :blk c.glGetProgramInfoLog;
150 },
151 };
152
153 if (log_length > 1) {
154 var buf: [1024]u8 = undefined;
155 var length: c.GLsizei = undefined;
156 getInfoLogFunc(handle, buf.len, &length, &buf[0]);
157 debug.warn("{}\n", buf[0..@intCast(usize, length)]);
158 }
159
160 if (@intCast(c.GLboolean, status) == c.GL_FALSE) {
161 debug.warn("ERROR: CreateDeviceObjects: failed to compile/link {}! (with GLSL '{}')\n", desc, g_GlslVersionString);
162 return error.ShaderLinkError;
163 }
165164 }
166165
167166 fn DestroyDeviceObjects() void {
168 if (g_VboHandle != 0) {
169 c.glDeleteBuffers(1, &g_VboHandle);
170 g_VboHandle = 0;
171 }
172
173 if (g_ElementsHandle != 0) {
174 c.glDeleteBuffers(1, &g_ElementsHandle);
175 g_ElementsHandle = 0;
176 }
177
178 if (g_ShaderHandle != 0 and g_VertHandle != 0)
179 c.glDetachShader(g_ShaderHandle, g_VertHandle);
180
181 if (g_ShaderHandle != 0 and g_FragHandle != 0)
182 c.glDetachShader(g_ShaderHandle, g_FragHandle);
183
184 if (g_VertHandle != 0) {
185 c.glDeleteShader(g_VertHandle);
186 g_VertHandle = 0;
187 }
188
189 if (g_FragHandle != 0) {
190 c.glDeleteShader(g_FragHandle);
191 g_FragHandle = 0;
192 }
193
194 if (g_ShaderHandle != 0) {
195 c.glDeleteProgram(g_ShaderHandle);
196 g_ShaderHandle = 0;
197 }
198
199 DestroyFontsTexture();
167 if (g_VboHandle != 0) {
168 c.glDeleteBuffers(1, &g_VboHandle);
169 g_VboHandle = 0;
170 }
171
172 if (g_ElementsHandle != 0) {
173 c.glDeleteBuffers(1, &g_ElementsHandle);
174 g_ElementsHandle = 0;
175 }
176
177 if (g_ShaderHandle != 0 and g_VertHandle != 0)
178 c.glDetachShader(g_ShaderHandle, g_VertHandle);
179
180 if (g_ShaderHandle != 0 and g_FragHandle != 0)
181 c.glDetachShader(g_ShaderHandle, g_FragHandle);
182
183 if (g_VertHandle != 0) {
184 c.glDeleteShader(g_VertHandle);
185 g_VertHandle = 0;
186 }
187
188 if (g_FragHandle != 0) {
189 c.glDeleteShader(g_FragHandle);
190 g_FragHandle = 0;
191 }
192
193 if (g_ShaderHandle != 0) {
194 c.glDeleteProgram(g_ShaderHandle);
195 g_ShaderHandle = 0;
196 }
197
198 DestroyFontsTexture();
200199 }
201200
202201 fn CreateFontsTexture() void {
203 const io = c.igGetIO();
204
205 // Get current font image data
206 var width : c_int = undefined;
207 var height : c_int = undefined;
208 var pixels : [*c]u8 = undefined;
209 c.ImFontAtlas_GetTexDataAsRGBA32(io.*.Fonts, &pixels, &width, &height, null);
210
211 // backup & restore state
212 var last_texture : c.GLint = undefined;
213 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &last_texture);
214 defer c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, last_texture));
215
216 // Upload texture to graphics system
217 c.glGenTextures(1, &g_FontTexture);
218 c.glBindTexture(c.GL_TEXTURE_2D, g_FontTexture);
219 c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR);
220 c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR);
221 if (@hasField(c, "GL_UNPACK_ROW_LENGTH"))
222 c.glPixelStorei(c.GL_UNPACK_ROW_LENGTH, 0);
223 c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, pixels);
224
225 // Store texture ID
226 io.*.Fonts.*.TexID = @intToPtr(c.ImTextureID, g_FontTexture);
202 const io = c.igGetIO();
203
204 // Get current font image data
205 var width: c_int = undefined;
206 var height: c_int = undefined;
207 var pixels: [*c]u8 = undefined;
208 c.ImFontAtlas_GetTexDataAsRGBA32(io.*.Fonts, &pixels, &width, &height, null);
209
210 // backup & restore state
211 var last_texture: c.GLint = undefined;
212 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &last_texture);
213 defer c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, last_texture));
214
215 // Upload texture to graphics system
216 c.glGenTextures(1, &g_FontTexture);
217 c.glBindTexture(c.GL_TEXTURE_2D, g_FontTexture);
218 c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR);
219 c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR);
220 if (@hasField(c, "GL_UNPACK_ROW_LENGTH"))
221 c.glPixelStorei(c.GL_UNPACK_ROW_LENGTH, 0);
222 c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, pixels);
223
224 // Store texture ID
225 io.*.Fonts.*.TexID = @intToPtr(c.ImTextureID, g_FontTexture);
227226 }
228227
229228 fn DestroyFontsTexture() void {
230 if (g_FontTexture == 0)
231 return;
232
233 const io = c.igGetIO();
234 c.glDeleteTextures(1, &g_FontTexture);
235 io.*.Fonts.*.TexID = @intToPtr(c.ImTextureID, 0);
236 g_FontTexture = 0;
237 }
238
239 pub fn RenderDrawData(draw_data : *c.ImDrawData) void {
240 // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
241 const fb_width = @floatToInt(i32, draw_data.*.DisplaySize.x * draw_data.*.FramebufferScale.x);
242 const fb_height = @floatToInt(i32, draw_data.*.DisplaySize.y * draw_data.*.FramebufferScale.y);
243 if (fb_width <= 0 or fb_height <= 0)
244 return;
245
246 // Backup GL state
247 var last_program : c.GLint = undefined;
248 var last_texture : c.GLint = undefined;
249 var last_sampler : c.GLint = undefined;
250 var last_array_buffer : c.GLint = undefined;
251 var last_vertex_array_object : c.GLint = undefined;
252 var last_polygon_mode : [2]c.GLint = undefined;
253 var last_viewport : [4]c.GLint = undefined;
254 var last_scissor_box : [4]c.GLint = undefined;
255 var last_blend_src_rgb : c.GLint = undefined;
256 var last_blend_dst_rgb : c.GLint = undefined;
257 var last_blend_src_alpha : c.GLint = undefined;
258 var last_blend_dst_alpha : c.GLint = undefined;
259 var last_blend_equation_rgb : c.GLint = undefined;
260 var last_blend_equation_alpha : c.GLint = undefined;
261 var clip_origin_lower_left : bool = true;
262 var last_clip_origin : c.GLint = 0;
263 var last_active_texture : c.GLint = undefined;
264
265 c.glGetIntegerv(c.GL_ACTIVE_TEXTURE, &last_active_texture);
266 c.glActiveTexture(c.GL_TEXTURE0);
267 c.glGetIntegerv(c.GL_CURRENT_PROGRAM, &last_program);
268 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &last_texture);
269 if (@hasField(c, "GL_SAMPLER_BINDING"))
270 c.glGetIntegerv(c.GL_SAMPLER_BINDING, &last_sampler);
271 c.glGetIntegerv(c.GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
272 if (!@hasField(c, "IMGUI_IMPL_OPENc.GL_ES2"))
273 c.glGetIntegerv(c.GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);
274 if (@hasField(c, "GL_POLYGON_MODE"))
275 c.glGetIntegerv(c.GL_POLYGON_MODE, last_polygon_mode);
276 c.glGetIntegerv(c.GL_VIEWPORT, &last_viewport[0]);
277 c.glGetIntegerv(c.GL_SCISSOR_BOX, &last_scissor_box[0]);
278 c.glGetIntegerv(c.GL_BLEND_SRC_RGB, &last_blend_src_rgb);
279 c.glGetIntegerv(c.GL_BLEND_DST_RGB, &last_blend_dst_rgb);
280 c.glGetIntegerv(c.GL_BLEND_SRC_ALPHA, &last_blend_src_alpha);
281 c.glGetIntegerv(c.GL_BLEND_DST_ALPHA, &last_blend_dst_alpha);
282 c.glGetIntegerv(c.GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb);
283 c.glGetIntegerv(c.GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha);
284 var last_enable_blend : c.GLboolean = c.glIsEnabled(c.GL_BLEND);
285 var last_enable_cull_face : c.GLboolean = c.glIsEnabled(c.GL_CULL_FACE);
286 var last_enable_depth_test : c.GLboolean = c.glIsEnabled(c.GL_DEPTH_TEST);
287 var last_enable_scissor_test : c.GLboolean = c.glIsEnabled(c.GL_SCISSOR_TEST);
288 if (@hasField(c, "GL_CLIP_ORIGIN") and builtin.os != builtin.Os.osx) {
289 // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
290 c.glGetIntegerv(c.GL_CLIP_ORIGIN, &last_clip_origin);
291 if (last_clip_origin == c.GL_UPPER_LEFT)
292 clip_origin_lower_left = false;
293 }
294
295 defer {
296 // Restore modified GL state
297 c.glUseProgram(@intCast(c.GLuint, last_program));
298 c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, last_texture));
229 if (g_FontTexture == 0)
230 return;
231
232 const io = c.igGetIO();
233 c.glDeleteTextures(1, &g_FontTexture);
234 io.*.Fonts.*.TexID = @intToPtr(c.ImTextureID, 0);
235 g_FontTexture = 0;
236 }
237
238 pub fn RenderDrawData(draw_data: *c.ImDrawData) void {
239 // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
240 const fb_width = @floatToInt(i32, draw_data.*.DisplaySize.x * draw_data.*.FramebufferScale.x);
241 const fb_height = @floatToInt(i32, draw_data.*.DisplaySize.y * draw_data.*.FramebufferScale.y);
242 if (fb_width <= 0 or fb_height <= 0)
243 return;
244
245 // Backup GL state
246 var last_program: c.GLint = undefined;
247 var last_texture: c.GLint = undefined;
248 var last_sampler: c.GLint = undefined;
249 var last_array_buffer: c.GLint = undefined;
250 var last_vertex_array_object: c.GLint = undefined;
251 var last_polygon_mode: [2]c.GLint = undefined;
252 var last_viewport: [4]c.GLint = undefined;
253 var last_scissor_box: [4]c.GLint = undefined;
254 var last_blend_src_rgb: c.GLint = undefined;
255 var last_blend_dst_rgb: c.GLint = undefined;
256 var last_blend_src_alpha: c.GLint = undefined;
257 var last_blend_dst_alpha: c.GLint = undefined;
258 var last_blend_equation_rgb: c.GLint = undefined;
259 var last_blend_equation_alpha: c.GLint = undefined;
260 var clip_origin_lower_left: bool = true;
261 var last_clip_origin: c.GLint = 0;
262 var last_active_texture: c.GLint = undefined;
263
264 c.glGetIntegerv(c.GL_ACTIVE_TEXTURE, &last_active_texture);
265 c.glActiveTexture(c.GL_TEXTURE0);
266 c.glGetIntegerv(c.GL_CURRENT_PROGRAM, &last_program);
267 c.glGetIntegerv(c.GL_TEXTURE_BINDING_2D, &last_texture);
299268 if (@hasField(c, "GL_SAMPLER_BINDING"))
300 c.glBindSampler(0, @intCast(c.GLuint, last_sampler));
301 c.glActiveTexture(@intCast(c.GLuint, last_active_texture));
269 c.glGetIntegerv(c.GL_SAMPLER_BINDING, &last_sampler);
270 c.glGetIntegerv(c.GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
271 if (!@hasField(c, "IMGUI_IMPL_OPENc.GL_ES2"))
272 c.glGetIntegerv(c.GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);
273 if (@hasField(c, "GL_POLYGON_MODE"))
274 c.glGetIntegerv(c.GL_POLYGON_MODE, last_polygon_mode);
275 c.glGetIntegerv(c.GL_VIEWPORT, &last_viewport[0]);
276 c.glGetIntegerv(c.GL_SCISSOR_BOX, &last_scissor_box[0]);
277 c.glGetIntegerv(c.GL_BLEND_SRC_RGB, &last_blend_src_rgb);
278 c.glGetIntegerv(c.GL_BLEND_DST_RGB, &last_blend_dst_rgb);
279 c.glGetIntegerv(c.GL_BLEND_SRC_ALPHA, &last_blend_src_alpha);
280 c.glGetIntegerv(c.GL_BLEND_DST_ALPHA, &last_blend_dst_alpha);
281 c.glGetIntegerv(c.GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb);
282 c.glGetIntegerv(c.GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha);
283 var last_enable_blend: c.GLboolean = c.glIsEnabled(c.GL_BLEND);
284 var last_enable_cull_face: c.GLboolean = c.glIsEnabled(c.GL_CULL_FACE);
285 var last_enable_depth_test: c.GLboolean = c.glIsEnabled(c.GL_DEPTH_TEST);
286 var last_enable_scissor_test: c.GLboolean = c.glIsEnabled(c.GL_SCISSOR_TEST);
287 if (@hasField(c, "GL_CLIP_ORIGIN") and builtin.os != builtin.Os.osx) {
288 // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
289 c.glGetIntegerv(c.GL_CLIP_ORIGIN, &last_clip_origin);
290 if (last_clip_origin == c.GL_UPPER_LEFT)
291 clip_origin_lower_left = false;
292 }
293
294 defer {
295 // Restore modified GL state
296 c.glUseProgram(@intCast(c.GLuint, last_program));
297 c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, last_texture));
298 if (@hasField(c, "GL_SAMPLER_BINDING"))
299 c.glBindSampler(0, @intCast(c.GLuint, last_sampler));
300 c.glActiveTexture(@intCast(c.GLuint, last_active_texture));
301 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
302 c.glBindVertexArray(@intCast(c.GLuint, last_vertex_array_object));
303 c.glBindBuffer(c.GL_ARRAY_BUFFER, @intCast(c.GLuint, last_array_buffer));
304 c.glBlendEquationSeparate(@intCast(c.GLuint, last_blend_equation_rgb), @intCast(c.GLuint, last_blend_equation_alpha));
305 c.glBlendFuncSeparate(@intCast(c.GLuint, last_blend_src_rgb), @intCast(c.GLuint, last_blend_dst_rgb), @intCast(c.GLuint, last_blend_src_alpha), @intCast(c.GLuint, last_blend_dst_alpha));
306 if (last_enable_blend == c.GL_TRUE) {
307 c.glEnable(c.GL_BLEND);
308 } else {
309 c.glDisable(c.GL_BLEND);
310 }
311 if (last_enable_cull_face == c.GL_TRUE) {
312 c.glEnable(c.GL_CULL_FACE);
313 } else {
314 c.glDisable(c.GL_CULL_FACE);
315 }
316 if (last_enable_depth_test == c.GL_TRUE) {
317 c.glEnable(c.GL_DEPTH_TEST);
318 } else {
319 c.glDisable(c.GL_DEPTH_TEST);
320 }
321 if (last_enable_scissor_test == c.GL_TRUE) {
322 c.glEnable(c.GL_SCISSOR_TEST);
323 } else {
324 c.glDisable(c.GL_SCISSOR_TEST);
325 }
326 if (@hasField(c, "GL_POLYGON_MODE"))
327 c.glPolygonMode(c.GL_FRONT_AND_BACK, @intCast(c.GLenum, last_polygon_mode[0]));
328 c.glViewport(last_viewport[0], last_viewport[1], @intCast(c.GLsizei, last_viewport[2]), @intCast(c.GLsizei, last_viewport[3]));
329 c.glScissor(last_scissor_box[0], last_scissor_box[1], @intCast(c.GLsizei, last_scissor_box[2]), @intCast(c.GLsizei, last_scissor_box[3]));
330 }
331
332 // Setup desired GL state
333 // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
334 // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
335 var vertex_array_object: c.GLuint = 0;
302336 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
303 c.glBindVertexArray(@intCast(c.GLuint, last_vertex_array_object));
304 c.glBindBuffer(c.GL_ARRAY_BUFFER, @intCast(c.GLuint, last_array_buffer));
305 c.glBlendEquationSeparate(@intCast(c.GLuint, last_blend_equation_rgb), @intCast(c.GLuint, last_blend_equation_alpha));
306 c.glBlendFuncSeparate(@intCast(c.GLuint, last_blend_src_rgb),
307 @intCast(c.GLuint, last_blend_dst_rgb),
308 @intCast(c.GLuint, last_blend_src_alpha),
309 @intCast(c.GLuint, last_blend_dst_alpha));
310 if (last_enable_blend == c.GL_TRUE) { c.glEnable(c.GL_BLEND); }
311 else { c.glDisable(c.GL_BLEND); }
312 if (last_enable_cull_face == c.GL_TRUE) { c.glEnable(c.GL_CULL_FACE); }
313 else { c.glDisable(c.GL_CULL_FACE); }
314 if (last_enable_depth_test == c.GL_TRUE) { c.glEnable(c.GL_DEPTH_TEST); }
315 else { c.glDisable(c.GL_DEPTH_TEST); }
316 if (last_enable_scissor_test == c.GL_TRUE) { c.glEnable(c.GL_SCISSOR_TEST); }
317 else { c.glDisable(c.GL_SCISSOR_TEST); }
337 c.glGenVertexArrays(1, &vertex_array_object);
338 defer if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
339 c.glDeleteVertexArrays(1, &vertex_array_object);
340
341 SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
342
343 // Will project scissor/clipping rectangles into framebuffer space
344 const clip_off = draw_data.*.DisplayPos; // (0,0) unless using multi-viewports
345 const clip_scale = draw_data.*.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
346
347 // Render command lists
348 var n: usize = 0;
349 while (n < @intCast(usize, draw_data.*.CmdListsCount)) : (n += 1) {
350 const cmd_list = draw_data.*.CmdLists[n];
351
352 // Upload vertex/index buffers
353 c.glBufferData(c.GL_ARRAY_BUFFER, cmd_list.*.VtxBuffer.Size * @sizeOf(c.ImDrawVert), @ptrCast(?*c.GLvoid, cmd_list.*.VtxBuffer.Data), c.GL_STREAM_DRAW);
354 c.glBufferData(c.GL_ELEMENT_ARRAY_BUFFER, cmd_list.*.IdxBuffer.Size * @sizeOf(c.ImDrawIdx), @ptrCast(*c.GLvoid, cmd_list.*.IdxBuffer.Data), c.GL_STREAM_DRAW);
355
356 var cmd_i: usize = 0;
357 while (cmd_i < @intCast(usize, cmd_list.*.CmdBuffer.Size)) : (cmd_i += 1) {
358 const pcmd = &cmd_list.*.CmdBuffer.Data[cmd_i];
359
360 if (pcmd.*.UserCallback != null) {
361 // User callback, registered via ImDrawList::AddCallback()
362 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
363 const ImDrawCallback_ResetRenderState = @intToPtr(c.ImDrawCallback, math.maxInt(usize));
364 if (pcmd.*.UserCallback == ImDrawCallback_ResetRenderState) {
365 SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
366 } else {
367 if (pcmd.*.UserCallback) |callback| {
368 callback(cmd_list, pcmd);
369 } else {
370 unreachable;
371 }
372 }
373 } else {
374 // Project scissor/clipping rectangles into framebuffer space
375 var clip_rect: c.ImVec4 = undefined;
376 clip_rect.x = (pcmd.*.ClipRect.x - clip_off.x) * clip_scale.x;
377 clip_rect.y = (pcmd.*.ClipRect.y - clip_off.y) * clip_scale.y;
378 clip_rect.z = (pcmd.*.ClipRect.z - clip_off.x) * clip_scale.x;
379 clip_rect.w = (pcmd.*.ClipRect.w - clip_off.y) * clip_scale.y;
380
381 if (clip_rect.x < @intToFloat(f32, fb_width) and clip_rect.y < @intToFloat(f32, fb_height) and clip_rect.z >= 0.0 and clip_rect.w >= 0.0) {
382 // Apply scissor/clipping rectangle
383 if (clip_origin_lower_left) {
384 c.glScissor(@floatToInt(c.GLint, clip_rect.x), fb_height - @floatToInt(c.GLint, clip_rect.w), @floatToInt(c.GLint, clip_rect.z - clip_rect.x), @floatToInt(c.GLint, clip_rect.w - clip_rect.y));
385 } else {
386 // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
387 c.glScissor(@floatToInt(c.GLint, clip_rect.x), @floatToInt(c.GLint, clip_rect.y), @floatToInt(c.GLint, clip_rect.z), @floatToInt(c.GLint, clip_rect.w));
388 }
389
390 // Bind texture, Draw
391 c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, @ptrToInt(pcmd.*.TextureId)));
392 const drawIndexSize = @sizeOf(c.ImDrawIdx);
393 const drawIndexType = if (drawIndexSize == 2) c.GL_UNSIGNED_SHORT else c.GL_UNSIGNED_INT;
394 const offset = @intToPtr(?*c.GLvoid, pcmd.*.IdxOffset * drawIndexSize);
395 if (@hasField(c, "IMGUI_IMPL_OPENGL_HAS_DRAW_WITH_BASE_VERTEX")) {
396 c.glDrawElementsBaseVertex(c.GL_TRIANGLES, @intCast(c.GLsizei, pcmd.*.ElemCount), drawIndexType, offset, @intCast(c.GLint, pcmd.*.VtxOffset));
397 } else {
398 c.glDrawElements(c.GL_TRIANGLES, @intCast(c.GLsizei, pcmd.*.ElemCount), drawIndexType, offset);
399 }
400 }
401 }
402 }
403 }
404 }
405
406 fn SetupRenderState(draw_data: *c.ImDrawData, fb_width: i32, fb_height: i32, vertex_array_object: c.GLuint) void {
407 // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
408 c.glEnable(c.GL_BLEND);
409 c.glBlendEquation(c.GL_FUNC_ADD);
410 c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
411 c.glDisable(c.GL_CULL_FACE);
412 c.glDisable(c.GL_DEPTH_TEST);
413 c.glEnable(c.GL_SCISSOR_TEST);
318414 if (@hasField(c, "GL_POLYGON_MODE"))
319 c.glPolygonMode(c.GL_FRONT_AND_BACK, @intCast(c.GLenum, last_polygon_mode[0]));
320 c.glViewport(last_viewport[0], last_viewport[1], @intCast(c.GLsizei, last_viewport[2]), @intCast(c.GLsizei, last_viewport[3]));
321 c.glScissor(last_scissor_box[0], last_scissor_box[1], @intCast(c.GLsizei, last_scissor_box[2]), @intCast(c.GLsizei, last_scissor_box[3]));
322 }
323
324 // Setup desired GL state
325 // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
326 // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
327 var vertex_array_object : c.GLuint = 0;
328 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
329 c.glGenVertexArrays(1, &vertex_array_object);
330 defer if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
331 c.glDeleteVertexArrays(1, &vertex_array_object);
332
333 SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
334
335 // Will project scissor/clipping rectangles into framebuffer space
336 const clip_off = draw_data.*.DisplayPos; // (0,0) unless using multi-viewports
337 const clip_scale = draw_data.*.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
338
339 // Render command lists
340 var n : usize = 0;
341 while (n < @intCast(usize, draw_data.*.CmdListsCount)) : (n += 1) {
342 const cmd_list = draw_data.*.CmdLists[n];
343
344 // Upload vertex/index buffers
345 c.glBufferData(c.GL_ARRAY_BUFFER, cmd_list.*.VtxBuffer.Size * @sizeOf(c.ImDrawVert), @ptrCast(?*c.GLvoid, cmd_list.*.VtxBuffer.Data), c.GL_STREAM_DRAW);
346 c.glBufferData(c.GL_ELEMENT_ARRAY_BUFFER, cmd_list.*.IdxBuffer.Size * @sizeOf(c.ImDrawIdx), @ptrCast(*c.GLvoid, cmd_list.*.IdxBuffer.Data), c.GL_STREAM_DRAW);
347
348 var cmd_i : usize = 0;
349 while (cmd_i < @intCast(usize, cmd_list.*.CmdBuffer.Size)) : (cmd_i += 1) {
350 const pcmd = &cmd_list.*.CmdBuffer.Data[cmd_i];
351
352 if (pcmd.*.UserCallback != null) {
353 // User callback, registered via ImDrawList::AddCallback()
354 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
355 const ImDrawCallback_ResetRenderState = @intToPtr(c.ImDrawCallback, math.maxInt(usize));
356 if (pcmd.*.UserCallback == ImDrawCallback_ResetRenderState) {
357 SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
358 } else {
359 if (pcmd.*.UserCallback) |callback| {
360 callback(cmd_list, pcmd);
361 } else {
362 unreachable;
363 }
364 }
365 } else {
366 // Project scissor/clipping rectangles into framebuffer space
367 var clip_rect : c.ImVec4 = undefined;
368 clip_rect.x = (pcmd.*.ClipRect.x - clip_off.x) * clip_scale.x;
369 clip_rect.y = (pcmd.*.ClipRect.y - clip_off.y) * clip_scale.y;
370 clip_rect.z = (pcmd.*.ClipRect.z - clip_off.x) * clip_scale.x;
371 clip_rect.w = (pcmd.*.ClipRect.w - clip_off.y) * clip_scale.y;
372
373 if (clip_rect.x < @intToFloat(f32, fb_width) and clip_rect.y < @intToFloat(f32, fb_height)
374 and clip_rect.z >= 0.0 and clip_rect.w >= 0.0) {
375 // Apply scissor/clipping rectangle
376 if (clip_origin_lower_left) {
377 c.glScissor(@floatToInt(c.GLint, clip_rect.x), fb_height - @floatToInt(c.GLint, clip_rect.w),
378 @floatToInt(c.GLint, clip_rect.z - clip_rect.x), @floatToInt(c.GLint, clip_rect.w - clip_rect.y));
379 } else {
380 // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
381 c.glScissor(@floatToInt(c.GLint, clip_rect.x), @floatToInt(c.GLint, clip_rect.y),
382 @floatToInt(c.GLint, clip_rect.z), @floatToInt(c.GLint, clip_rect.w));
383 }
384
385 // Bind texture, Draw
386 c.glBindTexture(c.GL_TEXTURE_2D, @intCast(c.GLuint, @ptrToInt(pcmd.*.TextureId)));
387 const drawIndexSize = @sizeOf(c.ImDrawIdx);
388 const drawIndexType = if (drawIndexSize == 2) c.GL_UNSIGNED_SHORT else c.GL_UNSIGNED_INT;
389 const offset = @intToPtr(?*c.GLvoid, pcmd.*.IdxOffset * drawIndexSize);
390 if (@hasField(c, "IMGUI_IMPL_OPENGL_HAS_DRAW_WITH_BASE_VERTEX")) {
391 c.glDrawElementsBaseVertex(c.GL_TRIANGLES, @intCast(c.GLsizei, pcmd.*.ElemCount), drawIndexType, offset, @intCast(c.GLint, pcmd.*.VtxOffset));
392 } else {
393 c.glDrawElements(c.GL_TRIANGLES, @intCast(c.GLsizei, pcmd.*.ElemCount), drawIndexType, offset);
394 }
395 }
396 }
397 }
398 }
399 }
400
401 fn SetupRenderState(draw_data: *c.ImDrawData, fb_width: i32, fb_height: i32, vertex_array_object: c.GLuint) void {
402 // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
403 c.glEnable(c.GL_BLEND);
404 c.glBlendEquation(c.GL_FUNC_ADD);
405 c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
406 c.glDisable(c.GL_CULL_FACE);
407 c.glDisable(c.GL_DEPTH_TEST);
408 c.glEnable(c.GL_SCISSOR_TEST);
409 if (@hasField(c, "GL_POLYGON_MODE"))
410 c.glPolygonMode(c.GL_FRONT_AND_BACK, c.GL_FILL);
411
412 // Setup viewport, orthographic projection matrix
413 // Our visible imgui space lies from draw_data.*.DisplayPos (top left) to draw_data.*.DisplayPos+data_data.*.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
414 c.glViewport(0, 0, @intCast(c.GLsizei, fb_width), @intCast(c.GLsizei, fb_height));
415 const L = draw_data.*.DisplayPos.x;
416 const R = draw_data.*.DisplayPos.x + draw_data.*.DisplaySize.x;
417 const T = draw_data.*.DisplayPos.y;
418 const B = draw_data.*.DisplayPos.y + draw_data.*.DisplaySize.y;
419 const ortho_projection = [4][4]f32{
420 [_]f32{ 2.0/(R-L), 0.0, 0.0, 0.0 },
421 [_]f32{ 0.0, 2.0/(T-B), 0.0, 0.0 },
422 [_]f32{ 0.0, 0.0, -1.0, 0.0 },
423 [_]f32{ (R+L)/(L-R), (T+B)/(B-T), 0.0, 1.0 },
424 };
425 c.glUseProgram(g_ShaderHandle);
426 c.glUniform1i(g_AttribLocationTex, 0);
427 c.glUniformMatrix4fv(g_AttribLocationProjMtx, 1, c.GL_FALSE, &ortho_projection[0][0]);
428 if (@hasField(c, "GL_SAMPLER_BINDING"))
429 c.glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
430
431 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
432 c.glBindVertexArray(vertex_array_object);
433
434 // Bind vertex/index buffers and setup attributes for ImDrawVert
435 c.glBindBuffer(c.GL_ARRAY_BUFFER, g_VboHandle);
436 c.glBindBuffer(c.GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
437 c.glEnableVertexAttribArray(@intCast(c.GLuint, g_AttribLocationVtxPos));
438 c.glEnableVertexAttribArray(@intCast(c.GLuint, g_AttribLocationVtxUV));
439 c.glEnableVertexAttribArray(@intCast(c.GLuint, g_AttribLocationVtxColor));
440 c.glVertexAttribPointer(@intCast(c.GLuint, g_AttribLocationVtxPos), 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(c.ImDrawVert), @intToPtr(?*c.GLvoid, @byteOffsetOf(c.ImDrawVert, "pos")));
441 c.glVertexAttribPointer(@intCast(c.GLuint, g_AttribLocationVtxUV), 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(c.ImDrawVert), @intToPtr(?*c.GLvoid, @byteOffsetOf(c.ImDrawVert, "uv")));
442 c.glVertexAttribPointer(@intCast(c.GLuint, g_AttribLocationVtxColor), 4, c.GL_UNSIGNED_BYTE, c.GL_TRUE, @sizeOf(c.ImDrawVert), @intToPtr(?*c.GLvoid, @byteOffsetOf(c.ImDrawVert, "col")));
443 }
415 c.glPolygonMode(c.GL_FRONT_AND_BACK, c.GL_FILL);
416
417 // Setup viewport, orthographic projection matrix
418 // Our visible imgui space lies from draw_data.*.DisplayPos (top left) to draw_data.*.DisplayPos+data_data.*.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
419 c.glViewport(0, 0, @intCast(c.GLsizei, fb_width), @intCast(c.GLsizei, fb_height));
420 const L = draw_data.*.DisplayPos.x;
421 const R = draw_data.*.DisplayPos.x + draw_data.*.DisplaySize.x;
422 const T = draw_data.*.DisplayPos.y;
423 const B = draw_data.*.DisplayPos.y + draw_data.*.DisplaySize.y;
424 const ortho_projection = [4][4]f32{
425 [_]f32{ 2.0 / (R - L), 0.0, 0.0, 0.0 },
426 [_]f32{ 0.0, 2.0 / (T - B), 0.0, 0.0 },
427 [_]f32{ 0.0, 0.0, -1.0, 0.0 },
428 [_]f32{ (R + L) / (L - R), (T + B) / (B - T), 0.0, 1.0 },
429 };
430 c.glUseProgram(g_ShaderHandle);
431 c.glUniform1i(g_AttribLocationTex, 0);
432 c.glUniformMatrix4fv(g_AttribLocationProjMtx, 1, c.GL_FALSE, &ortho_projection[0][0]);
433 if (@hasField(c, "GL_SAMPLER_BINDING"))
434 c.glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
435
436 if (!@hasField(c, "IMGUI_IMPL_OPENGL_ES2"))
437 c.glBindVertexArray(vertex_array_object);
438
439 // Bind vertex/index buffers and setup attributes for ImDrawVert
440 c.glBindBuffer(c.GL_ARRAY_BUFFER, g_VboHandle);
441 c.glBindBuffer(c.GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
442 c.glEnableVertexAttribArray(@intCast(c.GLuint, g_AttribLocationVtxPos));
443 c.glEnableVertexAttribArray(@intCast(c.GLuint, g_AttribLocationVtxUV));
444 c.glEnableVertexAttribArray(@intCast(c.GLuint, g_AttribLocationVtxColor));
445 c.glVertexAttribPointer(@intCast(c.GLuint, g_AttribLocationVtxPos), 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(c.ImDrawVert), @intToPtr(?*c.GLvoid, @byteOffsetOf(c.ImDrawVert, "pos")));
446 c.glVertexAttribPointer(@intCast(c.GLuint, g_AttribLocationVtxUV), 2, c.GL_FLOAT, c.GL_FALSE, @sizeOf(c.ImDrawVert), @intToPtr(?*c.GLvoid, @byteOffsetOf(c.ImDrawVert, "uv")));
447 c.glVertexAttribPointer(@intCast(c.GLuint, g_AttribLocationVtxColor), 4, c.GL_UNSIGNED_BYTE, c.GL_TRUE, @sizeOf(c.ImDrawVert), @intToPtr(?*c.GLvoid, @byteOffsetOf(c.ImDrawVert, "col")));
448 }
0 /// this is a port of cimgui/imgui/examples/imgui_impl_glfw.cpp
01 const c = @import("c.zig");
12 const builtin = @import("builtin");
23 const debug = @import("std").debug;
34 const math = @import("std").math;
45
56 pub const ClientApi = enum {
6 Unknown,
7 OpenGL,
8 Vulkan,
7 Unknown,
8 OpenGL,
9 Vulkan,
910 };
1011
1112 // Data
1213 var g_Window: ?*c.GLFWwindow = null;
1314 var g_ClientApi: ClientApi = .Unknown;
1415 var g_Time: f64 = 0.0;
15 var g_MouseJustPressed = [_]bool{ false } ** 5;
16 var g_MouseCursors = [_]?*c.GLFWcursor{ null } ** @enumToInt(c.ImGuiMouseCursor_COUNT);
16 var g_MouseJustPressed = [_]bool{false} ** 5;
17 var g_MouseCursors = [_]?*c.GLFWcursor{null} ** @enumToInt(c.ImGuiMouseCursor_COUNT);
1718 var g_WantUpdateMonitors = true;
1819
1920 // Chain GLFW callbacks for main viewport:
2425 var g_PrevUserCallbackChar: c.GLFWcharfun = null;
2526
2627 pub fn Init(window: *c.GLFWwindow, install_callbacks: bool, client_api: ClientApi) void {
27 g_Window = window;
28 g_Time = 0.0;
29
30 // Setup back-end capabilities flags
31 const io = c.igGetIO();
32 io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasMouseCursors); // We can honor GetMouseCursor() values (optional)
33 io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasSetMousePos); // We can honor io.WantSetMousePos requests (optional, rarely used)
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) {
36 io.*.BackendFlags |= @enumToInt(ImGuiBackendFlags_HasMouseHoveredViewport); // We can set io.MouseHoveredViewport correctly (optional, not easy)
37 }
38 io.*.BackendPlatformName = c"imgui_impl_glfw.zig";
39
40 // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
41 io.*.KeyMap[@enumToInt(c.ImGuiKey_Tab)] = c.GLFW_KEY_TAB;
42 io.*.KeyMap[@enumToInt(c.ImGuiKey_LeftArrow)] = c.GLFW_KEY_LEFT;
43 io.*.KeyMap[@enumToInt(c.ImGuiKey_RightArrow)] = c.GLFW_KEY_RIGHT;
44 io.*.KeyMap[@enumToInt(c.ImGuiKey_UpArrow)] = c.GLFW_KEY_UP;
45 io.*.KeyMap[@enumToInt(c.ImGuiKey_DownArrow)] = c.GLFW_KEY_DOWN;
46 io.*.KeyMap[@enumToInt(c.ImGuiKey_PageUp)] = c.GLFW_KEY_PAGE_UP;
47 io.*.KeyMap[@enumToInt(c.ImGuiKey_PageDown)] = c.GLFW_KEY_PAGE_DOWN;
48 io.*.KeyMap[@enumToInt(c.ImGuiKey_Home)] = c.GLFW_KEY_HOME;
49 io.*.KeyMap[@enumToInt(c.ImGuiKey_End)] = c.GLFW_KEY_END;
50 io.*.KeyMap[@enumToInt(c.ImGuiKey_Insert)] = c.GLFW_KEY_INSERT;
51 io.*.KeyMap[@enumToInt(c.ImGuiKey_Delete)] = c.GLFW_KEY_DELETE;
52 io.*.KeyMap[@enumToInt(c.ImGuiKey_Backspace)] = c.GLFW_KEY_BACKSPACE;
53 io.*.KeyMap[@enumToInt(c.ImGuiKey_Space)] = c.GLFW_KEY_SPACE;
54 io.*.KeyMap[@enumToInt(c.ImGuiKey_Enter)] = c.GLFW_KEY_ENTER;
55 io.*.KeyMap[@enumToInt(c.ImGuiKey_Escape)] = c.GLFW_KEY_ESCAPE;
56 io.*.KeyMap[@enumToInt(c.ImGuiKey_KeyPadEnter)] = c.GLFW_KEY_KP_ENTER;
57 io.*.KeyMap[@enumToInt(c.ImGuiKey_A)] = c.GLFW_KEY_A;
58 io.*.KeyMap[@enumToInt(c.ImGuiKey_C)] = c.GLFW_KEY_C;
59 io.*.KeyMap[@enumToInt(c.ImGuiKey_V)] = c.GLFW_KEY_V;
60 io.*.KeyMap[@enumToInt(c.ImGuiKey_X)] = c.GLFW_KEY_X;
61 io.*.KeyMap[@enumToInt(c.ImGuiKey_Y)] = c.GLFW_KEY_Y;
62 io.*.KeyMap[@enumToInt(c.ImGuiKey_Z)] = c.GLFW_KEY_Z;
63
64 // @TODO: Clipboard
65 // io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
66 // io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
67 io.*.ClipboardUserData = g_Window;
68
69 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR);
70 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_TextInput)] = c.glfwCreateStandardCursor(c.GLFW_IBEAM_CURSOR);
71 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeAll)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
72 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNS)] = c.glfwCreateStandardCursor(c.GLFW_VRESIZE_CURSOR);
73 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeEW)] = c.glfwCreateStandardCursor(c.GLFW_HRESIZE_CURSOR);
74 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNESW)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
75 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNWSE)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
76 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Hand)] = c.glfwCreateStandardCursor(c.GLFW_HAND_CURSOR);
77
78 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
79 g_PrevUserCallbackMousebutton = null;
80 g_PrevUserCallbackScroll = null;
81 g_PrevUserCallbackKey = null;
82 g_PrevUserCallbackChar = null;
83 if (install_callbacks) {
84 g_PrevUserCallbackMousebutton = c.glfwSetMouseButtonCallback(window, Callback_MouseButton);
85 g_PrevUserCallbackScroll = c.glfwSetScrollCallback(window, Callback_Scroll);
86 g_PrevUserCallbackKey = c.glfwSetKeyCallback(window, Callback_Key);
87 g_PrevUserCallbackChar = c.glfwSetCharCallback(window, Callback_Char);
88 }
89
90 // Our mouse update function expect PlatformHandle to be filled for the main viewport
91 const main_viewport = c.igGetMainViewport();
92 main_viewport.*.PlatformHandle = g_Window;
93 if (builtin.os == builtin.Os.windows)
94 main_viewport.*.PlatformHandleRaw = c.glfwGetWin32Window(g_Window);
95
96 // @TODO: Platform Interface (Viewport)
97 if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0)
98 unreachable;
28 g_Window = window;
29 g_Time = 0.0;
30
31 // Setup back-end capabilities flags
32 const io = c.igGetIO();
33 io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasMouseCursors); // We can honor GetMouseCursor() values (optional)
34 io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasSetMousePos); // We can honor io.WantSetMousePos requests (optional, rarely used)
35 if (false) io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_PlatformHasViewports); // We can create multi-viewports on the Platform side (optional)
36 if (false and @hasField(c, "GLFW_HAS_GLFW_HOVERED") and builtin.os == builtin.Os.windows) {
37 io.*.BackendFlags |= @enumToInt(ImGuiBackendFlags_HasMouseHoveredViewport); // We can set io.MouseHoveredViewport correctly (optional, not easy)
38 }
39 io.*.BackendPlatformName = c"imgui_impl_glfw.zig";
40
41 // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
42 io.*.KeyMap[@enumToInt(c.ImGuiKey_Tab)] = c.GLFW_KEY_TAB;
43 io.*.KeyMap[@enumToInt(c.ImGuiKey_LeftArrow)] = c.GLFW_KEY_LEFT;
44 io.*.KeyMap[@enumToInt(c.ImGuiKey_RightArrow)] = c.GLFW_KEY_RIGHT;
45 io.*.KeyMap[@enumToInt(c.ImGuiKey_UpArrow)] = c.GLFW_KEY_UP;
46 io.*.KeyMap[@enumToInt(c.ImGuiKey_DownArrow)] = c.GLFW_KEY_DOWN;
47 io.*.KeyMap[@enumToInt(c.ImGuiKey_PageUp)] = c.GLFW_KEY_PAGE_UP;
48 io.*.KeyMap[@enumToInt(c.ImGuiKey_PageDown)] = c.GLFW_KEY_PAGE_DOWN;
49 io.*.KeyMap[@enumToInt(c.ImGuiKey_Home)] = c.GLFW_KEY_HOME;
50 io.*.KeyMap[@enumToInt(c.ImGuiKey_End)] = c.GLFW_KEY_END;
51 io.*.KeyMap[@enumToInt(c.ImGuiKey_Insert)] = c.GLFW_KEY_INSERT;
52 io.*.KeyMap[@enumToInt(c.ImGuiKey_Delete)] = c.GLFW_KEY_DELETE;
53 io.*.KeyMap[@enumToInt(c.ImGuiKey_Backspace)] = c.GLFW_KEY_BACKSPACE;
54 io.*.KeyMap[@enumToInt(c.ImGuiKey_Space)] = c.GLFW_KEY_SPACE;
55 io.*.KeyMap[@enumToInt(c.ImGuiKey_Enter)] = c.GLFW_KEY_ENTER;
56 io.*.KeyMap[@enumToInt(c.ImGuiKey_Escape)] = c.GLFW_KEY_ESCAPE;
57 io.*.KeyMap[@enumToInt(c.ImGuiKey_KeyPadEnter)] = c.GLFW_KEY_KP_ENTER;
58 io.*.KeyMap[@enumToInt(c.ImGuiKey_A)] = c.GLFW_KEY_A;
59 io.*.KeyMap[@enumToInt(c.ImGuiKey_C)] = c.GLFW_KEY_C;
60 io.*.KeyMap[@enumToInt(c.ImGuiKey_V)] = c.GLFW_KEY_V;
61 io.*.KeyMap[@enumToInt(c.ImGuiKey_X)] = c.GLFW_KEY_X;
62 io.*.KeyMap[@enumToInt(c.ImGuiKey_Y)] = c.GLFW_KEY_Y;
63 io.*.KeyMap[@enumToInt(c.ImGuiKey_Z)] = c.GLFW_KEY_Z;
64
65 // @TODO: Clipboard
66 // io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
67 // io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
68 io.*.ClipboardUserData = g_Window;
69
70 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR);
71 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_TextInput)] = c.glfwCreateStandardCursor(c.GLFW_IBEAM_CURSOR);
72 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeAll)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
73 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNS)] = c.glfwCreateStandardCursor(c.GLFW_VRESIZE_CURSOR);
74 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeEW)] = c.glfwCreateStandardCursor(c.GLFW_HRESIZE_CURSOR);
75 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNESW)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
76 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNWSE)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
77 g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Hand)] = c.glfwCreateStandardCursor(c.GLFW_HAND_CURSOR);
78
79 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
80 g_PrevUserCallbackMousebutton = null;
81 g_PrevUserCallbackScroll = null;
82 g_PrevUserCallbackKey = null;
83 g_PrevUserCallbackChar = null;
84 if (install_callbacks) {
85 g_PrevUserCallbackMousebutton = c.glfwSetMouseButtonCallback(window, Callback_MouseButton);
86 g_PrevUserCallbackScroll = c.glfwSetScrollCallback(window, Callback_Scroll);
87 g_PrevUserCallbackKey = c.glfwSetKeyCallback(window, Callback_Key);
88 g_PrevUserCallbackChar = c.glfwSetCharCallback(window, Callback_Char);
89 }
90
91 // Our mouse update function expect PlatformHandle to be filled for the main viewport
92 const main_viewport = c.igGetMainViewport();
93 main_viewport.*.PlatformHandle = g_Window;
94 if (builtin.os == builtin.Os.windows)
95 main_viewport.*.PlatformHandleRaw = c.glfwGetWin32Window(g_Window);
96
97 // @TODO: Platform Interface (Viewport)
98 if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0)
99 unreachable;
99100 // ImGui_ImplGlfw_InitPlatformInterface();
100101
101 g_ClientApi = client_api;
102 g_ClientApi = client_api;
102103 }
103104
104105 pub fn Shutdown() void {
105 // @TODO: Platform Interface (Viewport)
106 // ImGui_ImplGlfw_ShutdownPlatformInterface();
107
108 for (g_MouseCursors) |*cursor| {
109 c.glfwDestroyCursor(cursor.*);
110 cursor.* = null;
111 }
112 g_ClientApi = .Unknown;
106 // @TODO: Platform Interface (Viewport)
107 // ImGui_ImplGlfw_ShutdownPlatformInterface();
108 for (g_MouseCursors) |*cursor| {
109 c.glfwDestroyCursor(cursor.*);
110 cursor.* = null;
111 }
112 g_ClientApi = .Unknown;
113113 }
114114
115115 pub fn NewFrame() void {
116 const io = c.igGetIO();
117 debug.assert(c.ImFontAtlas_IsBuilt(io.*.Fonts));
118
119 var w : c_int = undefined;
120 var h : c_int = undefined;
121 var display_w : c_int = undefined;
122 var display_h : c_int = undefined;
123 c.glfwGetWindowSize(g_Window, &w, &h);
124 c.glfwGetFramebufferSize(g_Window, &display_w, &display_h);
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();
116 const io = c.igGetIO();
117 debug.assert(c.ImFontAtlas_IsBuilt(io.*.Fonts));
118
119 var w: c_int = undefined;
120 var h: c_int = undefined;
121 var display_w: c_int = undefined;
122 var display_h: c_int = undefined;
123 c.glfwGetWindowSize(g_Window, &w, &h);
124 c.glfwGetFramebufferSize(g_Window, &display_w, &display_h);
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();
144144 }
145145
146146 fn UpdateMonitors() void {
147 const platform_io = c.igGetPlatformIO();
148 var monitors_count : c_int = 0;
149 const glfw_monitors = c.glfwGetMonitors(&monitors_count)[0..@intCast(usize, monitors_count)];
150
151 c.ImVector_ImGuiPlatformMonitor_Resize(&platform_io.*.Monitors, monitors_count);
152 for (glfw_monitors) |glfw_monitor, n| {
153 var monitor = &platform_io.*.Monitors.Data[n];
154 var x : c_int = undefined;
155 var y : c_int = undefined;
156 c.glfwGetMonitorPos(glfw_monitor, &x, &y);
157 const vid_mode = c.glfwGetVideoMode(glfw_monitor); // glfw_monitors[n]);
158
159 monitor.*.MainPos = c.ImVec2{ .x = @intToFloat(f32, x), .y = @intToFloat(f32, y) };
160 monitor.*.MainSize = c.ImVec2{
161 .x = @intToFloat(f32, vid_mode.*.width),
162 .y = @intToFloat(f32, vid_mode.*.height),
163 };
164 if (false and c.GLFW_HAS_MONITOR_WORK_AREA) {
165 var w : c_int = undefined;
166 var h : c_int = undefined;
167 c.glfwGetMonitorWorkarea(glfw_monitor, &x, &y, &w, &h);
168 monitor.*.WorkPos = ImVec2{ .x = @intToFloat(f32, x), .y = @intToFloat(f32, y) };
169 monitor.*.WorkSize = ImVec2{ .x = @intToFloat(f32, w), .y = @intToFloat(f32, h) };
170 }
171 if (false and c.GLFW_HAS_PER_MONITOR_DPI) {
172 // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings,
173 // which generally needs to be set in the manifest or at runtime.
174 var x_scale : f32 = undefined;
175 var y_scale : f32 = undefined;
176 c.glfwGetMonitorContentScale(glfw_monitor, &x_scale, &y_scale);
177 monitor.*.DpiScale = x_scale;
178 }
179 }
180 g_WantUpdateMonitors = false;
147 const platform_io = c.igGetPlatformIO();
148 var monitors_count: c_int = 0;
149 const glfw_monitors = c.glfwGetMonitors(&monitors_count)[0..@intCast(usize, monitors_count)];
150
151 c.ImVector_ImGuiPlatformMonitor_Resize(&platform_io.*.Monitors, monitors_count);
152 for (glfw_monitors) |glfw_monitor, n| {
153 var monitor = &platform_io.*.Monitors.Data[n];
154 var x: c_int = undefined;
155 var y: c_int = undefined;
156 c.glfwGetMonitorPos(glfw_monitor, &x, &y);
157 const vid_mode = c.glfwGetVideoMode(glfw_monitor); // glfw_monitors[n]);
158
159 monitor.*.MainPos = c.ImVec2{ .x = @intToFloat(f32, x), .y = @intToFloat(f32, y) };
160 monitor.*.MainSize = c.ImVec2{
161 .x = @intToFloat(f32, vid_mode.*.width),
162 .y = @intToFloat(f32, vid_mode.*.height),
163 };
164 if (false and c.GLFW_HAS_MONITOR_WORK_AREA) {
165 var w: c_int = undefined;
166 var h: c_int = undefined;
167 c.glfwGetMonitorWorkarea(glfw_monitor, &x, &y, &w, &h);
168 monitor.*.WorkPos = ImVec2{ .x = @intToFloat(f32, x), .y = @intToFloat(f32, y) };
169 monitor.*.WorkSize = ImVec2{ .x = @intToFloat(f32, w), .y = @intToFloat(f32, h) };
170 }
171 if (false and c.GLFW_HAS_PER_MONITOR_DPI) {
172 // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings,
173 // which generally needs to be set in the manifest or at runtime.
174 var x_scale: f32 = undefined;
175 var y_scale: f32 = undefined;
176 c.glfwGetMonitorContentScale(glfw_monitor, &x_scale, &y_scale);
177 monitor.*.DpiScale = x_scale;
178 }
179 }
180 g_WantUpdateMonitors = false;
181181 }
182182
183183 fn UpdateMousePosAndButtons() void {
184 // Update buttons
185 const io = c.igGetIO();
186 for (io.*.MouseDown) |*isDown, i| {
187 // 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.
188 isDown.* = g_MouseJustPressed[i] or c.glfwGetMouseButton(g_Window, @intCast(c_int, i)) != 0;
189 g_MouseJustPressed[i] = false;
190 }
191
192 // Update mouse position
193 const mouse_pos_backup = io.*.MousePos;
194 io.*.MousePos = c.ImVec2{ .x = math.f32_min, .y = math.f32_min };
195 io.*.MouseHoveredViewport = 0;
196 const platform_io = c.igGetPlatformIO();
197 var n : usize = 0;
198 while (n < @intCast(usize, platform_io.*.Viewports.Size)) : (n += 1) {
199 const viewport = platform_io.*.Viewports.Data[n];
200 const window = @ptrCast(*c.GLFWwindow, viewport.*.PlatformHandle);
201 const focused = c.glfwGetWindowAttrib(window, c.GLFW_FOCUSED) != 0;
202 if (focused) {
203 if (io.*.WantSetMousePos) {
204 c.glfwSetCursorPos(window, mouse_pos_backup.x - viewport.*.Pos.x, mouse_pos_backup.y - viewport.*.Pos.y);
205 } else {
206 var mouse_x : f64 = undefined;
207 var mouse_y : f64 = undefined;
208 c.glfwGetCursorPos(window, &mouse_x, &mouse_y);
209 if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0) {
210 // 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)
211 var window_x : c_int = undefined;
212 var window_y : c_int = undefined;
213 c.glfwGetWindowPos(window, &window_x, &window_y);
214 io.*.MousePos = c.ImVec2{
215 .x = @floatCast(f32, mouse_x) + @intToFloat(f32, window_x),
216 .y = @floatCast(f32, mouse_y) + @intToFloat(f32, window_y),
217 };
184 // Update buttons
185 const io = c.igGetIO();
186 for (io.*.MouseDown) |*isDown, i| {
187 // 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.
188 isDown.* = g_MouseJustPressed[i] or c.glfwGetMouseButton(g_Window, @intCast(c_int, i)) != 0;
189 g_MouseJustPressed[i] = false;
190 }
191
192 // Update mouse position
193 const mouse_pos_backup = io.*.MousePos;
194 io.*.MousePos = c.ImVec2{ .x = math.f32_min, .y = math.f32_min };
195 io.*.MouseHoveredViewport = 0;
196 const platform_io = c.igGetPlatformIO();
197 var n: usize = 0;
198 while (n < @intCast(usize, platform_io.*.Viewports.Size)) : (n += 1) {
199 const viewport = platform_io.*.Viewports.Data[n];
200 const window = @ptrCast(*c.GLFWwindow, viewport.*.PlatformHandle);
201 const focused = c.glfwGetWindowAttrib(window, c.GLFW_FOCUSED) != 0;
202 if (focused) {
203 if (io.*.WantSetMousePos) {
204 c.glfwSetCursorPos(window, mouse_pos_backup.x - viewport.*.Pos.x, mouse_pos_backup.y - viewport.*.Pos.y);
205 } else {
206 var mouse_x: f64 = undefined;
207 var mouse_y: f64 = undefined;
208 c.glfwGetCursorPos(window, &mouse_x, &mouse_y);
209 if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0) {
210 // 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)
211 var window_x: c_int = undefined;
212 var window_y: c_int = undefined;
213 c.glfwGetWindowPos(window, &window_x, &window_y);
214 io.*.MousePos = c.ImVec2{
215 .x = @floatCast(f32, mouse_x) + @intToFloat(f32, window_x),
216 .y = @floatCast(f32, mouse_y) + @intToFloat(f32, window_y),
217 };
218 } else {
219 // 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)
220 io.*.MousePos = c.ImVec2{ .x = @floatCast(f32, mouse_x), .y = @floatCast(f32, mouse_y) };
221 }
222 }
223
224 for (io.*.MouseDown) |*isDown, i|
225 isDown.* = isDown.* or c.glfwGetMouseButton(window, @intCast(c_int, i)) != 0;
226 }
227 }
228 }
229
230 fn UpdateMouseCursor() void {
231 const io = c.igGetIO();
232 if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_NoMouseCursorChange) != 0 or c.glfwGetInputMode(g_Window, c.GLFW_CURSOR) == c.GLFW_CURSOR_DISABLED)
233 return;
234
235 const imgui_cursor = c.igGetMouseCursor();
236 const platform_io = c.igGetPlatformIO();
237 var n: usize = 0;
238 while (n < @intCast(usize, platform_io.*.Viewports.Size)) : (n += 1) {
239 const window = @ptrCast(*c.GLFWwindow, platform_io.*.Viewports.Data[n].*.PlatformHandle);
240 if (imgui_cursor == @enumToInt(c.ImGuiMouseCursor_None) or io.*.MouseDrawCursor) {
241 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
242 c.glfwSetInputMode(window, c.GLFW_CURSOR, c.GLFW_CURSOR_HIDDEN);
218243 } else {
219 // 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)
220 io.*.MousePos = c.ImVec2{ .x = @floatCast(f32, mouse_x), .y = @floatCast(f32, mouse_y) };
244 // Show OS mouse cursor
245 // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
246 c.glfwSetCursor(window, if (g_MouseCursors[@intCast(usize, imgui_cursor)]) |cursor| cursor else g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)]);
247 c.glfwSetInputMode(window, c.GLFW_CURSOR, c.GLFW_CURSOR_NORMAL);
221248 }
222 }
223
224 for (io.*.MouseDown) |*isDown, i|
225 isDown.* = isDown.* or c.glfwGetMouseButton(window, @intCast(c_int, i)) != 0;
226 }
227 }
228 }
229
230 fn UpdateMouseCursor() void {
231 const io = c.igGetIO();
232 if (io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_NoMouseCursorChange) != 0
233 or c.glfwGetInputMode(g_Window, c.GLFW_CURSOR) == c.GLFW_CURSOR_DISABLED)
234 return;
235
236 const imgui_cursor = c.igGetMouseCursor();
237 const platform_io = c.igGetPlatformIO();
238 var n : usize = 0;
239 while (n < @intCast(usize, platform_io.*.Viewports.Size)) : (n += 1) {
240 const window = @ptrCast(*c.GLFWwindow, platform_io.*.Viewports.Data[n].*.PlatformHandle);
241 if (imgui_cursor == @enumToInt(c.ImGuiMouseCursor_None) or io.*.MouseDrawCursor) {
242 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
243 c.glfwSetInputMode(window, c.GLFW_CURSOR, c.GLFW_CURSOR_HIDDEN);
244 } else {
245 // Show OS mouse cursor
246 // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
247 c.glfwSetCursor(window,
248 if (g_MouseCursors[@intCast(usize, imgui_cursor)]) |cursor| cursor
249 else g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)]);
250 c.glfwSetInputMode(window, c.GLFW_CURSOR, c.GLFW_CURSOR_NORMAL);
251 }
252 }
249 }
253250 }
254251
255252 fn UpdateGamepads() void {
256 // @TODO
253 // @TODO
257254 }
258255
259256 // GLFW Callbacks
260257 extern fn Callback_MouseButton(window: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) void {
261 if (g_PrevUserCallbackMousebutton) |prev| {
262 prev(window, button, action, mods);
263 }
264
265 if (button < 0)
266 return;
267
268 const button_u = @intCast(usize, button);
269 if (action == c.GLFW_PRESS and button_u < g_MouseJustPressed.len)
270 g_MouseJustPressed[button_u] = true;
258 if (g_PrevUserCallbackMousebutton) |prev| {
259 prev(window, button, action, mods);
260 }
261
262 if (button < 0)
263 return;
264
265 const button_u = @intCast(usize, button);
266 if (action == c.GLFW_PRESS and button_u < g_MouseJustPressed.len)
267 g_MouseJustPressed[button_u] = true;
271268 }
272269
273270 extern fn Callback_Scroll(window: ?*c.GLFWwindow, dx: f64, dy: f64) void {
274 if (g_PrevUserCallbackScroll) |prev| {
275 prev(window, dx, dy);
276 }
277
278 const io = c.igGetIO();
279 io.*.MouseWheelH += @floatCast(f32, dx);
280 io.*.MouseWheel += @floatCast(f32, dy);
271 if (g_PrevUserCallbackScroll) |prev| {
272 prev(window, dx, dy);
273 }
274
275 const io = c.igGetIO();
276 io.*.MouseWheelH += @floatCast(f32, dx);
277 io.*.MouseWheel += @floatCast(f32, dy);
281278 }
282279
283280 extern fn Callback_Key(window: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, modifiers: c_int) void {
284 if (g_PrevUserCallbackKey) |prev| {
285 prev(window, key, scancode, action, modifiers);
286 }
287
288 if (key < 0)
289 unreachable;
290
291 const key_u = @intCast(usize, key);
292
293 const io = c.igGetIO();
294 if (action == c.GLFW_PRESS)
295 io.*.KeysDown[key_u] = true;
296 if (action == c.GLFW_RELEASE)
297 io.*.KeysDown[key_u] = false;
298
299 // Modifiers are not reliable across systems
300 io.*.KeyCtrl = io.*.KeysDown[c.GLFW_KEY_LEFT_CONTROL] or io.*.KeysDown[c.GLFW_KEY_RIGHT_CONTROL];
301 io.*.KeyShift = io.*.KeysDown[c.GLFW_KEY_LEFT_SHIFT] or io.*.KeysDown[c.GLFW_KEY_RIGHT_SHIFT];
302 io.*.KeyAlt = io.*.KeysDown[c.GLFW_KEY_LEFT_ALT] or io.*.KeysDown[c.GLFW_KEY_RIGHT_ALT];
303 io.*.KeySuper = io.*.KeysDown[c.GLFW_KEY_LEFT_SUPER] or io.*.KeysDown[c.GLFW_KEY_RIGHT_SUPER];
281 if (g_PrevUserCallbackKey) |prev| {
282 prev(window, key, scancode, action, modifiers);
283 }
284
285 if (key < 0)
286 unreachable;
287
288 const key_u = @intCast(usize, key);
289
290 const io = c.igGetIO();
291 if (action == c.GLFW_PRESS)
292 io.*.KeysDown[key_u] = true;
293 if (action == c.GLFW_RELEASE)
294 io.*.KeysDown[key_u] = false;
295
296 // Modifiers are not reliable across systems
297 io.*.KeyCtrl = io.*.KeysDown[c.GLFW_KEY_LEFT_CONTROL] or io.*.KeysDown[c.GLFW_KEY_RIGHT_CONTROL];
298 io.*.KeyShift = io.*.KeysDown[c.GLFW_KEY_LEFT_SHIFT] or io.*.KeysDown[c.GLFW_KEY_RIGHT_SHIFT];
299 io.*.KeyAlt = io.*.KeysDown[c.GLFW_KEY_LEFT_ALT] or io.*.KeysDown[c.GLFW_KEY_RIGHT_ALT];
300 io.*.KeySuper = io.*.KeysDown[c.GLFW_KEY_LEFT_SUPER] or io.*.KeysDown[c.GLFW_KEY_RIGHT_SUPER];
304301 }
305302
306303 extern fn Callback_Char(window: ?*c.GLFWwindow, char: c_uint) void {
307 if (g_PrevUserCallbackChar) |prev| {
308 prev(window, char);
309 }
310
311 const io = c.igGetIO();
312 c.ImGuiIO_AddInputCharacter(io, char);
313 }
304 if (g_PrevUserCallbackChar) |prev| {
305 prev(window, char);
306 }
307
308 const io = c.igGetIO();
309 c.ImGuiIO_AddInputCharacter(io, char);
310 }
0 /// this is a port of cimgui/imgui/examples/example_glfw_opengl3/main.cpp
01 const c = @import("c.zig");
12 const std = @import("std");
23 const panic = std.debug.panic;
56 const gl3_impl = @import("gl3_impl.zig");
67
78 extern fn errorCallback(err: c_int, description: [*c]const u8) void {
8 panic("Error: {}\n", description);
9 panic("Error: {}\n", description);
910 }
1011
1112 var window: *c.GLFWwindow = undefined;
1213
1314 pub fn main() !void {
14 _ = c.glfwSetErrorCallback(errorCallback);
15 _ = c.glfwSetErrorCallback(errorCallback);
1516
16 if (c.glfwInit() == c.GL_FALSE) {
17 panic("GLFW init failure\n");
18 }
19 defer c.glfwTerminate();
17 if (c.glfwInit() == c.GL_FALSE) {
18 panic("GLFW init failure\n");
19 }
20 defer c.glfwTerminate();
2021
21 c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3);
22 c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 2);
23 c.glfwWindowHint(c.GLFW_OPENGL_FORWARD_COMPAT, c.GL_TRUE);
24 c.glfwWindowHint(c.GLFW_OPENGL_DEBUG_CONTEXT, debug_gl.is_on);
25 c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
26 // c.glfwWindowHint(c.GLFW_DEPTH_BITS, 0);
27 // c.glfwWindowHint(c.GLFW_STENCIL_BITS, 8);
28 c.glfwWindowHint(c.GLFW_RESIZABLE, c.GL_TRUE);
22 c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3);
23 c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 2);
24 c.glfwWindowHint(c.GLFW_OPENGL_FORWARD_COMPAT, c.GL_TRUE);
25 c.glfwWindowHint(c.GLFW_OPENGL_DEBUG_CONTEXT, debug_gl.is_on);
26 c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE);
27 // c.glfwWindowHint(c.GLFW_DEPTH_BITS, 0);
28 // c.glfwWindowHint(c.GLFW_STENCIL_BITS, 8);
29 c.glfwWindowHint(c.GLFW_RESIZABLE, c.GL_TRUE);
2930
30 const window_width = 640;
31 const window_height = 480;
32 window = c.glfwCreateWindow(window_width, window_height, c"ImGUI Test", null, null) orelse {
33 panic("unable to create window\n");
34 };
35 defer c.glfwDestroyWindow(window);
31 const window_width = 640;
32 const window_height = 480;
33 window = c.glfwCreateWindow(window_width, window_height, c"ImGUI Test", null, null) orelse {
34 panic("unable to create window\n");
35 };
36 defer c.glfwDestroyWindow(window);
3637
37 c.glfwMakeContextCurrent(window);
38 c.glfwSwapInterval(1);
38 c.glfwMakeContextCurrent(window);
39 c.glfwSwapInterval(1);
3940
40 const context = c.igCreateContext(null);
41 defer c.igDestroyContext(context);
41 const context = c.igCreateContext(null);
42 defer c.igDestroyContext(context);
4243
43 const io = c.igGetIO();
44 io.*.ConfigFlags |= @enumToInt(c.ImGuiConfigFlags_NavEnableKeyboard);
45 // io.*.ConfigFlags |= @enumToInt(c.ImGuiConfigFlags_DockingEnable);
46 // io.*.ConfigFlags |= @enumToInt(c.ImGuiConfigFlags_ViewportsEnable);
44 const io = c.igGetIO();
45 io.*.ConfigFlags |= @enumToInt(c.ImGuiConfigFlags_NavEnableKeyboard);
46 // io.*.ConfigFlags |= @enumToInt(c.ImGuiConfigFlags_DockingEnable);
47 // io.*.ConfigFlags |= @enumToInt(c.ImGuiConfigFlags_ViewportsEnable);
4748
48 const style = c.igGetStyle();
49 c.igStyleColorsDark(style);
49 const style = c.igGetStyle();
50 c.igStyleColorsDark(style);
5051
51 if (false and io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0) {
52 style.*.WindowRounding = 0.0;
53 style.*.Colors[@enumToInt(c.ImGuiCol_WindowBg)].w = 1.0;
54 }
52 if (false and io.*.ConfigFlags & @enumToInt(c.ImGuiConfigFlags_ViewportsEnable) != 0) {
53 style.*.WindowRounding = 0.0;
54 style.*.Colors[@enumToInt(c.ImGuiCol_WindowBg)].w = 1.0;
55 }
5556
56 glfw_impl.Init(window, true, glfw_impl.ClientApi.OpenGL);
57 defer glfw_impl.Shutdown();
57 glfw_impl.Init(window, true, glfw_impl.ClientApi.OpenGL);
58 defer glfw_impl.Shutdown();
5859
59 gl3_impl.Init(); // #version 150
60 defer gl3_impl.Shutdown();
60 gl3_impl.Init(); // #version 150
61 defer gl3_impl.Shutdown();
6162
62 const start_time = c.glfwGetTime();
63 var prev_time = start_time;
63 const start_time = c.glfwGetTime();
64 var prev_time = start_time;
6465
65 while (c.glfwWindowShouldClose(window) == c.GL_FALSE) {
66 c.glfwPollEvents();
66 while (c.glfwWindowShouldClose(window) == c.GL_FALSE) {
67 c.glfwPollEvents();
6768
68 try gl3_impl.NewFrame();
69 glfw_impl.NewFrame();
70 c.igNewFrame();
69 try gl3_impl.NewFrame();
70 glfw_impl.NewFrame();
71 c.igNewFrame();
7172
72 // main part
73 c.igShowDemoWindow(null);
73 // main part
74 c.igShowDemoWindow(null);
7475
75 c.igRender();
76 var w: c_int = undefined;
77 var h: c_int = undefined;
78 c.glfwGetFramebufferSize(window, &w, &h);
79 c.glViewport(0, 0, w, h);
80 c.glClearColor(0.0, 0.0, 0.0, 0.0);
81 c.glClear(c.GL_COLOR_BUFFER_BIT);
82 gl3_impl.RenderDrawData(c.igGetDrawData());
76 c.igRender();
77 var w: c_int = undefined;
78 var h: c_int = undefined;
79 c.glfwGetFramebufferSize(window, &w, &h);
80 c.glViewport(0, 0, w, h);
81 c.glClearColor(0.0, 0.0, 0.0, 0.0);
82 c.glClear(c.GL_COLOR_BUFFER_BIT);
83 gl3_impl.RenderDrawData(c.igGetDrawData());
8384
84 // const now_time = c.glfwGetTime();
85 // const elapsed = now_time - prev_time;
86 // prev_time = now_time;
87 // nextFrame(t, elapsed);
88 // draw(t, @This());
89
90 c.glfwSwapBuffers(window);
91 }
85 // const now_time = c.glfwGetTime();
86 // const elapsed = now_time - prev_time;
87 // prev_time = now_time;
88 // nextFrame(t, elapsed);
89 // draw(t, @This());
90
91 c.glfwSwapBuffers(window);
92 }
9293 }