imgui-bindings 0.1.16 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,14 @@
1
1
  require 'ffi'
2
2
  require 'opengl'
3
+ require 'fiddle'
3
4
 
4
5
  require_relative 'imgui'
5
6
 
6
7
  module ImGui
7
8
 
8
- @@g_GlVersion = 0 # Extracted at runtime using GL::MAJOR_VERSION, GL::MINOR_VERSION queries.
9
- @@g_GlslVersionString = "" # Specified by user or detected based on compile time
10
- @@g_FontTexture = nil
9
+ @@g_GlVersion = 0
10
+ @@g_MaxTextureSize = 0
11
+ @@g_GlslVersionString = ""
11
12
 
12
13
  @@g_ShaderHandle = 0
13
14
 
@@ -26,37 +27,37 @@ module ImGui
26
27
  def self.PrintShaderCompileStatus(handle)
27
28
  rvalue = ' ' * 4
28
29
  GL.GetShaderiv(handle, GL::COMPILE_STATUS, rvalue)
29
- rvalue = rvalue.unpack1('L')
30
- if rvalue == GL::FALSE
31
- $stderr.puts "Error in compiling shader"
32
- log_length = ' ' * 4
33
- GL.GetShaderiv(handle, GL::INFO_LOG_LENGTH, log_length)
34
- log_length = log_length.unpack1('L')
35
- if log_length > 0
36
- buf = ' ' * log_length
37
- GL.GetShaderInfoLog(handle, log_length, nil, buf)
38
- $stderr.puts(buf)
39
- exit()
40
- end
30
+ ok = rvalue.unpack1('L')
31
+ return true if ok == GL::TRUE
32
+
33
+ $stderr.puts "Error in compiling shader"
34
+ log_length = ' ' * 4
35
+ GL.GetShaderiv(handle, GL::INFO_LOG_LENGTH, log_length)
36
+ log_length = log_length.unpack1('L')
37
+ if log_length > 0
38
+ buf = ' ' * log_length
39
+ GL.GetShaderInfoLog(handle, log_length, nil, buf)
40
+ $stderr.puts(buf)
41
41
  end
42
+ false
42
43
  end
43
44
 
44
45
  def self.PrintProgramLinkStatus(handle)
45
46
  rvalue = ' ' * 4
46
47
  GL.GetProgramiv(handle, GL::LINK_STATUS, rvalue)
47
- rvalue = rvalue.unpack1('L')
48
- if rvalue == GL::FALSE
49
- $stderr.puts "Error in linking program"
50
- log_length = ' ' * 4
51
- GL.GetProgramiv(handle, GL::INFO_LOG_LENGTH, log_length)
52
- log_length = log_length.unpack1('L')
53
- if log_length > 0
54
- buf = ' ' * log_length
55
- GL.GetProgramInfoLog(handle, log_length, nil, buf)
56
- $stderr.puts(buf)
57
- exit()
58
- end
48
+ ok = rvalue.unpack1('L')
49
+ return true if ok == GL::TRUE
50
+
51
+ $stderr.puts "Error in linking program"
52
+ log_length = ' ' * 4
53
+ GL.GetProgramiv(handle, GL::INFO_LOG_LENGTH, log_length)
54
+ log_length = log_length.unpack1('L')
55
+ if log_length > 0
56
+ buf = ' ' * log_length
57
+ GL.GetProgramInfoLog(handle, log_length, nil, buf)
58
+ $stderr.puts(buf)
59
59
  end
60
+ false
60
61
  end
61
62
 
62
63
  def self.ImplOpenGL3_Init(glsl_version = nil)
@@ -65,27 +66,56 @@ module ImGui
65
66
  GL.GetIntegerv(GL::MINOR_VERSION, minor)
66
67
  major = major.unpack1('L')
67
68
  minor = minor.unpack1('L')
68
- @@g_GlVersion = major * 1000 + minor
69
+
70
+ # OpenGL 2.x fallback when GL_MAJOR_VERSION/GL_MINOR_VERSION are unavailable.
71
+ if major == 0 && minor == 0 && GL.respond_to?(:GetString)
72
+ version_string = GL.GetString(GL::VERSION).to_s
73
+ parts = version_string.split(/[ .]/)
74
+ major = parts[0].to_i
75
+ minor = parts[1].to_i
76
+ end
77
+
78
+ @@g_GlVersion = major * 100 + minor * 10
79
+
80
+ max_texture_size = ' ' * 4
81
+ GL.GetIntegerv(GL::MAX_TEXTURE_SIZE, max_texture_size)
82
+ @@g_MaxTextureSize = max_texture_size.unpack1('L')
69
83
 
70
84
  io = ImGuiIO.new(ImGui::GetIO())
71
85
  io[:BackendRendererName] = @@g_BackendRendererName
72
- io[:BackendFlags] |= ImGuiBackendFlags_RendererHasVtxOffset if @@g_GlVersion >= 3200
73
-
74
- # Ref.: Fix imgui_impl_opengl3 on MacOS
75
- # https://github.com/ocornut/imgui/pull/3199
76
- if GL.get_platform() == :OPENGL_PLATFORM_MACOSX
77
- glsl_version = "#version 150" if glsl_version == nil
78
- else
79
- glsl_version = "#version 130" if glsl_version == nil
86
+ io[:BackendFlags] |= ImGuiBackendFlags_RendererHasVtxOffset if @@g_GlVersion >= 320
87
+ io[:BackendFlags] |= ImGuiBackendFlags_RendererHasTextures
88
+
89
+ platform_io = ImGuiPlatformIO.new(ImGui::GetPlatformIO())
90
+ platform_io[:Renderer_TextureMaxWidth] = @@g_MaxTextureSize
91
+ platform_io[:Renderer_TextureMaxHeight] = @@g_MaxTextureSize
92
+
93
+ if glsl_version.nil?
94
+ if GL.get_platform() == :OPENGL_PLATFORM_MACOSX
95
+ glsl_version = '#version 150'
96
+ else
97
+ glsl_version = '#version 130'
98
+ end
80
99
  end
