opengl_backend_programmable.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import
  3. import OpenGL.GL as gl # pip install PyOpenGL
  4. from imgui_bundle import imgui
  5. import ctypes
  6. from .opengl_base_backend import BaseOpenGLRenderer, get_common_gl_state, restore_common_gl_state
  7. class ProgrammablePipelineRenderer(BaseOpenGLRenderer):
  8. """Basic OpenGL integration base class."""
  9. VERTEX_SHADER_SRC = """
  10. #version 330
  11. uniform mat4 ProjMtx;
  12. in vec2 Position;
  13. in vec2 UV;
  14. in vec4 Color;
  15. out vec2 Frag_UV;
  16. out vec4 Frag_Color;
  17. void main() {
  18. Frag_UV = UV;
  19. Frag_Color = Color;
  20. gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
  21. }
  22. """
  23. FRAGMENT_SHADER_SRC = """
  24. #version 330
  25. uniform sampler2D Texture;
  26. in vec2 Frag_UV;
  27. in vec4 Frag_Color;
  28. out vec4 Out_Color;
  29. void main() {
  30. Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
  31. }
  32. """
  33. def __init__(self):
  34. self._shader_handle = None
  35. self._vert_handle = None
  36. self._fragment_handle = None
  37. self._attrib_location_tex = None
  38. self._attrib_proj_mtx = None
  39. self._attrib_location_position = None
  40. self._attrib_location_uv = None
  41. self._attrib_location_color = None
  42. self._vbo_handle = None
  43. self._elements_handle = None
  44. self._vao_handle = None
  45. super(ProgrammablePipelineRenderer, self).__init__()
  46. def _create_device_objects(self):
  47. # save state
  48. last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)
  49. last_array_buffer = gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING)
  50. last_vertex_array = gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING)
  51. self._shader_handle = gl.glCreateProgram()
  52. # note: no need to store shader parts handles after linking
  53. vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
  54. fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
  55. gl.glShaderSource(vertex_shader, self.VERTEX_SHADER_SRC)
  56. gl.glShaderSource(fragment_shader, self.FRAGMENT_SHADER_SRC)
  57. gl.glCompileShader(vertex_shader)
  58. gl.glCompileShader(fragment_shader)
  59. gl.glAttachShader(self._shader_handle, vertex_shader)
  60. gl.glAttachShader(self._shader_handle, fragment_shader)
  61. gl.glLinkProgram(self._shader_handle)
  62. # note: after linking shaders can be removed
  63. gl.glDeleteShader(vertex_shader)
  64. gl.glDeleteShader(fragment_shader)
  65. self._attrib_location_tex = gl.glGetUniformLocation(
  66. self._shader_handle, "Texture"
  67. )
  68. self._attrib_proj_mtx = gl.glGetUniformLocation(self._shader_handle, "ProjMtx")
  69. self._attrib_location_position = gl.glGetAttribLocation(
  70. self._shader_handle, "Position"
  71. )
  72. self._attrib_location_uv = gl.glGetAttribLocation(self._shader_handle, "UV")
  73. self._attrib_location_color = gl.glGetAttribLocation(
  74. self._shader_handle, "Color"
  75. )
  76. self._vbo_handle = gl.glGenBuffers(1)
  77. self._elements_handle = gl.glGenBuffers(1)
  78. self._vao_handle = gl.glGenVertexArrays(1)
  79. gl.glBindVertexArray(self._vao_handle)
  80. gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle)
  81. gl.glEnableVertexAttribArray(self._attrib_location_position)
  82. gl.glEnableVertexAttribArray(self._attrib_location_uv)
  83. gl.glEnableVertexAttribArray(self._attrib_location_color)
  84. gl.glVertexAttribPointer(
  85. self._attrib_location_position,
  86. 2,
  87. gl.GL_FLOAT,
  88. gl.GL_FALSE,
  89. imgui.VERTEX_SIZE,
  90. ctypes.c_void_p(imgui.VERTEX_BUFFER_POS_OFFSET),
  91. )
  92. gl.glVertexAttribPointer(
  93. self._attrib_location_uv,
  94. 2,
  95. gl.GL_FLOAT,
  96. gl.GL_FALSE,
  97. imgui.VERTEX_SIZE,
  98. ctypes.c_void_p(imgui.VERTEX_BUFFER_UV_OFFSET),
  99. )
  100. gl.glVertexAttribPointer(
  101. self._attrib_location_color,
  102. 4,
  103. gl.GL_UNSIGNED_BYTE,
  104. gl.GL_TRUE,
  105. imgui.VERTEX_SIZE,
  106. ctypes.c_void_p(imgui.VERTEX_BUFFER_COL_OFFSET),
  107. )
  108. # restore state
  109. gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)
  110. gl.glBindBuffer(gl.GL_ARRAY_BUFFER, last_array_buffer)
  111. gl.glBindVertexArray(last_vertex_array)
  112. def render(self, draw_data: imgui.ImDrawData) -> None:
  113. # perf: local for faster access
  114. io = self.io
  115. display_width, display_height = io.display_size
  116. fb_width = int(display_width * io.display_framebuffer_scale[0])
  117. fb_height = int(display_height * io.display_framebuffer_scale[1])
  118. # Honor RendererHasTextures
  119. self._update_textures()
  120. if fb_width == 0 or fb_height == 0:
  121. return
  122. draw_data.scale_clip_rects(io.display_framebuffer_scale)
  123. # backup GL state
  124. # todo: provide cleaner version of this backup-restore code
  125. common_gl_state_tuple = get_common_gl_state()
  126. last_program = gl.glGetIntegerv(gl.GL_CURRENT_PROGRAM)
  127. last_active_texture = gl.glGetIntegerv(gl.GL_ACTIVE_TEXTURE)
  128. last_array_buffer = gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING)
  129. last_element_array_buffer = gl.glGetIntegerv(gl.GL_ELEMENT_ARRAY_BUFFER_BINDING)
  130. last_vertex_array = gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING)
  131. gl.glEnable(gl.GL_BLEND)
  132. gl.glBlendEquation(gl.GL_FUNC_ADD)
  133. gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
  134. gl.glDisable(gl.GL_CULL_FACE)
  135. gl.glDisable(gl.GL_DEPTH_TEST)
  136. gl.glEnable(gl.GL_SCISSOR_TEST)
  137. gl.glActiveTexture(gl.GL_TEXTURE0)
  138. gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
  139. gl.glViewport(0, 0, int(fb_width), int(fb_height))
  140. ortho_projection = (ctypes.c_float * 16)( # noqa
  141. 2.0 / display_width,
  142. 0.0,
  143. 0.0,
  144. 0.0,
  145. 0.0,
  146. 2.0 / -display_height,
  147. 0.0,
  148. 0.0,
  149. 0.0,
  150. 0.0,
  151. -1.0,
  152. 0.0,
  153. -1.0,
  154. 1.0,
  155. 0.0,
  156. 1.0,
  157. )
  158. gl.glUseProgram(self._shader_handle)
  159. gl.glUniform1i(self._attrib_location_tex, 0)
  160. gl.glUniformMatrix4fv(self._attrib_proj_mtx, 1, gl.GL_FALSE, ortho_projection)
  161. gl.glBindVertexArray(self._vao_handle)
  162. for commands in draw_data.cmd_lists:
  163. gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle)
  164. # todo: check this (sizes)
  165. gl.glBufferData(
  166. gl.GL_ARRAY_BUFFER,
  167. commands.vtx_buffer.size() * imgui.VERTEX_SIZE,
  168. ctypes.c_void_p(commands.vtx_buffer.data_address()),
  169. gl.GL_STREAM_DRAW,
  170. )
  171. gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._elements_handle)
  172. # todo: check this (sizes)
  173. gl.glBufferData(
  174. gl.GL_ELEMENT_ARRAY_BUFFER,
  175. commands.idx_buffer.size() * imgui.INDEX_SIZE,
  176. ctypes.c_void_p(commands.idx_buffer.data_address()),
  177. gl.GL_STREAM_DRAW,
  178. )
  179. # todo: allow to iterate over _CmdList
  180. for command in commands.cmd_buffer:
  181. gl.glBindTexture(gl.GL_TEXTURE_2D, command.tex_ref.get_tex_id())
  182. # todo: use named tuple
  183. x, y, z, w = command.clip_rect
  184. gl.glScissor(int(x), int(fb_height - w), int(z - x), int(w - y))
  185. if imgui.INDEX_SIZE == 2:
  186. gltype = gl.GL_UNSIGNED_SHORT
  187. else:
  188. gltype = gl.GL_UNSIGNED_INT
  189. gl.glDrawElements(
  190. gl.GL_TRIANGLES,
  191. command.elem_count,
  192. gltype,
  193. ctypes.c_void_p(command.idx_offset * imgui.INDEX_SIZE),
  194. )
  195. # restore modified GL state
  196. restore_common_gl_state(common_gl_state_tuple)
  197. gl.glUseProgram(last_program)
  198. gl.glActiveTexture(last_active_texture)
  199. gl.glBindVertexArray(last_vertex_array)
  200. gl.glBindBuffer(gl.GL_ARRAY_BUFFER, last_array_buffer)
  201. gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer)
  202. def _invalidate_device_objects(self):
  203. if self._vao_handle > -1:
  204. gl.glDeleteVertexArrays(1, [self._vao_handle])
  205. if self._vbo_handle > -1:
  206. gl.glDeleteBuffers(1, [self._vbo_handle])
  207. if self._elements_handle > -1:
  208. gl.glDeleteBuffers(1, [self._elements_handle])
  209. self._vao_handle = self._vbo_handle = self._elements_handle = 0
  210. gl.glDeleteProgram(self._shader_handle)
  211. self._shader_handle = 0