2
0

PasImGui.Renderer.OpenGL3.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. Unit PasImGui.Renderer.OpenGL3;
  2. {$I ImGuiPasDef.inc}
  3. {$IFDEF FPC}
  4. {$mode Delphi}{$H+}
  5. {$ENDIF}
  6. {$POINTERMATH ON}
  7. // Debugging
  8. {$IfOpt D+}
  9. {$If Defined(FPC) or Defined(DelphiXEAndUp)}
  10. {$Define IMGUI_LOG}
  11. {$EndIf}
  12. {$EndIf}
  13. // Specific OpenGL ES versions
  14. //{$Define IMGUI_OPENGL_ES2}
  15. //{$Define IMGUI_OPENGL_ES3}
  16. {$If not Defined(IMGUI_OPENGL_ES2) and not Defined(IMGUI_OPENGL_ES3)}
  17. {$If (Defined(DARWIN) or Defined(IOS)) or Defined(Android)}
  18. {$Define IMGUI_OPENGL_ES3}
  19. {$ElseIf defined(AMIGA)}
  20. {$Define IMGUI_OPENGL_ES2}
  21. {$EndIf}
  22. {$EndIf}
  23. //{$Define IMGUI_OPENGL_LOADER_CUSTOM} // If you have your own loader :V
  24. // We already know we have 3.+ :V
  25. {$Define GL_VERSION_3_1}
  26. {$Define GL_VERSION_3_2}
  27. {$Define GL_VERSION_3_3}
  28. // Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
  29. {$Define IMGUI_HAS_POLYGON_MODE}
  30. // Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
  31. {$IfNDef IMGUI_OPENGL_ES2}
  32. {$Define IMGUI_OPENGL_USE_VERTEX_ARRAY}
  33. {$EndIf}
  34. // Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
  35. {$If not Defined(IMGUI_OPENGL_ES2) and not Defined(IMGUI_OPENGL_ES3) and Defined(GL_VERSION_3_2) }
  36. {$Define IMGUI_OPENGL_MAY_HAVE_VTX_OFFSET}
  37. {$EndIf}
  38. // Desktop GL use extension detection
  39. {$If not Defined(IMGUI_OPENGL_ES2) and not Defined(IMGUI_OPENGL_ES3)}
  40. {$Define IMGUI_OPENGL_MAY_HAVE_EXTENSIONS}
  41. {$EndIf}
  42. // Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler()
  43. {$If not Defined(IMGUI_OPENGL_ES2) and not Defined(IMGUI_OPENGL_ES3) or Defined(GL_VERSION_3_2) }
  44. {$Define IMGUI_OPENGL_MAY_HAVE_BIND_SAMPLER}
  45. {$EndIf}
  46. {$If not Defined(IMGUI_OPENGL_ES2) and not Defined(IMGUI_OPENGL_ES3) or Defined(GL_VERSION_3_1) }
  47. {$Define IMGUI_OPENGL_MAY_HAVE_PRIMITIVE_RESTART}
  48. {$EndIf}
  49. Interface
  50. Uses
  51. SysUtils,
  52. glad_gl,
  53. PasImGui,
  54. PasImGui.Utils,
  55. OpenGl3.Loader;
  56. Type
  57. // OpenGL Data
  58. ImGui_ImplOpenGL3_Data = Record
  59. GlVersion: GLuint;
  60. // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
  61. GlslVersionString: Array[0..31] Of AnsiChar;
  62. // Specified by user or detected based on compile time GL settings.
  63. GlProfileIsES2: Boolean;
  64. GlProfileIsES3: Boolean;
  65. GlProfileIsCompat: Boolean;
  66. GlProfileMask: GLint;
  67. FontTexture: GLuint;
  68. ShaderHandle: GLuint;
  69. AttribLocationTex: GLint; // Uniforms location
  70. AttribLocationProjMtx: GLint;
  71. AttribLocationVtxPos: GLuint; // Vertex attributes location
  72. AttribLocationVtxUV: GLuint;
  73. AttribLocationVtxColor: GLuint;
  74. VboHandle: GLuint;
  75. ElementsHandle: GLuint;
  76. VertexBufferSize: GLsizeiptr;
  77. IndexBufferSize: GLsizeiptr;
  78. HasPolygonMode : Boolean;
  79. HasClipOrigin: Boolean;
  80. UseBufferSubData: Boolean;
  81. End;
  82. PImGui_ImplOpenGL3_Data = ^ImGui_ImplOpenGL3_Data;
  83. procedure ImGui_OpenGL3_RenderDrawData(draw_data: PImDrawData);
  84. Function ImGui_OpenGL3_Init(glsl_version: PAnsiChar): Boolean;
  85. Procedure ImGui_OpenGL3_NewFrame();
  86. Procedure ImGui_OpenGL3_Shutdown();
  87. type
  88. TGLProc = reference to procedure;
  89. TError = reference to procedure(msg : string);
  90. const
  91. ImDrawCallback_ResetRenderState : ImDrawCallback = Pointer(-8);
  92. Implementation
  93. {$IfDef IMGUI_LOG}
  94. procedure OnAssert(const Message, Filename: {$IfDef FPC}ShortString{$ELSE}string{$EndIf}; LineNumber: Integer; ErrorAddr: Pointer);
  95. begin
  96. raise EAssertionFailed.Create(Format('%s (%s, line %d)', [Message, Filename, LineNumber]));
  97. end;
  98. procedure GL_CALL(ACall : TGLProc; AError: TError);
  99. var
  100. gl_err : GLenum;
  101. begin
  102. ACall();
  103. gl_err := glGetError();
  104. if (gl_err <> 0) then
  105. begin
  106. AError(Format('GL error 0x%x', [gl_err]));
  107. end;
  108. end;
  109. {$EndIf}
  110. Function ImGui_ImplOpenGL3_GetBackendData(): PImGui_ImplOpenGL3_Data;
  111. Begin
  112. If ImGui.GetCurrentContext() <> nil Then
  113. Result := PImGui_ImplOpenGL3_Data(ImGui.GetIO()^.BackendRendererUserData)
  114. Else
  115. Result := nil;
  116. End;
  117. procedure ImGui_ImplOpenGL3_SetupRenderState(draw_data: PImDrawData; fb_width: Integer; fb_height: Integer; vertex_array_object: GLuint);
  118. var
  119. bd: PImGui_ImplOpenGL3_Data;
  120. clip_origin_lower_left: Boolean;
  121. current_clip_origin: GLenum;
  122. L, R, T, B, tmp: Single;
  123. ortho_projection: array[0..3] of array[0..3] of Single;
  124. begin
  125. bd := ImGui_ImplOpenGL3_GetBackendData();
  126. // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
  127. glEnable(GL_BLEND);
  128. glBlendEquation(GL_FUNC_ADD);
  129. glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  130. glDisable(GL_CULL_FACE);
  131. glDisable(GL_DEPTH_TEST);
  132. glDisable(GL_STENCIL_TEST);
  133. glEnable(GL_SCISSOR_TEST);
  134. {$IfDef IMGUI_OPENGL_MAY_HAVE_PRIMITIVE_RESTART}
  135. if (bd^.GlVersion >= 310) then
  136. glDisable(GL_PRIMITIVE_RESTART);
  137. {$EndIf}
  138. {$IfDef IMGUI_HAS_POLYGON_MODE}
  139. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  140. {$EndIf}
  141. clip_origin_lower_left := False;
  142. // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
  143. if GLAD_GL_VERSION_4_5 then
  144. begin
  145. clip_origin_lower_left := True;
  146. if (bd^.HasClipOrigin) then
  147. begin
  148. current_clip_origin := GLenum(0);
  149. glGetIntegerv(GL_CLIP_ORIGIN, @GLint(current_clip_origin));
  150. if (current_clip_origin = GL_UPPER_LEFT) then
  151. begin
  152. clip_origin_lower_left := false;
  153. end;
  154. end;
  155. end;
  156. // Setup viewport, orthographic projection matrix
  157. // Our visible imgui space lies from draw_data^.DisplayPos (top left) to
  158. // draw_data^.DisplayPos+data_data^.DisplaySize (bottom right).
  159. // DisplayPos is (0,0) for single viewport apps.
  160. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  161. glViewport(0, 0, GLsizei(fb_width), GLsizei(fb_height));
  162. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  163. L := draw_data^.DisplayPos.x;
  164. R := draw_data^.DisplayPos.x + draw_data^.DisplaySize.x;
  165. T := draw_data^.DisplayPos.y;
  166. B := draw_data^.DisplayPos.y + draw_data^.DisplaySize.y;
  167. if GLAD_GL_VERSION_4_5 then
  168. begin
  169. if (not clip_origin_lower_left) then
  170. begin
  171. tmp := T;
  172. T := B;
  173. B := tmp;
  174. end; // Swap top and bottom if origin is upper left
  175. end;
  176. FillChar(ortho_projection, SizeOf(ortho_projection), 0);
  177. // Initialize the ortho_projection matrix
  178. ortho_projection[0][0] := 2.0 / (R - L);
  179. ortho_projection[1][1] := 2.0 / (T - B);
  180. ortho_projection[2][2] := -1.0;
  181. ortho_projection[3][0] := (R + L) / (L - R);
  182. ortho_projection[3][1] := (T + B) / (B - T);
  183. ortho_projection[3][3] := 1.0;
  184. glUseProgram(bd^.ShaderHandle);
  185. glUniform1i(bd^.AttribLocationTex, 0);
  186. glUniformMatrix4fv(bd^.AttribLocationProjMtx, 1, Boolean(GL_FALSE), @ortho_projection[0][0]);
  187. {$IfDef IMGUI_OPENGL_MAY_HAVE_BIND_SAMPLER}
  188. if (bd^.GlVersion >= 330) or (bd^.GlProfileIsES3) then
  189. glBindSampler(0, 0);
  190. // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
  191. {$EndIf}
  192. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  193. glBindVertexArray(vertex_array_object);
  194. {$EndIf}
  195. // Bind vertex/index buffers and setup attributes for ImDrawVert
  196. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  197. glBindBuffer(GL_ARRAY_BUFFER, bd^.VboHandle);
  198. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  199. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  200. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd^.ElementsHandle);
  201. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  202. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  203. glEnableVertexAttribArray(bd^.AttribLocationVtxPos);
  204. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  205. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  206. glEnableVertexAttribArray(bd^.AttribLocationVtxUV);
  207. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  208. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  209. glEnableVertexAttribArray(bd^.AttribLocationVtxColor);
  210. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  211. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  212. glVertexAttribPointer(bd^.AttribLocationVtxPos, 2, GL_FLOAT, Boolean(GL_FALSE), sizeof(ImDrawVert), Pointer(IntPtr(@PImDrawVert(nil)^.pos)));
  213. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  214. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  215. glVertexAttribPointer(bd^.AttribLocationVtxUV, 2, GL_FLOAT, Boolean(GL_FALSE), sizeof(ImDrawVert), Pointer(IntPtr(@PImDrawVert(nil)^.uv)));
  216. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  217. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  218. glVertexAttribPointer(bd^.AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, Boolean(GL_TRUE), sizeof(ImDrawVert), Pointer(IntPtr(@PImDrawVert(nil)^.col)));
  219. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  220. end;
  221. // OpenGL3 Render function.
  222. // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
  223. // This is in order to be able to run within an OpenGL engine that doesn't do so.
  224. procedure ImGui_OpenGL3_RenderDrawData(draw_data: PImDrawData);
  225. var
  226. fb_width, fb_height , n, cmd_i: Integer;
  227. bd: PImGui_ImplOpenGL3_Data;
  228. last_program, last_texture,
  229. last_sampler, last_array_buffer,
  230. last_vertex_array_object : GLuint;
  231. last_polygon_mode : Array [0..1] of GLint;
  232. last_viewport : Array [0..3] of GLint;
  233. last_scissor_box : Array [0..3] of GLint;
  234. last_active_texture, last_blend_src_rgb,
  235. last_blend_dst_rgb, last_blend_src_alpha,
  236. last_blend_dst_alpha, last_blend_equation_rgb,
  237. last_blend_equation_alpha : GLenum;
  238. last_enable_blend,
  239. last_enable_cull_face,
  240. last_enable_depth_test,
  241. last_enable_stencil_test,
  242. last_enable_scissor_test,
  243. last_enable_primitive_restart: GLboolean;
  244. vertex_array_object : GLuint;
  245. clip_off, clip_scale, clip_min, clip_max: ImVec2;
  246. cmd_list_ptr : PImDrawList;
  247. vtx_buffer_size, idx_buffer_size: GLsizeiptr;
  248. pcmd: PImDrawCmd;
  249. Begin
  250. // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
  251. fb_width := Trunc(draw_data^.DisplaySize.x * draw_data^.FramebufferScale.x);
  252. fb_height := Trunc(draw_data^.DisplaySize.y * draw_data^.FramebufferScale.y);
  253. if (fb_width <= 0) or (fb_height <= 0) then
  254. Exit;
  255. bd := ImGui_ImplOpenGL3_GetBackendData();
  256. // Backup GL state
  257. glGetIntegerv(GL_ACTIVE_TEXTURE, @GLint(last_active_texture));
  258. glActiveTexture(GL_TEXTURE0);
  259. glGetIntegerv(GL_CURRENT_PROGRAM, @GLint(last_program));
  260. glGetIntegerv(GL_TEXTURE_BINDING_2D, @GLint(last_texture));
  261. {$IfDef IMGUI_OPENGL_MAY_HAVE_BIND_SAMPLER}
  262. if (bd^.GlVersion >= 330) or (bd^.GlProfileIsES3) then
  263. glGetIntegerv(GL_SAMPLER_BINDING, @GLint(last_sampler))
  264. else
  265. last_sampler := 0;
  266. {$EndIf}
  267. glGetIntegerv(GL_ARRAY_BUFFER_BINDING, @GLint(last_array_buffer));
  268. {$IfNDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  269. // This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
  270. { TODO: Get Back to this later - Time : 11/17/2023 1:45:47 AM }
  271. {$EndIf}
  272. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  273. glGetIntegerv(GL_VERTEX_ARRAY_BINDING, @GLint(last_vertex_array_object));
  274. {$EndIf}
  275. {$IfDef IMGUI_HAS_POLYGON_MODE}
  276. glGetIntegerv(GL_POLYGON_MODE, @last_polygon_mode);
  277. {$EndIf}
  278. glGetIntegerv(GL_VIEWPORT, @last_viewport);
  279. glGetIntegerv(GL_SCISSOR_BOX, @last_scissor_box);
  280. glGetIntegerv(GL_BLEND_SRC_RGB, @GLint(last_blend_src_rgb));
  281. glGetIntegerv(GL_BLEND_DST_RGB, @GLint(last_blend_dst_rgb));
  282. glGetIntegerv(GL_BLEND_SRC_ALPHA, @GLint(last_blend_src_alpha));
  283. glGetIntegerv(GL_BLEND_DST_ALPHA, @GLint(last_blend_dst_alpha));
  284. glGetIntegerv(GL_BLEND_EQUATION_RGB, @GLint(last_blend_equation_rgb));
  285. glGetIntegerv(GL_BLEND_EQUATION_ALPHA, @GLint(last_blend_equation_alpha));
  286. last_enable_blend := glIsEnabled(GL_BLEND);
  287. last_enable_cull_face := glIsEnabled(GL_CULL_FACE);
  288. last_enable_depth_test := glIsEnabled(GL_DEPTH_TEST);
  289. last_enable_stencil_test := glIsEnabled(GL_STENCIL_TEST);
  290. last_enable_scissor_test := glIsEnabled(GL_SCISSOR_TEST);
  291. {$IfDef IMGUI_OPENGL_MAY_HAVE_PRIMITIVE_RESTART}
  292. if (bd^.GlVersion >= 310) or (bd^.GlProfileIsES3) then
  293. last_enable_primitive_restart := glIsEnabled(GL_PRIMITIVE_RESTART)
  294. else
  295. last_enable_primitive_restart := Boolean(GL_FALSE);
  296. {$EndIf}
  297. // Setup desired GL state
  298. // Recreate the VAO every time (this is to easily allow multiple GL contexts
  299. // to be rendered to. VAO are not shared among GL contexts).
  300. // The renderer would actually work without any VAO bound, but then our
  301. // VertexAttrib calls would overwrite the default one currently bound.
  302. vertex_array_object := 0;
  303. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  304. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  305. glGenVertexArrays(1, @vertex_array_object);
  306. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  307. {$EndIf}
  308. ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
  309. // Will project scissor/clipping rectangles into framebuffer space
  310. clip_off := draw_data^.DisplayPos; // (0,0) unless using multi-viewports
  311. clip_scale := draw_data^.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
  312. // Render command lists
  313. for n := 0 to Pred(draw_data^.CmdListsCount) do
  314. begin
  315. cmd_list_ptr := draw_data^.CmdLists.Data[n];
  316. // Upload vertex/index buffers
  317. // - OpenGL drivers are in a very sorry state nowadays....
  318. // During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
  319. // of leaks on Intel GPU when using multi-viewports on Windows.
  320. // - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel.
  321. // - We are now back to using exclusively glBufferData(). So bd^.UseBufferSubData IS ALWAYS FALSE in this code.
  322. // We are keeping the old code path for a while in case people finding new issues may want to test the bd^.UseBufferSubData path.
  323. // - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues.
  324. vtx_buffer_size := GLsizeiptr(cmd_list_ptr.VtxBuffer.Size * Integer(SizeOf(ImDrawVert)));
  325. idx_buffer_size := GLsizeiptr(cmd_list_ptr.IdxBuffer.Size * Integer(sizeof(ImDrawIdx)));
  326. if (bd^.UseBufferSubData) then
  327. begin
  328. if (bd^.VertexBufferSize < vtx_buffer_size) then
  329. begin
  330. bd^.VertexBufferSize := vtx_buffer_size;
  331. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  332. glBufferData(GL_ARRAY_BUFFER, bd^.VertexBufferSize, nil, GL_STREAM_DRAW);
  333. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  334. end;
  335. if (bd^.IndexBufferSize < idx_buffer_size) then
  336. begin
  337. bd^.IndexBufferSize := idx_buffer_size;
  338. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  339. glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd^.IndexBufferSize, nil, GL_STREAM_DRAW);
  340. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  341. end;
  342. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  343. glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, cmd_list_ptr.VtxBuffer.Data);
  344. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  345. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  346. glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, cmd_list_ptr.IdxBuffer.Data);
  347. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  348. end
  349. else
  350. begin
  351. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  352. glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, cmd_list_ptr.VtxBuffer.Data, GL_STREAM_DRAW);
  353. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  354. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  355. glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, cmd_list_ptr.IdxBuffer.Data,GL_STREAM_DRAW);
  356. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  357. end;
  358. for cmd_i := 0 to Pred(cmd_list_ptr.CmdBuffer.Size) do
  359. begin
  360. pcmd := @cmd_list_ptr.CmdBuffer.Data[cmd_i];
  361. if @pcmd.UserCallback <> nil then
  362. begin
  363. // User callback, registered via ImDrawList::AddCallback()
  364. // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
  365. if (@pcmd.UserCallback = @ImDrawCallback_ResetRenderState) then
  366. ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object)
  367. else
  368. pcmd.UserCallback(@cmd_list_ptr, @pcmd);
  369. end
  370. else
  371. begin
  372. // Project scissor/clipping rectangles into framebuffer space
  373. clip_min := ImVec2.New((pcmd.ClipRect.x - clip_off.x) * clip_scale.x,
  374. (pcmd.ClipRect.y - clip_off.y) * clip_scale.y);
  375. clip_max := ImVec2.New((pcmd.ClipRect.z - clip_off.x) * clip_scale.x,
  376. (pcmd.ClipRect.w - clip_off.y) * clip_scale.y);
  377. if (clip_max.x <= clip_min.x) or (clip_max.y <= clip_min.y) then
  378. Continue;
  379. // Apply scissor/clipping rectangle (Y is inverted in OpenGL)
  380. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  381. glScissor(Trunc(clip_min.x), Trunc(Single(fb_height - clip_max.y)), Trunc(clip_max.x - clip_min.x), Trunc(clip_max.y - clip_min.y));
  382. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  383. // Bind texture, Draw
  384. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  385. glBindTexture(GL_TEXTURE_2D, {%H-}GLuint(pcmd.GetTexID()));
  386. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  387. {$IfDef IMGUI_OPENGL_MAY_HAVE_VTX_OFFSET}
  388. if (bd^.GlVersion >= 320) then
  389. begin
  390. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  391. glDrawElementsBaseVertex(GL_TRIANGLES, GLsizei(pcmd.ElemCount), {$IfDef ImD_32}GL_UNSIGNED_INT{$ELSE}GL_UNSIGNED_SHORT{$EndIf} ,Pointer(IntPtr(pcmd.IdxOffset * sizeof(ImDrawIdx))), GLint(pcmd.VtxOffset));
  392. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  393. end
  394. else
  395. {$EndIf}
  396. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  397. glDrawElements(GL_TRIANGLES, GLsizei(pcmd.ElemCount), {$IfDef ImD_32}GL_UNSIGNED_INT{$ELSE}GL_UNSIGNED_SHORT{$EndIf},Pointer(IntPtr(pcmd.IdxOffset * sizeof(ImDrawIdx))));
  398. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  399. end;
  400. end;
  401. end;
  402. // Destroy the temporary VAO
  403. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  404. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  405. glDeleteVertexArrays(1, @vertex_array_object);
  406. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  407. {$EndIf}
  408. // Restore modified GL state
  409. // This "glIsProgram()" check is required because if the program is
  410. // "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220.
  411. if (last_program = 0) or (glIsProgram(last_program)) then
  412. glUseProgram(last_program);
  413. glBindTexture(GL_TEXTURE_2D, last_texture);
  414. {$IfDef IMGUI_OPENGL_MAY_HAVE_BIND_SAMPLER}
  415. if (bd^.GlVersion >= 330) or (bd^.GlProfileIsES3) then
  416. glBindSampler(0, last_sampler);
  417. {$EndIf}
  418. glActiveTexture(last_active_texture);
  419. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  420. glBindVertexArray(last_vertex_array_object);
  421. {$EndIf}
  422. glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
  423. {$IfnDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  424. { TODO: implement this - Time : 11/17/2023 5:18:38 AM }
  425. {$EndIf}
  426. glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
  427. glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
  428. if (last_enable_blend)then
  429. glEnable(GL_BLEND)
  430. else
  431. glDisable(GL_BLEND);
  432. if (last_enable_cull_face) then
  433. glEnable(GL_CULL_FACE)
  434. else
  435. glDisable(GL_CULL_FACE);
  436. if (last_enable_depth_test) then
  437. glEnable(GL_DEPTH_TEST)
  438. else
  439. glDisable(GL_DEPTH_TEST);
  440. if (last_enable_stencil_test) then
  441. glEnable(GL_STENCIL_TEST)
  442. else
  443. glDisable(GL_STENCIL_TEST);
  444. if (last_enable_scissor_test) then
  445. glEnable(GL_SCISSOR_TEST)
  446. else
  447. glDisable(GL_SCISSOR_TEST);
  448. {$IfDef IMGUI_OPENGL_MAY_HAVE_PRIMITIVE_RESTART}
  449. if (bd^.GlVersion >= 310) then
  450. if (last_enable_primitive_restart) then
  451. glEnable(GL_PRIMITIVE_RESTART)
  452. else
  453. glDisable(GL_PRIMITIVE_RESTART);
  454. {$EndIf}
  455. {$IfDef IMGUI_HAS_POLYGON_MODE}
  456. // Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons
  457. if (bd^.GlVersion <= 310) or (bd^.GlProfileIsCompat) then
  458. begin
  459. glPolygonMode(GL_FRONT, GLenum(last_polygon_mode[0]));
  460. glPolygonMode(GL_BACK, GLenum(last_polygon_mode[1]));
  461. end
  462. else
  463. glPolygonMode(GL_FRONT_AND_BACK, GLenum(last_polygon_mode[0]));
  464. {$EndIf}
  465. glViewport(last_viewport[0], last_viewport[1], GLsizei(last_viewport[2]), GLsizei(last_viewport[3]));
  466. glScissor(last_scissor_box[0], last_scissor_box[1], GLsizei(last_scissor_box[2]), GLsizei(last_scissor_box[3]));
  467. end;
  468. procedure ImGui_ImplOpenGL3_RenderWindow(viewport: PImGuiViewport; render_arg: Pointer); Cdecl;
  469. var
  470. clear_color : ImVec4;
  471. begin
  472. if not (viewport^.Flags and ImGuiViewportFlags_NoRendererClear <> 0) then
  473. begin
  474. clear_color := ImVec4.New(0.0, 0.0, 0.0, 1.0);
  475. glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
  476. glClear(GL_COLOR_BUFFER_BIT);
  477. end;
  478. ImGui_OpenGL3_RenderDrawData(viewport^.DrawData);
  479. end;
  480. procedure ImGui_ImplOpenGL3_InitPlatformInterface;
  481. var
  482. platform_io: PImGuiPlatformIO;
  483. begin
  484. platform_io := ImGui.GetPlatformIO();
  485. platform_io^.Renderer_RenderWindow := @ImGui_ImplOpenGL3_RenderWindow;
  486. end;
  487. function ImGui_OpenGL3_Init(glsl_version: PAnsiChar): Boolean;
  488. Var
  489. io: PImGuiIO;
  490. bd: PImGui_ImplOpenGL3_Data;
  491. num_extensions: GLint;
  492. major, minor, current_texture : GLint;
  493. gl_version_str, extension: PAnsiChar;
  494. i: Integer;
  495. Const
  496. VersionInfo =
  497. 'GlVersion = %d '#10 + 'GlProfileIsCompat = %d '#10 +
  498. 'GlProfileMask = 0x%X'#10 + 'GlProfileIsES2 = %d, GlProfileIsES3 = %d'#10 +
  499. 'GL_VENDOR = "%s"'#10 + 'GL_RENDERER = "%s"';
  500. Begin
  501. io := ImGui.GetIO();
  502. Assert(io^.BackendRendererUserData = nil, 'Already initialized a renderer backend!');
  503. // Initialize our loader
  504. {$If not Defined(IMGUI_OPENGL_ES2) and not Defined(IMGUI_OPENGL_ES3) and not Defined(IMGUI_OPENGL_LOADER_CUSTOM) }
  505. If Not ImGLInit() Then
  506. Begin
  507. If IsConsole Then
  508. WriteLn('Failed to initialize OpenGL loader!');
  509. Exit(False);
  510. End;
  511. {$EndIf}
  512. // Setup backend capabilities flags
  513. bd := AllocMem(SizeOf(ImGui_ImplOpenGL3_Data));
  514. io^.BackendRendererUserData := bd;
  515. io^.BackendRendererName := 'Pas_imgui_opengl3';
  516. // Query for GL version (e.g. 320 for GL 3.2)
  517. {$IFDEF IMGUI_OPENGL_ES2}
  518. // GLES 2
  519. bd^.GlVersion := 200;
  520. bd^.GlProfileIsES2 := True;
  521. {$ELSE}
  522. // Desktop or GLES 3
  523. major := 0;
  524. minor := 0;
  525. glGetIntegerv(GL_MAJOR_VERSION, @major);
  526. glGetIntegerv(GL_MINOR_VERSION, @minor);
  527. If (major = 0) And (minor = 0) Then
  528. Begin
  529. gl_version_str := PAnsiChar(glGetString(GL_VERSION));
  530. If IsConsole Then
  531. WriteLn(Format('%s %d.%d', [gl_version_str, major, minor]));
  532. End;
  533. bd^.GlVersion := GLuint(major * 100 + minor * 10);
  534. If (bd^.GlVersion >= 320) Then
  535. glGetIntegerv(GL_CONTEXT_PROFILE_MASK, @bd^.GlProfileMask);
  536. bd^.GlProfileIsCompat := (bd^.GlProfileMask And GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) <> 0;
  537. {$IfDef IMGUI_OPENGL_ES3}
  538. bd^.GlProfileIsES3 := true;
  539. {$EndIf}
  540. bd^.UseBufferSubData := False;
  541. {$ENDIF}
  542. {$IfDef IMGUI_LOG}
  543. if IsConsole then
  544. WriteLn(Format(VersionInfo, [bd^.GlVersion, Integer(bd^.GlProfileIsCompat),
  545. bd^.GlProfileMask, Integer(bd^.GlProfileIsES2), Integer(bd^.GlProfileIsES3),
  546. PAnsiChar(glGetString(GL_VENDOR)), PAnsiChar(glGetString(GL_RENDERER))])); // [DEBUG]
  547. {$EndIf}
  548. {$IfDef IMGUI_OPENGL_MAY_HAVE_VTX_OFFSET}
  549. // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
  550. if (bd^.GlVersion >= 320) then
  551. io^.BackendFlags := io^.BackendFlags or ImGuiBackendFlags_RendererHasVtxOffset;
  552. {$EndIf}
  553. // We can create multi-viewports on the Renderer side (optional)
  554. io^.BackendFlags := io^.BackendFlags or ImGuiBackendFlags_RendererHasViewports;
  555. // Store GLSL version string so we can refer to it later in case we recreate shaders.
  556. // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
  557. if glsl_version = nil then
  558. begin
  559. {$IFDEF IMGUI_OPENGL_ES2}
  560. glsl_version := '#version 100';
  561. {$ELSEIF DEFINED(IMGUI_OPENGL_ES3)}
  562. glsl_version := '#version 300 es';
  563. {$ELSEIF DEFINED(DARWIN)}
  564. glsl_version := '#version 150';
  565. {$ELSE}
  566. glsl_version := '#version 130';
  567. {$ENDIF}
  568. end;
  569. Assert(strlen(glsl_version) + 2 < Length(bd^.GlslVersionString), 'Ops');
  570. StrPCopy(bd^.GlslVersionString, glsl_version);
  571. StrCat(bd^.GlslVersionString, #10); // 1 = 1 as in C++ code :P
  572. // Make an arbitrary GL call (we don't actually need the result)
  573. // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
  574. glGetIntegerv(GL_TEXTURE_BINDING_2D, @current_texture);
  575. // Detect extensions we support
  576. bd^.HasClipOrigin := (bd^.GlVersion >= 450);
  577. {$IfDef IMGUI_OPENGL_MAY_HAVE_EXTENSIONS}
  578. bd^.HasClipOrigin := hasExt('GL_ARB_clip_control');
  579. {$EndIf}
  580. If (io^.ConfigFlags And ImGuiConfigFlags_ViewportsEnable) <> 0 Then
  581. Begin
  582. ImGui_ImplOpenGL3_InitPlatformInterface();
  583. End;
  584. Result := True;
  585. End;
  586. function GetGLVersion(GlslVersionString : AnsiString; GLVersion : Integer = 130) : Integer;
  587. var
  588. Code: Integer;
  589. begin
  590. Result := GLVersion;
  591. // Extract the integer following '#version '
  592. if Pos('#version ', GlslVersionString) = 1 then
  593. begin
  594. // Delete the '#version ' part to isolate the number
  595. Delete(GlslVersionString, 1, Length('#version '));
  596. GlslVersionString := Trim(GlslVersionString);
  597. Val(GlslVersionString, Result, Code);
  598. if (Result = 0) or (Code <> 0) then
  599. Result := GLVersion;
  600. end;
  601. end;
  602. // If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
  603. function CheckShader(handle: GLuint; desc: PAnsiChar) : Boolean;
  604. Var
  605. bd: PImGui_ImplOpenGL3_Data;
  606. status, log_length: GLint;
  607. buf : AnsiString;
  608. begin
  609. bd := ImGui_ImplOpenGL3_GetBackendData();
  610. status := 0; log_length := 0;
  611. glGetShaderiv(handle, GL_COMPILE_STATUS, @status);
  612. glGetShaderiv(handle, GL_INFO_LOG_LENGTH, @log_length);
  613. if boolean(status) = boolean(GL_FALSE) then
  614. begin
  615. if IsConsole then
  616. WriteLn(Format('ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s', [desc, bd^.GlslVersionString]));
  617. end;
  618. if (log_length > 1) then
  619. begin
  620. buf := '';
  621. SetLength(buf, log_length);
  622. glGetShaderInfoLog(handle, log_length, nil, @buf[1]);
  623. if IsConsole then
  624. WriteLn(Format('%s', [buf]));
  625. buf := '';
  626. end;
  627. Result := boolean(status) = boolean(GL_TRUE)
  628. end;
  629. // If you get an error please report on GitHub. You may try different GL context version or GLSL version.
  630. function CheckProgram(handle: GLuint; desc: PAnsiChar) : Boolean;
  631. Var
  632. bd: PImGui_ImplOpenGL3_Data;
  633. status, log_length: GLint;
  634. buf : AnsiString;
  635. begin
  636. bd := ImGui_ImplOpenGL3_GetBackendData();
  637. glGetProgramiv(handle, GL_LINK_STATUS, @status);
  638. glGetProgramiv(handle, GL_INFO_LOG_LENGTH, @log_length);
  639. if boolean(status) = boolean(GL_FALSE) then
  640. begin
  641. if IsConsole then
  642. WriteLn(Format('ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s', [desc, bd^.GlslVersionString]));
  643. end;
  644. if (log_length > 1) then
  645. begin
  646. buf := '';
  647. SetLength(buf, log_length);
  648. glGetProgramInfoLog(handle, log_length, nil, @buf[1]);
  649. if IsConsole then
  650. WriteLn(Format('%s', [buf]));
  651. buf := '';
  652. end;
  653. Result := boolean(status) = boolean(GL_TRUE)
  654. end;
  655. function ImGui_ImplOpenGL3_CreateFontsTexture() : Boolean;
  656. Var
  657. bd: PImGui_ImplOpenGL3_Data;
  658. io: PImGuiIO;
  659. pixels : PPByte;
  660. last_texture : GLint;
  661. width, height : Integer;
  662. begin
  663. io := ImGui.GetIO();
  664. bd := ImGui_ImplOpenGL3_GetBackendData();
  665. // Build texture atlas
  666. io^.Fonts^.GetTexDataAsRGBA32(@pixels, @width, @height);
  667. // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small)
  668. // 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.
  669. // Upload texture to graphics system
  670. // (Bilinear sampling is required by default.
  671. // Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
  672. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  673. glGetIntegerv(GL_TEXTURE_BINDING_2D, @last_texture);
  674. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  675. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  676. glGenTextures(1, @bd^.FontTexture);
  677. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  678. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  679. glBindTexture(GL_TEXTURE_2D, bd^.FontTexture);
  680. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  681. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  682. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  683. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  684. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  685. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  686. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  687. // Not on WebGL/ES
  688. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  689. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  690. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  691. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  692. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  693. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF}
  694. // Store our identifier
  695. io.Fonts^.SetTexID(ImTextureID(IntPtr(bd^.FontTexture)));
  696. // Restore state
  697. {$IfDef IMGUI_LOG}GL_CALL(procedure begin {$ENDIF}
  698. glBindTexture(GL_TEXTURE_2D, last_texture);
  699. {$IfDef IMGUI_LOG}end, procedure(msg : string) begin Assert(False, msg); end);{$ENDIF};
  700. Result := True;
  701. end;
  702. function ImGui_ImplOpenGL3_CreateDeviceObjects : Boolean;
  703. Var
  704. bd: PImGui_ImplOpenGL3_Data;
  705. vert_handle, frag_handle : GLuint;
  706. last_texture, last_array_buffer, last_vertex_array : GLint;
  707. glsl_version : Integer;
  708. vertex_shader, fragment_shader : PGLchar;
  709. vertex_shader_with_version: array[0..1] of PAnsiChar;
  710. fragment_shader_with_version : array[0..1] of PAnsiChar;
  711. const
  712. vertex_shader_glsl_120: PGLchar =
  713. 'uniform mat4 ProjMtx;' + #10 +
  714. 'attribute vec2 Position;' + #10 +
  715. 'attribute vec2 UV;' + #10 +
  716. 'attribute vec4 Color;' + #10 +
  717. 'varying vec2 Frag_UV;' + #10 +
  718. 'varying vec4 Frag_Color;' + #10 +
  719. 'void main()' + #10 +
  720. '{' + #10 +
  721. ' Frag_UV = UV;' + #10 +
  722. ' Frag_Color = Color;' + #10 +
  723. ' gl_Position = ProjMtx * vec4(Position.xy,0,1);' + #10 +
  724. '}' + #10;
  725. vertex_shader_glsl_130: PGLchar =
  726. 'uniform mat4 ProjMtx;' + #10 +
  727. 'in vec2 Position;' + #10 +
  728. 'in vec2 UV;' + #10 +
  729. 'in vec4 Color;' + #10 +
  730. 'out vec2 Frag_UV;' + #10 +
  731. 'out vec4 Frag_Color;' + #10 +
  732. 'void main()' + #10 +
  733. '{' + #10 +
  734. ' Frag_UV = UV;' + #10 +
  735. ' Frag_Color = Color;' + #10 +
  736. ' gl_Position = ProjMtx * vec4(Position.xy,0,1);' + #10 +
  737. '}' + #10;
  738. vertex_shader_glsl_300_es: PGLchar =
  739. 'precision highp float;' + #10 +
  740. 'layout (location = 0) in vec2 Position;' + #10 +
  741. 'layout (location = 1) in vec2 UV;' + #10 +
  742. 'layout (location = 2) in vec4 Color;' + #10 +
  743. 'uniform mat4 ProjMtx;' + #10 +
  744. 'out vec2 Frag_UV;' + #10 +
  745. 'out vec4 Frag_Color;' + #10 +
  746. 'void main()' + #10 +
  747. '{' + #10 +
  748. ' Frag_UV = UV;' + #10 +
  749. ' Frag_Color = Color;' + #10 +
  750. ' gl_Position = ProjMtx * vec4(Position.xy,0,1);' + #10 +
  751. '}' + #10;
  752. vertex_shader_glsl_410_core: PGLchar =
  753. 'layout (location = 0) in vec2 Position;' + #10 +
  754. 'layout (location = 1) in vec2 UV;' + #10 +
  755. 'layout (location = 2) in vec4 Color;' + #10 +
  756. 'uniform mat4 ProjMtx;' + #10 +
  757. 'out vec2 Frag_UV;' + #10 +
  758. 'out vec4 Frag_Color;' + #10 +
  759. 'void main()' + #10 +
  760. '{' + #10 +
  761. ' Frag_UV = UV;' + #10 +
  762. ' Frag_Color = Color;' + #10 +
  763. ' gl_Position = ProjMtx * vec4(Position.xy,0,1);' + #10 +
  764. '}' + #10;
  765. fragment_shader_glsl_120: PGLchar =
  766. '#ifdef GL_ES' + #10 +
  767. ' precision mediump float;' + #10 +
  768. '#endif' + #10 +
  769. 'uniform sampler2D Texture;' + #10 +
  770. 'varying vec2 Frag_UV;' + #10 +
  771. 'varying vec4 Frag_Color;' + #10 +
  772. 'void main()' + #10 +
  773. '{' + #10 +
  774. ' gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);' + #10 +
  775. '}' + #10;
  776. fragment_shader_glsl_130: PGLchar =
  777. 'uniform sampler2D Texture;' + #10 +
  778. 'in vec2 Frag_UV;' + #10 +
  779. 'in vec4 Frag_Color;' + #10 +
  780. 'out vec4 Out_Color;' + #10 +
  781. 'void main()' + #10 +
  782. '{' + #10 +
  783. ' Out_Color = Frag_Color * texture(Texture, Frag_UV.st);' + #10 +
  784. '}' + #10;
  785. fragment_shader_glsl_300_es: PGLchar =
  786. 'precision mediump float;' + #10 +
  787. 'uniform sampler2D Texture;' + #10 +
  788. 'in vec2 Frag_UV;' + #10 +
  789. 'in vec4 Frag_Color;' + #10 +
  790. 'layout (location = 0) out vec4 Out_Color;' + #10 +
  791. 'void main()' + #10 +
  792. '{' + #10 +
  793. ' Out_Color = Frag_Color * texture(Texture, Frag_UV.st);' + #10 +
  794. '}' + #10;
  795. fragment_shader_glsl_410_core: PGLchar =
  796. 'in vec2 Frag_UV;' + #10 +
  797. 'in vec4 Frag_Color;' + #10 +
  798. 'uniform sampler2D Texture;' + #10 +
  799. 'layout (location = 0) out vec4 Out_Color;' + #10 +
  800. 'void main()' + #10 +
  801. '{' + #10 +
  802. ' Out_Color = Frag_Color * texture(Texture, Frag_UV.st);' + #10 +
  803. '}' + #10;
  804. Begin
  805. bd := ImGui_ImplOpenGL3_GetBackendData();
  806. // Backup GL state
  807. glGetIntegerv(GL_TEXTURE_BINDING_2D, @last_texture);
  808. glGetIntegerv(GL_ARRAY_BUFFER_BINDING, @last_array_buffer);
  809. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  810. glGetIntegerv(GL_VERTEX_ARRAY_BINDING, @last_vertex_array);
  811. {$EndIf}
  812. // Parse GLSL version string
  813. glsl_version := 130;
  814. glsl_version := GetGLVersion(AnsiString(bd^.GlslVersionString), glsl_version);
  815. // Select shaders matching our GLSL versions
  816. if glsl_version < 130 then
  817. begin
  818. vertex_shader := vertex_shader_glsl_120;
  819. fragment_shader := fragment_shader_glsl_120;
  820. end
  821. else if glsl_version >= 410 then
  822. begin
  823. vertex_shader := vertex_shader_glsl_410_core;
  824. fragment_shader := fragment_shader_glsl_410_core;
  825. end
  826. else if glsl_version = 300 then
  827. begin
  828. vertex_shader := vertex_shader_glsl_300_es;
  829. fragment_shader := fragment_shader_glsl_300_es;
  830. end
  831. else
  832. begin
  833. vertex_shader := vertex_shader_glsl_130;
  834. fragment_shader := fragment_shader_glsl_130;
  835. end;
  836. // Create shaders
  837. vertex_shader_with_version := [@bd^.GlslVersionString[0], vertex_shader];
  838. vert_handle := glCreateShader(GL_VERTEX_SHADER);
  839. glShaderSource(vert_handle, 2, @vertex_shader_with_version, nil);
  840. glCompileShader(vert_handle);
  841. CheckShader(vert_handle, 'vertex shader');
  842. fragment_shader_with_version := [@bd^.GlslVersionString[0], fragment_shader];
  843. frag_handle := glCreateShader(GL_FRAGMENT_SHADER);
  844. glShaderSource(frag_handle, 2, @fragment_shader_with_version, nil);
  845. glCompileShader(frag_handle);
  846. CheckShader(frag_handle, 'fragment shader');
  847. // Link
  848. bd^.ShaderHandle := glCreateProgram();
  849. glAttachShader(bd^.ShaderHandle, vert_handle);
  850. glAttachShader(bd^.ShaderHandle, frag_handle);
  851. glLinkProgram(bd^.ShaderHandle);
  852. CheckProgram(bd^.ShaderHandle, 'shader program');
  853. glDetachShader(bd^.ShaderHandle, vert_handle);
  854. glDetachShader(bd^.ShaderHandle, frag_handle);
  855. glDeleteShader(vert_handle);
  856. glDeleteShader(frag_handle);
  857. bd^.AttribLocationTex := glGetUniformLocation(bd^.ShaderHandle, 'Texture');
  858. bd^.AttribLocationProjMtx := glGetUniformLocation(bd^.ShaderHandle, 'ProjMtx');
  859. bd^.AttribLocationVtxPos := GLuint(glGetAttribLocation(bd^.ShaderHandle, 'Position'));
  860. bd^.AttribLocationVtxUV := GLuint(glGetAttribLocation(bd^.ShaderHandle, 'UV'));
  861. bd^.AttribLocationVtxColor := GLuint(glGetAttribLocation(bd^.ShaderHandle, 'Color'));
  862. // Create buffers
  863. glGenBuffers(1, @bd^.VboHandle);
  864. glGenBuffers(1, @bd^.ElementsHandle);
  865. ImGui_ImplOpenGL3_CreateFontsTexture();
  866. // Restore modified GL state
  867. glBindTexture(GL_TEXTURE_2D, last_texture);
  868. glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
  869. {$IfDef IMGUI_OPENGL_USE_VERTEX_ARRAY}
  870. glBindVertexArray(last_vertex_array);
  871. {$EndIf}
  872. Result := True;
  873. end;
  874. procedure ImGui_OpenGL3_NewFrame;
  875. Var
  876. bd: PImGui_ImplOpenGL3_Data;
  877. Begin
  878. bd := ImGui_ImplOpenGL3_GetBackendData();
  879. Assert(bd <> nil, 'Context or backend not initialized! Did you call ImGui_OpenGL3_Init()?');
  880. if (bd^.ShaderHandle = 0) then
  881. ImGui_ImplOpenGL3_CreateDeviceObjects();
  882. if (bd^.FontTexture = 0)then
  883. ImGui_ImplOpenGL3_CreateFontsTexture();
  884. End;
  885. procedure ImGui_ImplOpenGL3_ShutdownPlatformInterface();
  886. begin
  887. ImGui.DestroyPlatformWindows();
  888. end;
  889. procedure ImGui_ImplOpenGL3_DestroyFontsTexture;
  890. Var
  891. bd: PImGui_ImplOpenGL3_Data;
  892. io: PImGuiIO;
  893. Begin
  894. bd := ImGui_ImplOpenGL3_GetBackendData();
  895. io := imgui.GetIO();
  896. if (bd^.FontTexture > 0) then
  897. begin
  898. glDeleteTextures(1, @bd^.FontTexture);
  899. io^.Fonts^.SetTexID(nil);
  900. bd^.FontTexture := 0;
  901. end;
  902. end;
  903. procedure ImGui_ImplOpenGL3_DestroyDeviceObjects;
  904. Var
  905. bd: PImGui_ImplOpenGL3_Data;
  906. Begin
  907. bd := ImGui_ImplOpenGL3_GetBackendData();
  908. if (bd^.VboHandle > 0) then
  909. begin
  910. glDeleteBuffers(1, @bd^.VboHandle);
  911. bd^.VboHandle := 0;
  912. end;
  913. if (bd^.ElementsHandle > 0) then
  914. begin
  915. glDeleteBuffers(1, @bd^.ElementsHandle);
  916. bd^.ElementsHandle := 0;
  917. end;
  918. if (bd^.ShaderHandle > 0) then
  919. begin
  920. glDeleteProgram(bd^.ShaderHandle);
  921. bd^.ShaderHandle := 0;
  922. end;
  923. ImGui_ImplOpenGL3_DestroyFontsTexture();
  924. end;
  925. procedure ImGui_OpenGL3_Shutdown;
  926. Var
  927. bd: PImGui_ImplOpenGL3_Data;
  928. io: PImGuiIO;
  929. Begin
  930. bd := ImGui_ImplOpenGL3_GetBackendData();
  931. Assert(bd <> nil, 'No renderer backend to shutdown, or already shutdown?');
  932. io := imgui.GetIO();
  933. ImGui_ImplOpenGL3_ShutdownPlatformInterface();
  934. ImGui_ImplOpenGL3_DestroyDeviceObjects();
  935. io^.BackendRendererName := nil;
  936. io^.BackendRendererUserData := nil;
  937. io^.BackendFlags := io^.BackendFlags and not(ImGuiBackendFlags_RendererHasVtxOffset or ImGuiBackendFlags_RendererHasViewports);
  938. // Free Allocated data
  939. Freemem(bd);
  940. End;
  941. {$IfDef IMGUI_LOG}
  942. initialization
  943. AssertErrorProc := @OnAssert;
  944. {$EndIf}
  945. End.