81
100
 
82
- @@g_GlslVersionString = glsl_version.dup
101
+ @@g_GlslVersionString = glsl_version.end_with?("\n") ? glsl_version.dup : "#{glsl_version}\n"
83
102
 
84
- return true
103
+ true
85
104
  end
86
105
 
87
106
  def self.ImplOpenGL3_Shutdown()
88
107
  ImplOpenGL3_DestroyDeviceObjects()
108
+
109
+ io = ImGuiIO.new(ImGui::GetIO())
110
+ io[:BackendRendererName] = nil
111
+ io[:BackendFlags] &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures)
112
+
113
+ begin
114
+ platform_io = ImGuiPlatformIO.new(ImGui::GetPlatformIO())
115
+ platform_io.ClearRendererHandlers()
116
+ rescue StandardError
117
+ # Older generated bindings may not expose all platform IO helpers.
118
+ end
89
119
  end
90
120
 
91
121
  def self.ImplOpenGL3_NewFrame()
@@ -93,32 +123,38 @@ module ImGui
93
123
  end
94
124
 
95
125
  def self.ImplOpenGL3_RenderDrawData(draw_data_raw)
96
- # Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
97
126
  draw_data = ImDrawData.new(draw_data_raw)
127
+
128
+ # Avoid rendering when minimized, scale coordinates for retina displays.
98
129
  fb_width = (draw_data[:DisplaySize][:x] * draw_data[:FramebufferScale][:x]).to_i
99
130
  fb_height = (draw_data[:DisplaySize][:y] * draw_data[:FramebufferScale][:y]).to_i
131
+ return if fb_width <= 0 || fb_height <= 0
132
+
133
+ ImplOpenGL3_ProcessTextureUpdates(draw_data)
100
134
 
101
- return if fb_width == 0 || fb_height == 0
135
+ last_active_texture = ' ' * 4; GL.GetIntegerv(GL::ACTIVE_TEXTURE, last_active_texture)
136
+ GL.ActiveTexture(GL::TEXTURE0)
102
137
 
103
- # Backup GL state
104
- last_active_texture = ' ' * 4; GL.GetIntegerv(GL::ACTIVE_TEXTURE, last_active_texture)
105
- last_program = ' ' * 4; GL.GetIntegerv(GL::CURRENT_PROGRAM, last_program)
106
- last_texture = ' ' * 4; GL.GetIntegerv(GL::TEXTURE_BINDING_2D, last_texture)
138
+ last_program = ' ' * 4; GL.GetIntegerv(GL::CURRENT_PROGRAM, last_program)
139
+ last_texture = ' ' * 4; GL.GetIntegerv(GL::TEXTURE_BINDING_2D, last_texture)
107
140
 
108
- last_sampler = ' ' * 4; GL.GetIntegerv(GL::SAMPLER_BINDING, last_sampler)
109
- last_array_buffer = ' ' * 4; GL.GetIntegerv(GL::ARRAY_BUFFER_BINDING, last_array_buffer)
110
- last_vertex_array_object = ' ' * 4; GL.GetIntegerv(GL::VERTEX_ARRAY_BINDING, last_vertex_array_object)
141
+ has_sampler = defined?(GL::SAMPLER_BINDING)
142
+ last_sampler = ' ' * 4
143
+ GL.GetIntegerv(GL::SAMPLER_BINDING, last_sampler) if has_sampler
111
144
 
112
- last_polygon_mode = ' ' * 8; GL.GetIntegerv(GL::POLYGON_MODE, last_polygon_mode)
113
- last_viewport = ' ' * 16; GL.GetIntegerv(GL::VIEWPORT, last_viewport)
114
- last_scissor_box = ' ' * 16; GL.GetIntegerv(GL::SCISSOR_BOX, last_scissor_box)
145
+ last_array_buffer = ' ' * 4; GL.GetIntegerv(GL::ARRAY_BUFFER_BINDING, last_array_buffer)
146
+ last_vertex_array_object = ' ' * 4; GL.GetIntegerv(GL::VERTEX_ARRAY_BINDING, last_vertex_array_object)
115
147
 
