PasImGui.Renderer.OpenGL3.pas 40 KB

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