|
0 |
/// this is a port of cimgui/imgui/examples/imgui_impl_opengl3.cpp
|
0 | 1 |
const c = @import("c.zig");
|
1 | 2 |
const mem = @import("std").mem;
|
2 | 3 |
const math = @import("std").math;
|
|
4 | 5 |
const builtin = @import("builtin");
|
5 | 6 |
|
6 | 7 |
const OpenGLHasDrawWithBaseVertex = @hasField(c, "IMGUI_IMPL_OPENGL_ES2") or
|
7 | |
@hasField(c, "IMGUI_IMPL_OPENGL_ES3");
|
|
8 |
@hasField(c, "IMGUI_IMPL_OPENGL_ES3");
|
8 | 9 |
|
9 | 10 |
// 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;
|
16 | 17 |
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;
|
24 | 25 |
|
25 | 26 |
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();
|
44 | 45 |
}
|
45 | 46 |
|
46 | 47 |
pub fn Shutdown() void {
|
47 | |
// ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
48 | |
DestroyDeviceObjects();
|
|
48 |
// ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
|
49 |
DestroyDeviceObjects();
|
49 | 50 |
}
|
50 | 51 |
|
51 | 52 |
pub fn NewFrame() !void {
|
52 | |
if (g_ShaderHandle == 0)
|
53 | |
try CreateDeviceObjects();
|
|
53 |
if (g_ShaderHandle == 0)
|
|
54 |
try CreateDeviceObjects();
|
54 | 55 |
}
|
55 | 56 |
|
56 | 57 |
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 |
}
|
132 | 132 |
|
133 | 133 |
const CheckableThing = enum {
|
134 | |
Shader,
|
135 | |
Program,
|
|
134 |
Shader,
|
|
135 |
Program,
|
136 | 136 |
};
|
137 | 137 |
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 |
}
|
165 | 164 |
}
|
166 | 165 |
|
167 | 166 |
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();
|
200 | 199 |
}
|
201 | 200 |
|
202 | 201 |
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);
|
227 | 226 |
}
|
228 | 227 |
|
229 | 228 |
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);
|
299 | 268 |
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;
|
302 | 336 |
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);
|
318 | 414 |
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 |
}
|