116
- last_blend_src_rgb = ' ' * 4; GL.GetIntegerv(GL::BLEND_SRC_RGB, last_blend_src_rgb)
117
- last_blend_dst_rgb = ' ' * 4; GL.GetIntegerv(GL::BLEND_DST_RGB, last_blend_dst_rgb)
118
- last_blend_src_alpha = ' ' * 4; GL.GetIntegerv(GL::BLEND_SRC_ALPHA, last_blend_src_alpha)
119
- last_blend_dst_alpha = ' ' * 4; GL.GetIntegerv(GL::BLEND_DST_ALPHA, last_blend_dst_alpha)
120
- last_blend_equation_rgb = ' ' * 4; GL.GetIntegerv(GL::BLEND_EQUATION_RGB, last_blend_equation_rgb)
121
- last_blend_equation_alpha = ' ' * 4; GL.GetIntegerv(GL::BLEND_EQUATION_ALPHA, last_blend_equation_alpha)
148
+ last_polygon_mode = ' ' * 8; GL.GetIntegerv(GL::POLYGON_MODE, last_polygon_mode)
149
+ last_viewport = ' ' * 16; GL.GetIntegerv(GL::VIEWPORT, last_viewport)
150
+ last_scissor_box = ' ' * 16; GL.GetIntegerv(GL::SCISSOR_BOX, last_scissor_box)
151
+
152
+ last_blend_src_rgb = ' ' * 4; GL.GetIntegerv(GL::BLEND_SRC_RGB, last_blend_src_rgb)
153
+ last_blend_dst_rgb = ' ' * 4; GL.GetIntegerv(GL::BLEND_DST_RGB, last_blend_dst_rgb)
154
+ last_blend_src_alpha = ' ' * 4; GL.GetIntegerv(GL::BLEND_SRC_ALPHA, last_blend_src_alpha)
155
+ last_blend_dst_alpha = ' ' * 4; GL.GetIntegerv(GL::BLEND_DST_ALPHA, last_blend_dst_alpha)
156
+ last_blend_equation_rgb = ' ' * 4; GL.GetIntegerv(GL::BLEND_EQUATION_RGB, last_blend_equation_rgb)
157
+ last_blend_equation_alpha = ' ' * 4; GL.GetIntegerv(GL::BLEND_EQUATION_ALPHA, last_blend_equation_alpha)
122
158
 
123
159
  last_enable_blend = GL.IsEnabled(GL::BLEND)
124
160
  last_enable_cull_face = GL.IsEnabled(GL::CULL_FACE)
@@ -126,80 +162,70 @@ module ImGui
126
162
  last_enable_stencil_test = GL.IsEnabled(GL::STENCIL_TEST)
127
163
  last_enable_scissor_test = GL.IsEnabled(GL::SCISSOR_TEST)
128
164
 
129
- # Setup desired GL state
130
- vertex_array_object = ' ' * 4
131
- GL.GenVertexArrays(1, vertex_array_object)
132
- vertex_array_object = vertex_array_object.unpack1('L')
165
+ # Recreate VAO every frame so this works across multiple GL contexts.
166
+ vao_mem = ' ' * 4
167
+ GL.GenVertexArrays(1, vao_mem)
168
+ vertex_array_object = vao_mem.unpack1('L')
133
169
  ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object)
134
170
 
135
- # Will project scissor/clipping rectangles into framebuffer space
136
- clip_off = draw_data[:DisplayPos] # (0,0) unless using multi-viewports
137
- clip_scale = draw_data[:FramebufferScale] # (1,1) unless using retina display which are often (2,2)
171
+ clip_off = draw_data[:DisplayPos]
172
+ clip_scale = draw_data[:FramebufferScale]
173
+
174
+ cmd_list_data = draw_data[:CmdLists][:Data]
175
+ pointer_stride = FFI::Pointer.size
138
176
 
139
- # Render command lists
140
177
  draw_data[:CmdListsCount].times do |n|
178
+ cmd_list_ptr = (cmd_list_data + pointer_stride * n).read_pointer
179
+ cmd_list = ImDrawList.new(cmd_list_ptr)
141
180
 
142
- cmd_list = ImDrawList.new((draw_data[:CmdLists][:Data] + 8 * n).read_pointer) # 8 == const ImDrawList*
143
- # vtx_buffer = ImDrawVert.new(cmd_list[:VtxBuffer][:Data]) # const ImDrawVert*
144
- # idx_buffer = cmd_list[:IdxBuffer][:Data] # const ImDrawIdx*
181
+ vtx_size = cmd_list[:VtxBuffer][:Size] * ImDrawVert.size
182
+ idx_size = cmd_list[:IdxBuffer][:Size] * 2 # ImDrawIdx is currently ushort in generated bindings.
145
183
 
146
- # Upload vertex/index buffers
147
- GL.BufferData(GL::ARRAY_BUFFER, cmd_list[:VtxBuffer][:Size] * ImDrawVert.size, Fiddle::Pointer.new(cmd_list[:VtxBuffer][:Data]), GL::STREAM_DRAW)
148
- # 2 == ImDrawIdx(:ushort).size
149
- GL.BufferData(GL::ELEMENT_ARRAY_BUFFER, cmd_list[:IdxBuffer][:Size] * 2, Fiddle::Pointer.new(cmd_list[:IdxBuffer][:Data]), GL::STREAM_DRAW) # [TODO] Refer ImGui::ImDrawIdx
184
+ GL.BufferData(GL::ARRAY_BUFFER, vtx_size, Fiddle::Pointer.new(cmd_list[:VtxBuffer][:Data]), GL::STREAM_DRAW)
185
+ GL.BufferData(GL::ELEMENT_ARRAY_BUFFER, idx_size, Fiddle::Pointer.new(cmd_list[:IdxBuffer][:Data]), GL::STREAM_DRAW)
150
186
 
151
187
  cmd_list[:CmdBuffer][:Size].times do |cmd_i|
152
- pcmd = ImDrawCmd.new(cmd_list[:CmdBuffer][:Data] + ImDrawCmd.size * cmd_i) # const ImDrawCmd*
188
+ pcmd = ImDrawCmd.new(cmd_list[:CmdBuffer][:Data] + ImDrawCmd.size * cmd_i)
153
189
  if pcmd[:UserCallback] != nil
154
- # [TODO] Handle user callback (Ref.: https://github.com/ffi/ffi/wiki/Callbacks )
155
-
156
- # User callback, registered via ImDrawList::AddCallback()
157
- # (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
158
- # if pcmd[:UserCallback] == :ImDrawCallback_ResetRenderState
159
- ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object)
160
- # else
161
- # pcmd[:UserCallback](cmd_list, pcmd)
162
- # end
163
- else
164
- # Project scissor/clipping rectangles into framebuffer space
165
- clip_rect = ImVec4.new
166
- clip_rect[:x] = (pcmd[:ClipRect][:x] - clip_off[:x]) * clip_scale[:x]
167
- clip_rect[:y] = (pcmd[:ClipRect][:y] - clip_off[:y]) * clip_scale[:y]
168
- clip_rect[:z] = (pcmd[:ClipRect][:z] - clip_off[:x]) * clip_scale[:x]
169
- clip_rect[:w] = (pcmd[:ClipRect][:w] - clip_off[:y]) * clip_scale[:y]
170
-
171
- if (clip_rect[:x] < fb_width && clip_rect[:y] < fb_height && clip_rect[:z] >= 0.0 && clip_rect[:w] >= 0.0)
172
- # Apply scissor/clipping rectangle
173
- GL.Scissor(clip_rect[:x].to_i, (fb_height - clip_rect[:w]).to_i, (clip_rect[:z] - clip_rect[:x]).to_i, (clip_rect[:w] - clip_rect[:y]).to_i)
174
-
175
- # Bind texture, Draw
176
- GL.BindTexture(GL::TEXTURE_2D, pcmd.GetTexID())
177
-
178
- if @@g_GlVersion >= 3200
179
- # 2 == ImDrawIdx(:ushort).size
180
- GL.DrawElementsBaseVertex(GL::TRIANGLES, pcmd[:ElemCount], GL::UNSIGNED_SHORT, Fiddle::Pointer.new(pcmd[:IdxOffset] * 2), pcmd[:VtxOffset])
181
- else
182
- # 2 == ImDrawIdx(:ushort).size
183
- GL.DrawElements(GL::TRIANGLES, pcmd[:ElemCount], GL::UNSIGNED_SHORT, Fiddle::Pointer.new(pcmd[:IdxOffset] * 2))
184
- end
185
- end
190
+ # Reset callback token is not exposed cleanly in current bindings, so keep old behavior.
191
+ ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object)
192
+ next
193
+ end
186
194
 
195
+ clip_min_x = (pcmd[:ClipRect][:x] - clip_off[:x]) * clip_scale[:x]
196
+ clip_min_y = (pcmd[:ClipRect][:y] - clip_off[:y]) * clip_scale[:y]
197
+ clip_max_x = (pcmd[:ClipRect][:z] - clip_off[:x]) * clip_scale[:x]
198
+ clip_max_y = (pcmd[:ClipRect][:w] - clip_off[:y]) * clip_scale[:y]
199
+
200
+ next if clip_max_x <= clip_min_x || clip_max_y <= clip_min_y
201
+
202
+ GL.Scissor(clip_min_x.to_i, (fb_height - clip_max_y).to_i, (clip_max_x - clip_min_x).to_i, (clip_max_y - clip_min_y).to_i)
203
+
204
+ GL.BindTexture(GL::TEXTURE_2D, pcmd.GetTexID())
205
+ if @@g_GlVersion >= 320
206
+ GL.DrawElementsBaseVertex(GL::TRIANGLES, pcmd[:ElemCount], GL::UNSIGNED_SHORT, Fiddle::Pointer.new(pcmd[:IdxOffset] * 2), pcmd[:VtxOffset])
207
+ else
208
+ GL.DrawElements(GL::TRIANGLES, pcmd[:ElemCount], GL::UNSIGNED_SHORT, Fiddle::Pointer.new(pcmd[:IdxOffset] * 2))
187
209
  end
188
- # idx_buffer += pcmd[:ElemCount] * 2 # 2 == ImDrawIdx(:ushort).size
189
210
  end
190
211
  end
191
212
 
192
- # Destroy the temporary VAO
193
213
  GL.DeleteVertexArrays(1, [vertex_array_object].pack('L'))
194
214
 
195
- # Restore modified GL state
196
215
  GL.UseProgram(last_program.unpack1('L'))
197
216
  GL.BindTexture(GL::TEXTURE_2D, last_texture.unpack1('L'))
198
- GL.BindSampler(0, last_sampler.unpack1('L'))
217
+ GL.BindSampler(0, last_sampler.unpack1('L')) if has_sampler
199
218
  GL.ActiveTexture(last_active_texture.unpack1('L'))
200
219
  GL.BindVertexArray(last_vertex_array_object.unpack1('L'))
201
220
  GL.BindBuffer(GL::ARRAY_BUFFER, last_array_buffer.unpack1('L'))
221
+
202
222
  GL.BlendEquationSeparate(last_blend_equation_rgb.unpack1('L'), last_blend_equation_alpha.unpack1('L'))
223
+ GL.BlendFuncSeparate(
224
+ last_blend_src_rgb.unpack1('L'),
225
+ last_blend_dst_rgb.unpack1('L'),
226
+ last_blend_src_alpha.unpack1('L'),
227
+ last_blend_dst_alpha.unpack1('L')
228
+ )
203
229
 
204
230
  if last_enable_blend then GL.Enable(GL::BLEND) else GL.Disable(GL::BLEND) end
205
231
  if last_enable_cull_face then GL.Enable(GL::CULL_FACE) else GL.Disable(GL::CULL_FACE) end
@@ -209,17 +235,15 @@ module ImGui
209
235
 
210
236
  last_polygon_mode = last_polygon_mode.unpack('L2')
211
237
  GL.PolygonMode(GL::FRONT_AND_BACK, last_polygon_mode[0])
238
+
212
239
  last_viewport = last_viewport.unpack('L4')
213
240
  GL.Viewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3])
241
+
214
242
  last_scissor_box = last_scissor_box.unpack('L4')
215
243
  GL.Scissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3])
216
-
217
244
  end
218
245
 
219
- # private
220
-
221
246
  def self.ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object)
222
- # Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
223
247
  GL.Enable(GL::BLEND)
224
248
  GL.BlendEquation(GL::FUNC_ADD)
225
249
  GL.BlendFuncSeparate(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA, GL::ONE, GL::ONE_MINUS_SRC_ALPHA)
@@ -227,30 +251,30 @@ module ImGui
227
251
  GL.Disable(GL::DEPTH_TEST)
228
252
  GL.Disable(GL::STENCIL_TEST)
229
253
  GL.Enable(GL::SCISSOR_TEST)
230
- GL.PolygonMode(GL::FRONT_AND_BACK, GL::FILL) # GL::POLYGON_MODE
254
+ GL.PolygonMode(GL::FRONT_AND_BACK, GL::FILL)
231
255
 
232
- # Setup viewport, orthographic projection matrix
233
- # 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.
234
256
  GL.Viewport(0, 0, fb_width, fb_height)
235
257
  l = draw_data[:DisplayPos][:x]
236
258
  r = draw_data[:DisplayPos][:x] + draw_data[:DisplaySize][:x]
237
259
  t = draw_data[:DisplayPos][:y]
238
260
  b = draw_data[:DisplayPos][:y] + draw_data[:DisplaySize][:y]
261
+
239
262
  ortho_projection = [
240
- 2.0/(r-l), 0.0, 0.0, 0.0,
241
- 0.0, 2.0/(t-b), 0.0, 0.0,
242
- 0.0, 0.0, -1.0, 0.0,
243
- (r+l)/(l-r), (t+b)/(b-t), 0.0, 1.0,
263
+ 2.0 / (r - l), 0.0, 0.0, 0.0,
264
+ 0.0, 2.0 / (t - b), 0.0, 0.0,
265
+ 0.0, 0.0, -1.0, 0.0,
266
+ (r + l) / (l - r), (t + b) / (b - t), 0.0, 1.0,
244
267
  ]
268
+
245
269
  GL.UseProgram(@@g_ShaderHandle)
246
270
  GL.Uniform1i(@@g_AttribLocationTex, 0)
247
271
  GL.UniformMatrix4fv(@@g_AttribLocationProjMtx, 1, GL::FALSE, ortho_projection.pack('F16'))
248
- # GL::SAMPLER_BINDING
249
- GL.BindSampler(0, 0) # We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
250
272
 
251
- GL.BindVertexArray(vertex_array_object)
273
+ if defined?(GL::SAMPLER_BINDING)
274
+ GL.BindSampler(0, 0)
275
+ end
252
276
 
253
- # Bind vertex/index buffers and setup attributes for ImDrawVert
277
+ GL.BindVertexArray(vertex_array_object)
254
278
  GL.BindBuffer(GL::ARRAY_BUFFER, @@g_VboHandle)
255
279
  GL.BindBuffer(GL::ELEMENT_ARRAY_BUFFER, @@g_ElementsHandle)
256
280
 
@@ -258,67 +282,139 @@ module ImGui
258
282
  GL.EnableVertexAttribArray(@@g_AttribLocationVtxUV)
259
283
  GL.EnableVertexAttribArray(@@g_AttribLocationVtxColor)
260
284
 
261
- GL.VertexAttribPointer(@@g_AttribLocationVtxPos, 2, GL::FLOAT, GL::FALSE, ImDrawVert.size, ImDrawVert.offset_of(:pos))
262
- GL.VertexAttribPointer(@@g_AttribLocationVtxUV, 2, GL::FLOAT, GL::FALSE, ImDrawVert.size, ImDrawVert.offset_of(:uv))
263
- GL.VertexAttribPointer(@@g_AttribLocationVtxColor, 4, GL::UNSIGNED_BYTE, GL::TRUE, ImDrawVert.size, ImDrawVert.offset_of(:col))
264
-
285
+ GL.VertexAttribPointer(@@g_AttribLocationVtxPos, 2, GL::FLOAT, GL::FALSE, ImDrawVert.size, ImDrawVert.offset_of(:pos))
286
+ GL.VertexAttribPointer(@@g_AttribLocationVtxUV, 2, GL::FLOAT, GL::FALSE, ImDrawVert.size, ImDrawVert.offset_of(:uv))
287
+ GL.VertexAttribPointer(@@g_AttribLocationVtxColor, 4, GL::UNSIGNED_BYTE, GL::TRUE, ImDrawVert.size, ImDrawVert.offset_of(:col))
265
288
  end
266
289
 
290
+ # Compatibility wrapper retained for older caller code.
267
291
  def self.ImplOpenGL3_CreateFontsTexture()
268
- # Build texture atlas
269
- io = ImGuiIO.new(ImGui::GetIO())
270
- pixels = FFI::MemoryPointer.new :pointer
271
- width = FFI::MemoryPointer.new :int
272
- height = FFI::MemoryPointer.new :int
273
- io[:Fonts].GetTexDataAsRGBA32(pixels, width, height, nil) # Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
292
+ true
293
+ end
274
294
 
275
- # Upload texture to graphics system
276
- last_texture = ' ' * 4
277
- @@g_FontTexture = ' ' * 4
278
- GL.GetIntegerv(GL::TEXTURE_BINDING_2D, last_texture)
279
- GL.GenTextures(1, @@g_FontTexture)
280
- GL.BindTexture(GL::TEXTURE_2D, @@g_FontTexture.unpack1('L'))
281
- GL.TexParameteri(GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::LINEAR)
282
- GL.TexParameteri(GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::LINEAR)
283
- GL.PixelStorei(GL::UNPACK_ROW_LENGTH, 0)
284
- # Ruby/FFI <-> Fiddle pointer exchange
285
- # p pixels
286
- # p pixels.read_pointer
287
- # p pixels.read_pointer.address.to_s(16)
288
- pixels_ptr = Fiddle::Pointer.new(pixels.read_pointer.address)
289
- GL.TexImage2D(GL::TEXTURE_2D, 0, GL::RGBA, width.read_uint, height.read_uint, 0, GL::RGBA, GL::UNSIGNED_BYTE, pixels_ptr)
290
-
291
- # Store our identifier
292
- io[:Fonts][:TexID] = @@g_FontTexture.unpack1('L')
293
-
294
- # Restore state
295
- GL.BindTexture(GL::TEXTURE_2D, last_texture.unpack1('L'))
295
+ # Compatibility wrapper retained for older caller code.
296
+ def self.ImplOpenGL3_DestroyFontsTexture()
297
+ nil
298
+ end
296
299
 
297
- return true
300
+ def self.ImplOpenGL3_ProcessTextureUpdates(draw_data)
301
+ textures_ptr = draw_data[:Textures]
302
+ return if textures_ptr.nil? || textures_ptr.null?
303
+
304
+ textures = ImVector.new(textures_ptr)
305
+ data_ptr = textures[:Data]
306
+ pointer_stride = FFI::Pointer.size
307
+
308
+ textures[:Size].times do |i|
309
+ tex_ptr = (data_ptr + pointer_stride * i).read_pointer
310
+ next if tex_ptr.nil? || tex_ptr.null?
311
+
312
+ tex = ImTextureData.new(tex_ptr)
313
+ ImplOpenGL3_UpdateTexture(tex) if tex[:Status] != ImTextureStatus_OK
314
+ end
298
315
  end
299
316
 
300
- def self.ImplOpenGL3_DestroyFontsTexture()
301
- if @@g_FontTexture != 0
302
- GL.DeleteTextures(1, @@g_FontTexture)
303
- io = ImGuiIO.new(ImGui::GetIO())
304
- io[:Fonts][:TexID] = 0
305
- @@g_FontTexture = 0
317
+ def self.ImplOpenGL3_DestroyTexture(tex)
318
+ gl_tex_id = tex.GetTexID()
319
+ if gl_tex_id != 0
320
+ GL.DeleteTextures(1, [gl_tex_id].pack('L'))
321
+ end
322
+
323
+ tex.SetTexID(0)
324
+ tex.SetStatus(ImTextureStatus_Destroyed)
325
+ end
326
+
327
+ def self.ImplOpenGL3_AsGLPointer(pointer)
328
+ return nil if pointer.nil? || pointer.null?
329
+
330
+ Fiddle::Pointer.new(pointer.to_i)
331
+ end
332
+
333
+ def self.ImplOpenGL3_UpdateTexture(tex)
334
+ status = tex[:Status]
335
+
336
+ if status == ImTextureStatus_WantCreate || status == ImTextureStatus_WantUpdates
337
+ GL.PixelStorei(GL::UNPACK_ROW_LENGTH, 0) if defined?(GL::UNPACK_ROW_LENGTH)
338
+ GL.PixelStorei(GL::UNPACK_ALIGNMENT, 1) if defined?(GL::UNPACK_ALIGNMENT)
339
+ end
340
+
341
+ if status == ImTextureStatus_WantCreate
342
+ return unless tex[:Format] == ImTextureFormat_RGBA32
343
+
344
+ last_texture = ' ' * 4
345
+ GL.GetIntegerv(GL::TEXTURE_BINDING_2D, last_texture)
346
+
347
+ texture_mem = ' ' * 4
348
+ GL.GenTextures(1, texture_mem)
349
+ gl_texture_id = texture_mem.unpack1('L')
350
+
351
+ GL.BindTexture(GL::TEXTURE_2D, gl_texture_id)
352
+ GL.TexParameteri(GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::LINEAR)
353
+ GL.TexParameteri(GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::LINEAR)
354
+ GL.TexParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_S, GL::CLAMP_TO_EDGE)
355
+ GL.TexParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_T, GL::CLAMP_TO_EDGE)
356
+
357
+ pixels_ptr = ImplOpenGL3_AsGLPointer(tex[:Pixels])
358
+ GL.TexImage2D(GL::TEXTURE_2D, 0, GL::RGBA, tex[:Width], tex[:Height], 0, GL::RGBA, GL::UNSIGNED_BYTE, pixels_ptr)
359
+
360
+ tex.SetTexID(gl_texture_id)
361
+ tex.SetStatus(ImTextureStatus_OK)
362
+
363
+ GL.BindTexture(GL::TEXTURE_2D, last_texture.unpack1('L'))
364
+ return
365
+ end
366
+
367
+ if status == ImTextureStatus_WantUpdates
368
+ last_texture = ' ' * 4
369
+ GL.GetIntegerv(GL::TEXTURE_BINDING_2D, last_texture)
370
+
371
+ GL.BindTexture(GL::TEXTURE_2D, tex.GetTexID())
372
+
373
+ updates = tex[:Updates]
374
+ updates_ptr = updates[:Data]
375
+
376
+ if !updates_ptr.nil? && !updates_ptr.null?
377
+ if defined?(GL::UNPACK_ROW_LENGTH)
378
+ GL.PixelStorei(GL::UNPACK_ROW_LENGTH, tex[:Width])
379
+
380
+ updates[:Size].times do |i|
381
+ rect = ImTextureRect.new(updates_ptr + i * ImTextureRect.size)
382
+ pixels_ptr = ImplOpenGL3_AsGLPointer(tex.GetPixelsAt(rect[:x], rect[:y]))
383
+ GL.TexSubImage2D(GL::TEXTURE_2D, 0, rect[:x], rect[:y], rect[:w], rect[:h], GL::RGBA, GL::UNSIGNED_BYTE, pixels_ptr)
384
+ end
385
+
386
+ GL.PixelStorei(GL::UNPACK_ROW_LENGTH, 0)
387
+ else
388
+ updates[:Size].times do |i|
389
+ rect = ImTextureRect.new(updates_ptr + i * ImTextureRect.size)
390
+ rect[:h].times do |line|
391
+ pixels_ptr = ImplOpenGL3_AsGLPointer(tex.GetPixelsAt(rect[:x], rect[:y] + line))
392
+ GL.TexSubImage2D(GL::TEXTURE_2D, 0, rect[:x], rect[:y] + line, rect[:w], 1, GL::RGBA, GL::UNSIGNED_BYTE, pixels_ptr)
393
+ end
394
+ end
395
+ end
396
+ end
397
+
398
+ tex.SetStatus(ImTextureStatus_OK)
399
+ GL.BindTexture(GL::TEXTURE_2D, last_texture.unpack1('L'))
400
+ return
401
+ end
402
+
403
+ if status == ImTextureStatus_WantDestroy && tex[:UnusedFrames] > 0
404
+ ImplOpenGL3_DestroyTexture(tex)
306
405
  end
307
406
  end
308
407
 
309
408
  def self.ImplOpenGL3_CreateDeviceObjects()
310
- # Backup GL state
311
- last_texture, last_array_buffer = ' ' * 4, ' ' * 4
409
+ last_texture = ' ' * 4
410
+ last_array_buffer = ' ' * 4
312
411
  GL.GetIntegerv(GL::TEXTURE_BINDING_2D, last_texture)
313
412
  GL.GetIntegerv(GL::ARRAY_BUFFER_BINDING, last_array_buffer)
314
- last_texture = last_texture.unpack1('L')
315
- last_array_buffer = last_array_buffer.unpack1('L')
316
413
 
317
414
  last_vertex_array = ' ' * 4
318
415
  GL.GetIntegerv(GL::VERTEX_ARRAY_BINDING, last_vertex_array)
319
- last_vertex_array = last_vertex_array.unpack1('L')
320
416
 
321
- glsl_version = @@g_GlslVersionString.split[1].to_i # == scanf(@@g_GlslVersionString, "#version %d")
417
+ glsl_version = @@g_GlslVersionString.split[1].to_i
322
418
 
323
419
  vertex_shader_glsl_120 = <<-'SRC'
324
420
  uniform mat4 ProjMtx;
@@ -351,7 +447,7 @@ module ImGui
351
447
  SRC
352
448
 
353
449
  vertex_shader_glsl_300_es = <<-'SRC'
354
- precision mediump float;
450
+ precision highp float;
355
451
  layout (location = 0) in vec2 Position;
356
452
  layout (location = 1) in vec2 UV;
357
453
  layout (location = 2) in vec4 Color;
@@ -382,7 +478,7 @@ module ImGui
382
478
  SRC
383
479
 
384
480
  fragment_shader_glsl_120 = <<-'SRC'
385
- #ifdef GL::ES
481
+ #ifdef GL_ES
386
482
  precision mediump float;
387
483
  #endif
388
484
  uniform sampler2D Texture;
@@ -438,55 +534,45 @@ module ImGui
438
534
  [vertex_shader_glsl_130, fragment_shader_glsl_130]
439
535
  end
440
536
 
441
- vertex_shader.prepend(@@g_GlslVersionString + "\n")
442
537
  vert_handle = GL.CreateShader(GL::VERTEX_SHADER)
443
- GL.ShaderSource(vert_handle, 1, [vertex_shader].pack('p'), nil)
538
+ GL.ShaderSource(vert_handle, 2, [@@g_GlslVersionString, vertex_shader].pack('p*'), nil)
444
539
  GL.CompileShader(vert_handle)
445
- PrintShaderCompileStatus(vert_handle)
540
+ return false unless PrintShaderCompileStatus(vert_handle)
446
541
 
447
- fragment_shader.prepend(@@g_GlslVersionString + "\n")
448
542
  frag_handle = GL.CreateShader(GL::FRAGMENT_SHADER)
449
- GL.ShaderSource(frag_handle, 1, [fragment_shader].pack('p'), [fragment_shader.size].pack('I'))
543
+ GL.ShaderSource(frag_handle, 2, [@@g_GlslVersionString, fragment_shader].pack('p*'), nil)
450
544
  GL.CompileShader(frag_handle)
451
- PrintShaderCompileStatus(frag_handle)
545
+ return false unless PrintShaderCompileStatus(frag_handle)
452
546
 
453
547
  @@g_ShaderHandle = GL.CreateProgram()
454
548
  GL.AttachShader(@@g_ShaderHandle, vert_handle)
455
549
  GL.AttachShader(@@g_ShaderHandle, frag_handle)
456
550
  GL.LinkProgram(@@g_ShaderHandle)
457
- PrintProgramLinkStatus(@@g_ShaderHandle)
551
+ return false unless PrintProgramLinkStatus(@@g_ShaderHandle)
458
552
 
459
553
  GL.DetachShader(@@g_ShaderHandle, vert_handle)
460
554
  GL.DetachShader(@@g_ShaderHandle, frag_handle)
461
555
  GL.DeleteShader(vert_handle)
462
556
  GL.DeleteShader(frag_handle)
463
557
 
464
- @@g_AttribLocationTex = GL.GetUniformLocation(@@g_ShaderHandle, "Texture")
465
- @@g_AttribLocationProjMtx = GL.GetUniformLocation(@@g_ShaderHandle, "ProjMtx")
558
+ @@g_AttribLocationTex = GL.GetUniformLocation(@@g_ShaderHandle, 'Texture')
559
+ @@g_AttribLocationProjMtx = GL.GetUniformLocation(@@g_ShaderHandle, 'ProjMtx')
560
+ @@g_AttribLocationVtxPos = GL.GetAttribLocation(@@g_ShaderHandle, 'Position')
561
+ @@g_AttribLocationVtxUV = GL.GetAttribLocation(@@g_ShaderHandle, 'UV')
562
+ @@g_AttribLocationVtxColor = GL.GetAttribLocation(@@g_ShaderHandle, 'Color')
466
563
 
467
- @@g_AttribLocationVtxPos = GL.GetAttribLocation(@@g_ShaderHandle, "Position")
468
- @@g_AttribLocationVtxUV = GL.GetAttribLocation(@@g_ShaderHandle, "UV")
469
- @@g_AttribLocationVtxColor = GL.GetAttribLocation(@@g_ShaderHandle, "Color")
564
+ vbo_mem = ' ' * 4
565
+ elem_mem = ' ' * 4
566
+ GL.GenBuffers(1, vbo_mem)
567
+ GL.GenBuffers(1, elem_mem)
568
+ @@g_VboHandle = vbo_mem.unpack1('L')
569
+ @@g_ElementsHandle = elem_mem.unpack1('L')
470
570
 
471
- # Create buffers
472
- posBuf = ' ' * 4
473
- GL.GenBuffers(1, posBuf)
474
- GL.BindBuffer(GL::ARRAY_BUFFER, posBuf.unpack('L')[0])
475
-
476
- @@g_VboHandle, @@g_ElementsHandle = ' ' * 4, ' ' * 4
477
- GL.GenBuffers(1, @@g_VboHandle)
478
- GL.GenBuffers(1, @@g_ElementsHandle)
479
- @@g_VboHandle = @@g_VboHandle.unpack1('L')
480
- @@g_ElementsHandle = @@g_ElementsHandle.unpack1('L')
481
-
482
- ImplOpenGL3_CreateFontsTexture()
483
-
484
- # Restore modified GL state
485
- GL.BindTexture(GL::TEXTURE_2D, last_texture)
486
- GL.BindBuffer(GL::ARRAY_BUFFER, last_array_buffer)
487
- GL.BindVertexArray(last_vertex_array)
571
+ GL.BindTexture(GL::TEXTURE_2D, last_texture.unpack1('L'))
572
+ GL.BindBuffer(GL::ARRAY_BUFFER, last_array_buffer.unpack1('L'))
573
+ GL.BindVertexArray(last_vertex_array.unpack1('L'))
488
574
 
489
- return true
575
+ true
490
576
  end
491
577
 
492
578
  def self.ImplOpenGL3_DestroyDeviceObjects()
@@ -494,16 +580,32 @@ module ImGui
494
580
  GL.DeleteBuffers(1, [@@g_VboHandle].pack('L'))
495
581
  @@g_VboHandle = 0
496
582
  end
583
+
497
584
  if @@g_ElementsHandle != 0
498
585
  GL.DeleteBuffers(1, [@@g_ElementsHandle].pack('L'))
499
586
  @@g_ElementsHandle = 0
500
587
  end
588
+
501
589
  if @@g_ShaderHandle != 0
502
590
  GL.DeleteProgram(@@g_ShaderHandle)
503
591
  @@g_ShaderHandle = 0
504
592
  end
505
593
 
506
- ImplOpenGL3_DestroyFontsTexture()
594
+ # Destroy textures retained only by the renderer backend.
595
+ platform_io = ImGuiPlatformIO.new(ImGui::GetPlatformIO())
596
+ textures = platform_io[:Textures]
597
+ tex_data = textures[:Data]
598
+
599
+ if !tex_data.nil? && !tex_data.null?
600
+ pointer_stride = FFI::Pointer.size
601
+ textures[:Size].times do |i|
602
+ tex_ptr = (tex_data + pointer_stride * i).read_pointer
603
+ next if tex_ptr.nil? || tex_ptr.null?
604
+
605
+ tex = ImTextureData.new(tex_ptr)
606
+ ImplOpenGL3_DestroyTexture(tex) if tex[:RefCount] == 1
607
+ end
608
+ end
507
609
  end
508
610
 
509
611
  end