pyglet 2.1.13__py3-none-any.whl → 3.0.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. pyglet/__init__.py +67 -61
  2. pyglet/__init__.pyi +15 -8
  3. pyglet/app/__init__.py +22 -13
  4. pyglet/app/async_app.py +212 -0
  5. pyglet/app/base.py +2 -1
  6. pyglet/app/{xlib.py → linux.py} +3 -3
  7. pyglet/config/__init__.py +101 -0
  8. pyglet/config/gl/__init__.py +30 -0
  9. pyglet/config/gl/egl.py +120 -0
  10. pyglet/config/gl/macos.py +262 -0
  11. pyglet/config/gl/windows.py +267 -0
  12. pyglet/config/gl/x11.py +142 -0
  13. pyglet/customtypes.py +43 -2
  14. pyglet/display/__init__.py +8 -6
  15. pyglet/display/base.py +3 -63
  16. pyglet/display/cocoa.py +12 -17
  17. pyglet/display/emscripten.py +39 -0
  18. pyglet/display/headless.py +23 -30
  19. pyglet/display/wayland.py +157 -0
  20. pyglet/display/win32.py +5 -21
  21. pyglet/display/xlib.py +19 -27
  22. pyglet/display/xlib_vidmoderestore.py +2 -2
  23. pyglet/enums.py +183 -0
  24. pyglet/event.py +0 -1
  25. pyglet/experimental/geoshader_sprite.py +15 -13
  26. pyglet/experimental/hidraw.py +6 -15
  27. pyglet/experimental/multitexture_sprite.py +31 -19
  28. pyglet/experimental/particles.py +13 -35
  29. pyglet/font/__init__.py +251 -85
  30. pyglet/font/base.py +116 -61
  31. pyglet/font/dwrite/__init__.py +349 -204
  32. pyglet/font/dwrite/dwrite_lib.py +27 -5
  33. pyglet/font/fontconfig.py +14 -6
  34. pyglet/font/freetype.py +138 -87
  35. pyglet/font/freetype_lib.py +19 -0
  36. pyglet/font/group.py +179 -0
  37. pyglet/font/harfbuzz/__init__.py +3 -3
  38. pyglet/font/pyodide_js.py +310 -0
  39. pyglet/font/quartz.py +319 -126
  40. pyglet/font/ttf.py +45 -3
  41. pyglet/font/user.py +14 -19
  42. pyglet/font/win32.py +45 -21
  43. pyglet/graphics/__init__.py +8 -787
  44. pyglet/graphics/allocation.py +115 -1
  45. pyglet/graphics/api/__init__.py +77 -0
  46. pyglet/graphics/api/base.py +299 -0
  47. pyglet/graphics/api/gl/__init__.py +58 -0
  48. pyglet/graphics/api/gl/base.py +24 -0
  49. pyglet/graphics/{vertexbuffer.py → api/gl/buffer.py} +104 -159
  50. pyglet/graphics/api/gl/cocoa/context.py +76 -0
  51. pyglet/graphics/api/gl/context.py +391 -0
  52. pyglet/graphics/api/gl/default_shaders.py +0 -0
  53. pyglet/graphics/api/gl/draw.py +627 -0
  54. pyglet/graphics/api/gl/egl/__init__.py +0 -0
  55. pyglet/graphics/api/gl/egl/context.py +92 -0
  56. pyglet/graphics/api/gl/enums.py +76 -0
  57. pyglet/graphics/api/gl/framebuffer.py +315 -0
  58. pyglet/graphics/api/gl/gl.py +5463 -0
  59. pyglet/graphics/api/gl/gl_info.py +188 -0
  60. pyglet/graphics/api/gl/global_opengl.py +226 -0
  61. pyglet/{gl → graphics/api/gl}/lib.py +34 -18
  62. pyglet/graphics/api/gl/shader.py +1476 -0
  63. pyglet/graphics/api/gl/shapes.py +55 -0
  64. pyglet/graphics/api/gl/sprite.py +102 -0
  65. pyglet/graphics/api/gl/state.py +219 -0
  66. pyglet/graphics/api/gl/text.py +190 -0
  67. pyglet/graphics/api/gl/texture.py +1526 -0
  68. pyglet/graphics/{vertexarray.py → api/gl/vertexarray.py} +11 -13
  69. pyglet/graphics/api/gl/vertexdomain.py +751 -0
  70. pyglet/graphics/api/gl/win32/__init__.py +0 -0
  71. pyglet/graphics/api/gl/win32/context.py +108 -0
  72. pyglet/graphics/api/gl/win32/wgl_info.py +24 -0
  73. pyglet/graphics/api/gl/xlib/__init__.py +0 -0
  74. pyglet/graphics/api/gl/xlib/context.py +174 -0
  75. pyglet/{gl → graphics/api/gl/xlib}/glx_info.py +26 -31
  76. pyglet/graphics/api/gl1/__init__.py +0 -0
  77. pyglet/{gl → graphics/api/gl1}/gl_compat.py +3 -2
  78. pyglet/graphics/api/gl2/__init__.py +0 -0
  79. pyglet/graphics/api/gl2/buffer.py +320 -0
  80. pyglet/graphics/api/gl2/draw.py +600 -0
  81. pyglet/graphics/api/gl2/global_opengl.py +122 -0
  82. pyglet/graphics/api/gl2/shader.py +200 -0
  83. pyglet/graphics/api/gl2/shapes.py +51 -0
  84. pyglet/graphics/api/gl2/sprite.py +79 -0
  85. pyglet/graphics/api/gl2/text.py +175 -0
  86. pyglet/graphics/api/gl2/vertexdomain.py +364 -0
  87. pyglet/graphics/api/webgl/__init__.py +233 -0
  88. pyglet/graphics/api/webgl/buffer.py +302 -0
  89. pyglet/graphics/api/webgl/context.py +234 -0
  90. pyglet/graphics/api/webgl/draw.py +590 -0
  91. pyglet/graphics/api/webgl/enums.py +76 -0
  92. pyglet/graphics/api/webgl/framebuffer.py +360 -0
  93. pyglet/graphics/api/webgl/gl.py +1537 -0
  94. pyglet/graphics/api/webgl/gl_info.py +130 -0
  95. pyglet/graphics/api/webgl/shader.py +1346 -0
  96. pyglet/graphics/api/webgl/shapes.py +92 -0
  97. pyglet/graphics/api/webgl/sprite.py +102 -0
  98. pyglet/graphics/api/webgl/state.py +227 -0
  99. pyglet/graphics/api/webgl/text.py +187 -0
  100. pyglet/graphics/api/webgl/texture.py +1227 -0
  101. pyglet/graphics/api/webgl/vertexarray.py +54 -0
  102. pyglet/graphics/api/webgl/vertexdomain.py +616 -0
  103. pyglet/graphics/api/webgl/webgl_js.pyi +307 -0
  104. pyglet/{image → graphics}/atlas.py +33 -32
  105. pyglet/graphics/base.py +10 -0
  106. pyglet/graphics/buffer.py +245 -0
  107. pyglet/graphics/draw.py +578 -0
  108. pyglet/graphics/framebuffer.py +26 -0
  109. pyglet/graphics/instance.py +178 -69
  110. pyglet/graphics/shader.py +267 -1553
  111. pyglet/graphics/state.py +83 -0
  112. pyglet/graphics/texture.py +703 -0
  113. pyglet/graphics/vertexdomain.py +695 -538
  114. pyglet/gui/ninepatch.py +10 -10
  115. pyglet/gui/widgets.py +120 -10
  116. pyglet/image/__init__.py +20 -1973
  117. pyglet/image/animation.py +12 -12
  118. pyglet/image/base.py +730 -0
  119. pyglet/image/codecs/__init__.py +9 -0
  120. pyglet/image/codecs/bmp.py +53 -30
  121. pyglet/image/codecs/dds.py +53 -31
  122. pyglet/image/codecs/gdiplus.py +38 -14
  123. pyglet/image/codecs/gdkpixbuf2.py +0 -2
  124. pyglet/image/codecs/js_image.py +99 -0
  125. pyglet/image/codecs/ktx2.py +161 -0
  126. pyglet/image/codecs/pil.py +1 -1
  127. pyglet/image/codecs/png.py +1 -1
  128. pyglet/image/codecs/wic.py +11 -2
  129. pyglet/info.py +26 -24
  130. pyglet/input/__init__.py +8 -0
  131. pyglet/input/base.py +163 -105
  132. pyglet/input/controller.py +13 -19
  133. pyglet/input/controller_db.py +39 -24
  134. pyglet/input/emscripten/__init__.py +18 -0
  135. pyglet/input/emscripten/gamepad_js.py +397 -0
  136. pyglet/input/linux/__init__.py +11 -5
  137. pyglet/input/linux/evdev.py +10 -11
  138. pyglet/input/linux/x11_xinput.py +2 -2
  139. pyglet/input/linux/x11_xinput_tablet.py +1 -1
  140. pyglet/input/macos/__init__.py +7 -2
  141. pyglet/input/macos/darwin_gc.py +559 -0
  142. pyglet/input/win32/__init__.py +1 -1
  143. pyglet/input/win32/directinput.py +34 -29
  144. pyglet/input/win32/xinput.py +11 -61
  145. pyglet/lib.py +3 -3
  146. pyglet/libs/__init__.py +1 -1
  147. pyglet/{gl → libs/darwin}/agl.py +1 -1
  148. pyglet/libs/darwin/cocoapy/__init__.py +2 -2
  149. pyglet/libs/darwin/cocoapy/cocoahelpers.py +181 -0
  150. pyglet/libs/darwin/cocoapy/cocoalibs.py +31 -0
  151. pyglet/libs/darwin/cocoapy/cocoatypes.py +27 -0
  152. pyglet/libs/darwin/cocoapy/runtime.py +81 -45
  153. pyglet/libs/darwin/coreaudio.py +4 -4
  154. pyglet/{gl → libs/darwin}/lib_agl.py +9 -8
  155. pyglet/libs/darwin/quartzkey.py +1 -3
  156. pyglet/libs/egl/__init__.py +2 -0
  157. pyglet/libs/egl/egl_lib.py +576 -0
  158. pyglet/libs/egl/eglext.py +51 -5
  159. pyglet/libs/linux/__init__.py +0 -0
  160. pyglet/libs/linux/egl/__init__.py +0 -0
  161. pyglet/libs/linux/egl/eglext.py +22 -0
  162. pyglet/libs/linux/glx/__init__.py +0 -0
  163. pyglet/{gl → libs/linux/glx}/glx.py +13 -14
  164. pyglet/{gl → libs/linux/glx}/glxext_arb.py +408 -192
  165. pyglet/{gl → libs/linux/glx}/glxext_mesa.py +1 -1
  166. pyglet/{gl → libs/linux/glx}/glxext_nv.py +345 -164
  167. pyglet/{gl → libs/linux/glx}/lib_glx.py +3 -2
  168. pyglet/libs/linux/wayland/__init__.py +0 -0
  169. pyglet/libs/linux/wayland/client.py +1068 -0
  170. pyglet/libs/linux/wayland/lib_wayland.py +207 -0
  171. pyglet/libs/linux/wayland/wayland_egl.py +38 -0
  172. pyglet/libs/{wayland → linux/wayland}/xkbcommon.py +26 -0
  173. pyglet/libs/{x11 → linux/x11}/xf86vmode.py +4 -4
  174. pyglet/libs/{x11 → linux/x11}/xinerama.py +2 -2
  175. pyglet/libs/{x11 → linux/x11}/xinput.py +10 -10
  176. pyglet/libs/linux/x11/xrandr.py +0 -0
  177. pyglet/libs/{x11 → linux/x11}/xrender.py +1 -1
  178. pyglet/libs/shared/__init__.py +0 -0
  179. pyglet/libs/shared/spirv/__init__.py +0 -0
  180. pyglet/libs/shared/spirv/lib_shaderc.py +85 -0
  181. pyglet/libs/shared/spirv/lib_spirv_cross.py +126 -0
  182. pyglet/libs/win32/__init__.py +28 -8
  183. pyglet/libs/win32/constants.py +59 -48
  184. pyglet/libs/win32/context_managers.py +20 -3
  185. pyglet/libs/win32/dinput.py +105 -88
  186. pyglet/{gl → libs/win32}/lib_wgl.py +52 -26
  187. pyglet/libs/win32/types.py +58 -23
  188. pyglet/{gl → libs/win32}/wgl.py +32 -25
  189. pyglet/{gl → libs/win32}/wglext_arb.py +364 -2
  190. pyglet/media/__init__.py +9 -10
  191. pyglet/media/codecs/__init__.py +12 -1
  192. pyglet/media/codecs/base.py +99 -96
  193. pyglet/media/codecs/ffmpeg.py +2 -2
  194. pyglet/media/codecs/ffmpeg_lib/libavformat.py +3 -8
  195. pyglet/media/codecs/webaudio_pyodide.py +111 -0
  196. pyglet/media/drivers/__init__.py +9 -4
  197. pyglet/media/drivers/base.py +4 -4
  198. pyglet/media/drivers/openal/__init__.py +1 -1
  199. pyglet/media/drivers/openal/adaptation.py +3 -3
  200. pyglet/media/drivers/pulse/__init__.py +1 -1
  201. pyglet/media/drivers/pulse/adaptation.py +3 -3
  202. pyglet/media/drivers/pyodide_js/__init__.py +8 -0
  203. pyglet/media/drivers/pyodide_js/adaptation.py +288 -0
  204. pyglet/media/drivers/xaudio2/adaptation.py +3 -3
  205. pyglet/media/player.py +276 -193
  206. pyglet/media/player_worker_thread.py +1 -1
  207. pyglet/model/__init__.py +39 -29
  208. pyglet/model/codecs/base.py +4 -4
  209. pyglet/model/codecs/gltf.py +3 -3
  210. pyglet/model/codecs/obj.py +71 -43
  211. pyglet/resource.py +129 -78
  212. pyglet/shapes.py +154 -194
  213. pyglet/sprite.py +47 -164
  214. pyglet/text/__init__.py +44 -54
  215. pyglet/text/caret.py +12 -7
  216. pyglet/text/document.py +19 -17
  217. pyglet/text/formats/html.py +2 -2
  218. pyglet/text/formats/structured.py +10 -40
  219. pyglet/text/layout/__init__.py +20 -13
  220. pyglet/text/layout/base.py +176 -287
  221. pyglet/text/layout/incremental.py +9 -10
  222. pyglet/text/layout/scrolling.py +7 -95
  223. pyglet/window/__init__.py +183 -172
  224. pyglet/window/cocoa/__init__.py +62 -51
  225. pyglet/window/cocoa/pyglet_delegate.py +2 -25
  226. pyglet/window/cocoa/pyglet_view.py +9 -8
  227. pyglet/window/dialog/__init__.py +184 -0
  228. pyglet/window/dialog/base.py +99 -0
  229. pyglet/window/dialog/darwin.py +121 -0
  230. pyglet/window/dialog/linux.py +72 -0
  231. pyglet/window/dialog/windows.py +194 -0
  232. pyglet/window/emscripten/__init__.py +779 -0
  233. pyglet/window/headless/__init__.py +44 -28
  234. pyglet/window/key.py +2 -0
  235. pyglet/window/mouse.py +2 -2
  236. pyglet/window/wayland/__init__.py +377 -0
  237. pyglet/window/win32/__init__.py +101 -46
  238. pyglet/window/xlib/__init__.py +104 -66
  239. {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
  240. pyglet-3.0.dev1.dist-info/RECORD +322 -0
  241. {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/WHEEL +1 -1
  242. pyglet/gl/__init__.py +0 -208
  243. pyglet/gl/base.py +0 -499
  244. pyglet/gl/cocoa.py +0 -309
  245. pyglet/gl/gl.py +0 -4625
  246. pyglet/gl/gl.pyi +0 -2320
  247. pyglet/gl/gl_compat.pyi +0 -3097
  248. pyglet/gl/gl_info.py +0 -190
  249. pyglet/gl/headless.py +0 -166
  250. pyglet/gl/wgl_info.py +0 -36
  251. pyglet/gl/wglext_nv.py +0 -1096
  252. pyglet/gl/win32.py +0 -268
  253. pyglet/gl/xlib.py +0 -295
  254. pyglet/image/buffer.py +0 -274
  255. pyglet/image/codecs/s3tc.py +0 -354
  256. pyglet/libs/x11/xrandr.py +0 -166
  257. pyglet-2.1.13.dist-info/RECORD +0 -234
  258. /pyglet/{libs/wayland → graphics/api/gl/cocoa}/__init__.py +0 -0
  259. /pyglet/libs/{egl → linux/egl}/egl.py +0 -0
  260. /pyglet/libs/{egl → linux/egl}/lib.py +0 -0
  261. /pyglet/libs/{ioctl.py → linux/ioctl.py} +0 -0
  262. /pyglet/libs/{wayland → linux/wayland}/gbm.py +0 -0
  263. /pyglet/libs/{x11 → linux/x11}/__init__.py +0 -0
  264. /pyglet/libs/{x11 → linux/x11}/cursorfont.py +0 -0
  265. /pyglet/libs/{x11 → linux/x11}/xlib.py +0 -0
  266. /pyglet/libs/{x11 → linux/x11}/xsync.py +0 -0
  267. {pyglet-2.1.13.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
@@ -0,0 +1,751 @@
1
+ """Manage related vertex attributes within a single vertex domain.
2
+
3
+ A vertex "domain" consists of a set of attribute descriptions that together
4
+ describe the layout of one or more vertex buffers which are used together to
5
+ specify the vertices in a primitive. Additionally, the domain manages the
6
+ buffers used to store the data and will resize them as necessary to accommodate
7
+ new vertices.
8
+
9
+ Domains can optionally be indexed, in which case they also manage a buffer
10
+ containing vertex indices. This buffer is grown separately and has no size
11
+ relation to the attribute buffers.
12
+
13
+ Applications can create vertices (and optionally, indices) within a domain
14
+ with the :py:meth:`VertexDomain.create` method. This returns a
15
+ :py:class:`VertexList` representing the list of vertices created. The vertex
16
+ attribute data within the group can be modified, and the changes will be made
17
+ to the underlying buffers automatically.
18
+
19
+ The entire domain can be efficiently drawn in one step with the
20
+ :py:meth:`VertexDomain.draw` method, assuming all the vertices comprise
21
+ primitives of the same OpenGL primitive mode.
22
+ """
23
+ from __future__ import annotations
24
+
25
+ import ctypes
26
+ from typing import TYPE_CHECKING, Any, Sequence
27
+
28
+
29
+ from pyglet.graphics.api.gl import (
30
+ GL_BYTE,
31
+ GL_DOUBLE,
32
+ GL_FLOAT,
33
+ GL_INT,
34
+ GL_SHORT,
35
+ GL_UNSIGNED_BYTE,
36
+ GL_UNSIGNED_INT,
37
+ GL_UNSIGNED_SHORT,
38
+ GLint,
39
+ GLintptr,
40
+ GLsizei,
41
+ GLvoid,
42
+ vertexarray, OpenGLSurfaceContext,
43
+ )
44
+ from pyglet.graphics.api.gl.buffer import AttributeBufferObject, IndexedBufferObject
45
+ from pyglet.graphics.api.gl.enums import geometry_map
46
+ from pyglet.graphics.api.gl.shader import GLAttribute
47
+ from pyglet.graphics.instance import InstanceBucket, BaseInstanceDomain, VertexInstanceBase
48
+ from pyglet.graphics.vertexdomain import (
49
+ VertexStream,
50
+ VertexArrayBinding,
51
+ VertexArrayProtocol,
52
+ InstanceStream,
53
+ IndexStream,
54
+ _RunningIndexSupport,
55
+ VertexGroupBucket,
56
+ VertexDomainBase,
57
+ IndexedVertexDomainBase,
58
+ VertexListBase,
59
+ IndexedVertexListBase,
60
+ InstancedVertexDomainBase,
61
+ InstancedIndexedVertexDomainBase,
62
+ )
63
+
64
+ if TYPE_CHECKING:
65
+ from ctypes import Array
66
+ from pyglet.graphics.shader import AttributeView
67
+ from pyglet.graphics import GeometryMode, Group
68
+ from pyglet.graphics.shader import Attribute
69
+ from pyglet.customtypes import CType, DataTypes
70
+
71
+ _c_types = {
72
+ GL_BYTE: ctypes.c_byte,
73
+ GL_UNSIGNED_BYTE: ctypes.c_ubyte,
74
+ GL_SHORT: ctypes.c_short,
75
+ GL_UNSIGNED_SHORT: ctypes.c_ushort,
76
+ GL_INT: ctypes.c_int,
77
+ GL_UNSIGNED_INT: ctypes.c_uint,
78
+ GL_FLOAT: ctypes.c_float,
79
+ GL_DOUBLE: ctypes.c_double,
80
+ }
81
+
82
+ _gl_types = {
83
+ 'b': GL_BYTE,
84
+ 'B': GL_UNSIGNED_BYTE,
85
+ 'h': GL_SHORT,
86
+ 'H': GL_UNSIGNED_SHORT,
87
+ 'i': GL_INT,
88
+ 'I': GL_UNSIGNED_INT,
89
+ 'f': GL_FLOAT,
90
+ 'd': GL_DOUBLE,
91
+ }
92
+
93
+
94
+ def _make_attribute_property(name: str) -> property:
95
+ def _attribute_getter(self: VertexList) -> Array[float | int]:
96
+ buffer = self.domain.attrib_name_buffers[name]
97
+ region = buffer.get_region(self.start, self.count)
98
+ buffer.invalidate_region(self.start, self.count)
99
+ return region
100
+
101
+ def _attribute_setter(self: VertexList, data: Any) -> None:
102
+ buffer = self.domain.attrib_name_buffers[name]
103
+ buffer.set_region(self.start, self.count, data)
104
+
105
+ return property(_attribute_getter, _attribute_setter)
106
+
107
+ class _GLVertexStreamMix(VertexStream):
108
+ _ctx: OpenGLSurfaceContext
109
+
110
+ def __init__(self, ctx: OpenGLSurfaceContext, initial_size: int, attrs: Sequence[Attribute], *, divisor: int = 0):
111
+ super().__init__(ctx, initial_size, attrs, divisor=divisor)
112
+
113
+ def get_graphics_attribute(self, attribute: Attribute, view: AttributeView) -> GLAttribute:
114
+ return GLAttribute(attribute, view)
115
+
116
+ def get_buffer(self, size: int, attribute) -> AttributeBufferObject:
117
+ # TODO: use persistent buffer if we have GL support for it:
118
+ # attribute.buffer = PersistentBufferObject(attribute.stride * self.allocator.capacity, attribute, self.vao)
119
+ return AttributeBufferObject(self._ctx, size, attribute)
120
+
121
+ def bind_into(self, vao) -> None:
122
+ for attribute, buffer in zip(self.attribute_names.values(), self.buffers):
123
+ buffer.bind()
124
+ attribute.enable()
125
+ attribute.set_pointer()
126
+ attribute.set_divisor()
127
+
128
+ class GLVertexStream(_GLVertexStreamMix, VertexStream): # noqa: D101
129
+ def __init__(self, ctx: OpenGLSurfaceContext, initial_size: int, attrs: Sequence[Attribute]) -> None:
130
+ """Contains data for vertex stream.
131
+
132
+ Args:
133
+ ctx:
134
+ The core context that owns this stream.
135
+ initial_size:
136
+ Initial buffer size.
137
+ attrs:
138
+ Attributes that will be used.
139
+ """
140
+ super().__init__(ctx, initial_size, attrs)
141
+
142
+ class GLInstanceStream(_GLVertexStreamMix, InstanceStream): # noqa: D101
143
+ _ctx: OpenGLSurfaceContext
144
+
145
+ def __init__(self, ctx: OpenGLSurfaceContext, initial_size: int, attrs: Sequence[Attribute], # noqa: D107
146
+ *, divisor: int = 0) -> None:
147
+ super().__init__(ctx, initial_size, attrs, divisor=divisor)
148
+
149
+ class GLVertexArrayBinding(VertexArrayBinding): # noqa: D101
150
+
151
+ def _create_vao(self) -> VertexArrayProtocol:
152
+ return vertexarray.VertexArray(self._ctx)
153
+
154
+ def _link(self) -> None:
155
+ self.vao.bind()
156
+ for stream in self.streams:
157
+ stream.bind_into(self.vao)
158
+ self.vao.unbind()
159
+
160
+ def bind(self) -> None:
161
+ self.vao.bind()
162
+
163
+ def unbind(self) -> None:
164
+ self.vao.unbind()
165
+
166
+
167
+ class VertexList(VertexListBase):
168
+ """A list of vertices within a :py:class:`VertexDomain`.
169
+
170
+ Use :py:meth:`VertexDomain.create` to construct this list.
171
+ """
172
+ count: int
173
+ start: int
174
+ domain: VertexDomain
175
+ indexed: bool = False
176
+ instanced: bool = False
177
+ initial_attribs: dict
178
+
179
+ bucket: VertexGroupBucket | None
180
+
181
+ def __init__(self, domain: VertexDomain, group: Group, start: int, count: int) -> None: # noqa: D107
182
+ super().__init__(domain, group, start, count)
183
+
184
+
185
+
186
+ class InstanceVertexList(VertexList):
187
+ """A list of vertices within an :py:class:`InstancedVertexDomain` that are not indexed."""
188
+ instanced: bool = True
189
+
190
+ def __init__(self, domain: VertexDomain, group: Group, start: int, count: int, bucket: InstanceBucket) -> None: # noqa: D107
191
+ super().__init__(domain, group, start, count)
192
+ self.instance_bucket = bucket
193
+ self.instance_bucket.create_instance()
194
+
195
+ def create_instance(self, **attributes: Any) -> VertexInstanceBase:
196
+ return self.instance_bucket.create_instance(**attributes)
197
+
198
+ def set_attribute_data(self, name: str, data: Any) -> None:
199
+ if self.initial_attribs[name].fmt.is_instanced:
200
+ stream = self.instance_bucket.stream
201
+ count = 1
202
+ start = 0
203
+ else:
204
+ stream = self.domain.attrib_name_buffers[name]
205
+ count = self.count
206
+ start = self.start
207
+ buffer = stream.attrib_name_buffers[name]
208
+
209
+ array_start = buffer.element_count * start
210
+ array_end = buffer.element_count * count + array_start
211
+ try:
212
+ buffer.data[array_start:array_end] = data
213
+ buffer.invalidate_region(start, count)
214
+ except ValueError:
215
+ msg = f"Invalid data size for '{buffer}'. Expected {array_end - array_start}, got {len(data)}."
216
+ raise ValueError(msg) from None
217
+
218
+
219
+
220
+ class IndexedVertexList(IndexedVertexListBase):
221
+ """A list of vertices within an :py:class:`IndexedVertexDomain` that are indexed.
222
+
223
+ Use :py:meth:`IndexedVertexDomain.create` to construct this list.
224
+ """
225
+ domain: IndexedVertexDomain | InstancedIndexedVertexDomain
226
+ indexed: bool = True
227
+
228
+ index_count: int
229
+ index_start: int
230
+
231
+ def __init__(self, domain: IndexedVertexDomain, group: Group, start: int, count: int, index_start: int, # noqa: D107
232
+ index_count: int) -> None:
233
+ super().__init__(domain, group, start, count, index_start, index_count)
234
+
235
+
236
+ class InstanceIndexedVertexList(VertexList):
237
+ """A list of vertices within an :py:class:`IndexedVertexDomain` that are indexed.
238
+
239
+ Use :py:meth:`IndexedVertexDomain.create` to construct this list.
240
+ """
241
+ domain: IndexedVertexDomain | InstancedIndexedVertexDomain
242
+ indexed: bool = True
243
+ instanced: bool = True
244
+
245
+ index_count: int
246
+ index_start: int
247
+
248
+ instance_bucket: InstanceBucket
249
+
250
+ def __init__(self, domain: IndexedVertexDomain, group: Group, start: int, count: int,
251
+ index_start: int, index_count: int, index_type: DataTypes, base_vertex: int,
252
+ instance_bucket: InstanceBucket) -> None:
253
+ self.index_start = index_start
254
+ self.index_count = index_count
255
+ self.index_type = index_type
256
+ self.base_vertex = base_vertex
257
+ self.instance_bucket = instance_bucket
258
+ self.instance_bucket.create_instance()
259
+ self.start_base_vertex = start if self.supports_base_vertex else 0
260
+ super().__init__(domain, group, start, count)
261
+
262
+ def delete(self) -> None:
263
+ """Delete this group."""
264
+ raise Exception
265
+ super().delete()
266
+ self.domain.index_allocator.dealloc(self.index_start, self.index_count)
267
+
268
+ def migrate(self, domain: InstancedIndexedVertexDomain) -> None:
269
+ old_domain = self.domain
270
+
271
+ # Moved vertex data here.
272
+ super().migrate(domain)
273
+
274
+ # Remove from bucket and enter into new bucket.
275
+ new_bucket = domain.instance_domain.get_elements_bucket(mode=0,
276
+ first_index=self.index_start,
277
+ index_count=self.index_count,
278
+ index_type="I")
279
+
280
+ # Move instance data.
281
+ old_domain.instance_domain.move_all(self.instance_bucket, new_bucket)
282
+
283
+ def create_instance(self, **attributes: Any) -> None:
284
+ return self.instance_bucket.create_instance(**attributes)
285
+
286
+ def set_attribute_data(self, name: str, data: Any) -> None:
287
+ if self.initial_attribs[name].fmt.is_instanced:
288
+ stream = self.instance_bucket.stream
289
+ count = 1
290
+ start = 0
291
+ else:
292
+ stream = self.domain.attrib_name_buffers[name]
293
+ count = self.count
294
+ start = self.start
295
+ buffer = stream.attrib_name_buffers[name]
296
+
297
+ array_start = buffer.element_count * start
298
+ array_end = buffer.element_count * count + array_start
299
+ try:
300
+ buffer.data[array_start:array_end] = data
301
+ buffer.invalidate_region(start, count)
302
+ except ValueError:
303
+ msg = f"Invalid data size for '{buffer}'. Expected {array_end - array_start}, got {len(data)}."
304
+ raise ValueError(msg) from None
305
+
306
+ def dealloc_from_group(self, vertex_list):
307
+ """Removes a vertex list from a specific state in this domain."""
308
+ vertex_list.bucket.remove_vertex_list(vertex_list)
309
+
310
+ class VertexDomain(VertexDomainBase):
311
+ """Management of a set of vertex lists.
312
+
313
+ Construction of a vertex domain is usually done with the
314
+ :py:func:`create_domain` function.
315
+ """
316
+ _vertex_buckets: dict[Group, VertexGroupBucket]
317
+ streams: list[GLVertexStream | GLInstanceStream | GLIndexStream]
318
+ per_instance: list[Attribute]
319
+ per_vertex: list[Attribute]
320
+
321
+ attribute_meta: dict[str, Attribute]
322
+ buffer_attributes: list[tuple[AttributeBufferObject, Attribute]]
323
+ vao: GLVertexArrayBinding
324
+ attribute_names: dict[str, Attribute]
325
+ attrib_name_buffers: dict[str, GLVertexStream]
326
+ _vertexlist_class: type
327
+
328
+ _vertex_class: type[VertexList] = VertexList
329
+
330
+ def __init__(self, context: OpenGLSurfaceContext, initial_count: int, attribute_meta: dict[str, Attribute]) -> None:
331
+ super().__init__(context, initial_count, attribute_meta)
332
+
333
+ def _has_multi_draw_extension(self, ctx: OpenGLSurfaceContext) -> bool:
334
+ return ctx.get_info().have_extension("GL_EXT_multi_draw_arrays")
335
+
336
+ def draw_bucket(self, mode: int, bucket) -> None:
337
+ bucket.draw(self, mode)
338
+
339
+ def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
340
+ regions = []
341
+ for bucket in buckets:
342
+ regions.extend(bucket.merged_ranges)
343
+
344
+ start_list = [region[0] for region in regions]
345
+ size_list = [region[1] for region in regions]
346
+ primcount = len(regions)
347
+ if self._supports_multi_draw:
348
+ starts = (GLint * primcount)(*start_list)
349
+ sizes = (GLsizei * primcount)(*size_list)
350
+ self._context.glMultiDrawArrays(mode, starts, sizes, primcount)
351
+ else:
352
+ for start, size in zip(start_list, size_list):
353
+ self._context.glDrawArrays(mode, start, size)
354
+
355
+
356
+ def _create_vertex_class(self) -> type:
357
+ return type(self._vertex_class.__name__, (self._vertex_class,), self.vertex_buffers._property_dict)
358
+
359
+ def _create_vao(self) -> VertexArrayBinding:
360
+ return GLVertexArrayBinding(self._context, self._streams)
361
+
362
+ def _create_streams(self, size: int) -> list[VertexStream | IndexStream | InstanceStream]:
363
+ self.vertex_buffers = GLVertexStream(self._context, size, self.per_vertex)
364
+ return [self.vertex_buffers]
365
+
366
+ def draw_range(self, mode: int, start: int, count: int) -> None:
367
+ """Draw a range of vertices.
368
+
369
+ Args:
370
+ """
371
+ self._context.glDrawArrays(mode, start, count)
372
+
373
+ def draw(self, mode: int) -> None:
374
+ """Draw all vertices in the domain.
375
+
376
+ All vertices in the domain are drawn at once. This is the
377
+ most efficient way to render primitives.
378
+
379
+ Args:
380
+ mode:
381
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
382
+
383
+ """
384
+ self.vao.bind()
385
+ self.vertex_buffers.commit()
386
+
387
+ starts, sizes = self.vertex_buffers.allocator.get_allocated_regions()
388
+ primcount = len(starts)
389
+ if primcount == 0:
390
+ pass
391
+ elif primcount == 1:
392
+ # Common case
393
+ self._context.glDrawArrays(mode, starts[0], sizes[0])
394
+ else:
395
+ starts = (GLint * primcount)(*starts)
396
+ sizes = (GLsizei * primcount)(*sizes)
397
+ self._context.glMultiDrawArrays(mode, starts, sizes, primcount)
398
+
399
+ def draw_subset(self, mode: GeometryMode, vertex_list: VertexList) -> None:
400
+ """Draw a specific VertexList in the domain.
401
+
402
+ The `vertex_list` parameter specifies a :py:class:`VertexList`
403
+ to draw. Only primitives in that list will be drawn.
404
+
405
+ Args:
406
+ mode:
407
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
408
+ vertex_list:
409
+ Vertex list to draw.
410
+
411
+ """
412
+ self.vao.bind()
413
+ self.vertex_buffers.commit()
414
+ self._context.glDrawArrays(geometry_map[mode], vertex_list.start, vertex_list.count)
415
+
416
+
417
+ class GLInstanceDomainArrays(BaseInstanceDomain):
418
+ def __init__(self, domain: Any, initial_instances: int) -> None:
419
+ super().__init__(domain, initial_instances)
420
+ self._ctx = domain._context
421
+
422
+ def _create_bucket_arrays(self) -> InstanceBucket:
423
+ istream = GLInstanceStream(self._ctx, self._initial, self._domain.per_instance, divisor=1)
424
+ vao = GLVertexArrayBinding(self._ctx, [self._domain.vertex_buffers, istream])
425
+ return InstanceBucket(istream, vao)
426
+
427
+ def _create_bucket_elements(self) -> InstanceBucket:
428
+ raise NotImplementedError("Use GLInstanceDomainElements for indexed draws")
429
+
430
+ def draw(self, mode: int) -> None:
431
+ for key, bucket in self._buckets.items():
432
+ if bucket.instance_count <= 0:
433
+ continue
434
+ first_vertex, vertex_count = self._geom[bucket]
435
+ bucket.vao.bind()
436
+ bucket.stream.commit()
437
+ self._ctx.glDrawArraysInstanced(mode, first_vertex, vertex_count, bucket.instance_count)
438
+
439
+ def draw_subset(self, mode: int, vertex_list: InstanceVertexList):
440
+ """Draw a specific VertexList in the domain."""
441
+ bucket = vertex_list.bucket
442
+ bucket.vao.bind()
443
+ bucket.stream.commit()
444
+ self._ctx.glDrawArraysInstanced(mode, vertex_list.start, vertex_list.count, bucket.instance_count)
445
+
446
+ class GLInstanceDomainElements(BaseInstanceDomain):
447
+ _ctx: OpenGLSurfaceContext
448
+
449
+ def __init__(self, domain: Any, initial_instances: int, index_stream: GLIndexStream) -> None:
450
+ super().__init__(domain, initial_instances)
451
+ self._ctx = domain._context
452
+ self._index_stream = index_stream
453
+ self._index_gl_type = self._index_stream.gl_type
454
+ self._elem_size = index_stream.index_element_size
455
+
456
+ def _create_bucket_elements(self) -> InstanceBucket:
457
+ istream = GLInstanceStream(self._ctx, self._initial, self._domain.per_instance, divisor=1)
458
+ vao = GLVertexArrayBinding(self._ctx, [self._domain.vertex_buffers, istream, self._index_stream])
459
+ return InstanceBucket(istream, vao)
460
+
461
+ def _create_bucket_arrays(self) -> InstanceBucket:
462
+ raise NotImplementedError("Use GLInstanceDomainArrays for non-indexed draws")
463
+
464
+ def draw_subset(self, mode: GeometryMode, vertex_list: InstanceIndexedVertexList) -> None:
465
+ """Draw a specific VertexList in the domain."""
466
+ byte_offset = vertex_list.index_start * self._elem_size
467
+ if vertex_list.start:
468
+ self._ctx.glDrawElementsInstancedBaseVertex(
469
+ mode,
470
+ vertex_list.index_count,
471
+ self._index_gl_type,
472
+ byte_offset,
473
+ vertex_list.bucket.instance_count,
474
+ vertex_list.start,
475
+ )
476
+ else:
477
+ self._ctx.glDrawElementsInstanced(
478
+ mode,
479
+ vertex_list.index_count,
480
+ self._index_gl_type,
481
+ byte_offset,
482
+ vertex_list.bucket.instance_count,
483
+ )
484
+
485
+ def draw_bucket(self, mode: int, bucket: InstanceBucket) -> None:
486
+ if bucket.instance_count <= 0:
487
+ return
488
+ first_index, index_count, _, base_vertex = self._geom[bucket]
489
+ byte_offset = first_index * self._elem_size
490
+ bucket.vao.bind()
491
+ bucket.stream.commit()
492
+ if base_vertex:
493
+ self._ctx.glDrawElementsInstancedBaseVertex(
494
+ mode, index_count, self._index_gl_type, byte_offset,
495
+ bucket.instance_count, base_vertex,
496
+ )
497
+ else:
498
+ self._ctx.glDrawElementsInstanced(
499
+ mode, index_count, self._index_gl_type, byte_offset,
500
+ bucket.instance_count,
501
+ )
502
+
503
+ def draw(self, mode: int) -> None:
504
+ for key, bucket in self._buckets.items():
505
+ if bucket.instance_count <= 0:
506
+ continue
507
+ first_index, index_count, _, base_vertex = self._geom[bucket]
508
+ byte_offset = first_index * self._elem_size
509
+ bucket.vao.bind()
510
+ bucket.stream.commit()
511
+ if base_vertex:
512
+ self._ctx.glDrawElementsInstancedBaseVertex(
513
+ mode, index_count, self._index_gl_type, byte_offset,
514
+ bucket.instance_count, base_vertex,
515
+ )
516
+ else:
517
+ self._ctx.glDrawElementsInstanced(
518
+ mode, index_count, self._index_gl_type, byte_offset,
519
+ bucket.instance_count,
520
+ )
521
+
522
+ class InstancedVertexDomain(InstancedVertexDomainBase, VertexDomain): # noqa: D101
523
+ _instances: int
524
+ _instance_properties: dict[str, property]
525
+ _vertexinstance_class: type
526
+ _vertex_class = InstanceVertexList
527
+
528
+ def __init__(self, context: OpenGLSurfaceContext, initial_count: int, # noqa: D107
529
+ attribute_meta: dict[str, Attribute]) -> None:
530
+ super().__init__(context, initial_count, attribute_meta)
531
+
532
+ def create_instance_domain(self, size: int) -> GLInstanceDomainArrays:
533
+ return GLInstanceDomainArrays(self, size)
534
+
535
+ def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
536
+ """Draw a specific VertexGroupBucket in the domain."""
537
+ self.instance_domain.draw(mode)
538
+
539
+ def draw(self, mode: int) -> None:
540
+ """Draw all vertices in the domain.
541
+
542
+ All vertices in the domain are drawn at once. This is the
543
+ most efficient way to render primitives.
544
+
545
+ Args:
546
+ mode:
547
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
548
+
549
+ """
550
+ self.vertex_buffers.commit()
551
+ self.instance_domain.draw(mode)
552
+
553
+ def draw_subset(self, mode: GeometryMode, vertex_list: InstanceVertexList) -> None:
554
+ """Draw a specific VertexList in the domain.
555
+
556
+ The `vertex_list` parameter specifies a :py:class:`VertexList`
557
+ to draw. Only primitives in that list will be drawn.
558
+
559
+ Args:
560
+ mode:
561
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
562
+ vertex_list:
563
+ Vertex list to draw.
564
+ """
565
+ self.vertex_buffers.commit()
566
+ self.instance_domain.draw_subset(geometry_map[mode], vertex_list)
567
+
568
+ class GLIndexStream(IndexStream): # noqa: D101
569
+ index_element_size: int
570
+ index_c_type: CType
571
+ gl_type: int
572
+
573
+ def __init__(self, ctx: OpenGLSurfaceContext, data_type: DataTypes, initial_elems: int) -> None: # noqa: D107
574
+ self.gl_type = _gl_types[data_type]
575
+ self.index_c_type = _c_types[self.gl_type]
576
+ self.index_element_size = ctypes.sizeof(self.index_c_type)
577
+ super().__init__(ctx, data_type, initial_elems)
578
+
579
+ def _create_buffer(self) -> IndexedBufferObject:
580
+ return IndexedBufferObject(
581
+ self.ctx, self.allocator.capacity * self.index_element_size, self.index_c_type, self.index_element_size, 1,
582
+ )
583
+
584
+ def bind_into(self, vao: VertexArrayBinding) -> None:
585
+ self.buffer.bind_to_index_buffer()
586
+
587
+ class IndexedVertexDomain(IndexedVertexDomainBase):
588
+ """Management of a set of indexed vertex lists.
589
+
590
+ Construction of an indexed vertex domain is usually done with the
591
+ :py:func:`create_domain` function.
592
+ """
593
+ vertex_buffers: GLVertexStream
594
+ index_stream: GLIndexStream
595
+ _vertex_class = IndexedVertexList
596
+ _supports_base_vertex: bool
597
+
598
+ def __init__(self, context: OpenGLSurfaceContext, initial_count: int, attribute_meta: dict[str, Attribute], # noqa: D107
599
+ index_type: DataTypes = "I") -> None:
600
+ self.index_type = index_type
601
+ #self._supports_base_vertex = False
602
+ self._supports_base_vertex = context.get_info().have_extension("GL_ARB_draw_elements_base_vertex")
603
+ super().__init__(context, initial_count, attribute_meta)
604
+
605
+ def _has_multi_draw_extension(self, ctx: OpenGLSurfaceContext) -> bool:
606
+ return ctx.get_info().have_extension("GL_EXT_multi_draw_arrays")
607
+
608
+ def _create_vertex_class(self) -> type:
609
+ # Make a custom VertexList class w/ properties for each attribute in the ShaderProgram:
610
+ return type(self._vertex_class.__name__, (_RunningIndexSupport, self._vertex_class),
611
+ self.vertex_buffers._property_dict) # noqa: SLF001
612
+
613
+ def _create_streams(self, size: int) -> list[VertexStream | IndexStream | InstanceStream]:
614
+ self.vertex_buffers = GLVertexStream(self._context, size, self.per_vertex)
615
+ self.index_stream = GLIndexStream(self._context, self.index_type, size)
616
+ return [self.vertex_buffers, self.index_stream]
617
+
618
+ def _create_vao(self) -> VertexArrayBinding:
619
+ return GLVertexArrayBinding(self._context, self._streams)
620
+
621
+ def draw_range(self, mode: int, start: int, count: int) -> None:
622
+ """Draw a range of vertices."""
623
+ self._context.glDrawElements(
624
+ mode, count, self.index_stream.gl_type, start * self.index_stream.index_element_size,
625
+ )
626
+
627
+ def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
628
+ regions = []
629
+ for bucket in buckets:
630
+ regions.extend(bucket.merged_ranges)
631
+
632
+ start_list = [region[0] for region in regions]
633
+ size_list = [region[1] for region in regions]
634
+ primcount = len(regions)
635
+
636
+ if self._supports_multi_draw:
637
+ starts = [s * self.index_stream.index_element_size for s in start_list]
638
+ starts = (ctypes.POINTER(GLvoid) * primcount)(*(GLintptr * primcount)(*starts))
639
+ sizes = (GLsizei * primcount)(*size_list)
640
+ self._context.glMultiDrawElements(mode, sizes, self.index_stream.gl_type, starts, primcount)
641
+ else:
642
+ for start, size in zip(start_list, size_list):
643
+ self._context.glDrawElements(mode, size, self.index_stream.gl_type,
644
+ start * self.index_stream.index_element_size)
645
+
646
+ def draw(self, mode: int) -> None:
647
+ """Draw all vertices in the domain.
648
+
649
+ All vertices in the domain are drawn at once. This is the most efficient way to render primitives.
650
+
651
+ Args:
652
+ mode:
653
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
654
+
655
+ """
656
+ self.vao.bind()
657
+ self.vertex_buffers.commit()
658
+ self.index_stream.buffer.commit()
659
+
660
+ starts, sizes = self.index_stream.allocator.get_allocated_regions()
661
+ primcount = len(starts)
662
+ if primcount == 0:
663
+ pass
664
+ elif primcount == 1:
665
+ # Common case
666
+ self._context.glDrawElements(mode, sizes[0], self.index_stream.gl_type,
667
+ starts[0] * self.index_stream.index_element_size)
668
+ else:
669
+ starts = [s * self.index_stream.index_element_size for s in starts]
670
+ starts = (ctypes.POINTER(GLvoid) * primcount)(*(GLintptr * primcount)(*starts))
671
+ sizes = (GLsizei * primcount)(*sizes)
672
+ self._context.glMultiDrawElements(mode, sizes, self.index_stream.gl_type, starts, primcount)
673
+
674
+ def draw_subset(self, mode: GeometryMode, vertex_list: IndexedVertexList) -> None:
675
+ """Draw a specific IndexedVertexList in the domain.
676
+
677
+ The `vertex_list` parameter specifies a :py:class:`IndexedVertexList`
678
+ to draw. Only primitives in that list will be drawn.
679
+
680
+ Args:
681
+ mode:
682
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
683
+ vertex_list:
684
+ Vertex list to draw.
685
+ """
686
+ self.vao.bind()
687
+ self.vertex_buffers.commit()
688
+ self.index_stream.buffer.commit()
689
+
690
+ self._context.glDrawElements(
691
+ geometry_map[mode],
692
+ vertex_list.index_count,
693
+ self.index_stream.gl_type,
694
+ vertex_list.index_start * self.index_stream.index_element_size,
695
+ )
696
+
697
+
698
+ class InstancedIndexedVertexDomain(InstancedIndexedVertexDomainBase, IndexedVertexDomain):
699
+ """Management of a set of indexed vertex lists.
700
+
701
+ Construction of an indexed vertex domain is usually done with the
702
+ :py:func:`create_domain` function.
703
+ """
704
+ _initial_index_count: int = 16
705
+ _vertex_class = InstanceIndexedVertexList
706
+
707
+ def __init__(self, context: OpenGLSurfaceContext, initial_count: int, attribute_meta: dict[str, dict[str, Any]],
708
+ index_type: DataTypes = "I") -> None:
709
+ super().__init__(context, initial_count, attribute_meta, index_type)
710
+ self._instance_map = {}
711
+
712
+ def create_instance_domain(self, size: int) -> GLInstanceDomainElements:
713
+ return GLInstanceDomainElements(self, size, index_stream=self.index_stream)
714
+
715
+ def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
716
+ """Draw a specific VertexGroupBucket in the domain."""
717
+ for bucket in buckets:
718
+ for vl_range in bucket.ranges:
719
+ self.instance_domain.draw_bucket(mode, self._instance_map[vl_range])
720
+
721
+ def draw(self, mode: int) -> None:
722
+ """Draw all vertices in the domain.
723
+
724
+ All vertices in the domain are drawn at once. This is the
725
+ most efficient way to render primitives.
726
+
727
+ Args:
728
+ mode:
729
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
730
+
731
+ """
732
+ self.vertex_buffers.commit()
733
+ self.index_stream.commit()
734
+ self.instance_domain.draw(mode)
735
+
736
+ def draw_subset(self, mode: GeometryMode, vertex_list: InstanceIndexedVertexList) -> None:
737
+ """Draw a specific IndexedVertexList in the domain.
738
+
739
+ The ``vertex_list`` parameter specifies a :py:class:`IndexedVertexList`
740
+ to draw. Only primitives in that list will be drawn.
741
+
742
+ Args:
743
+ mode:
744
+ OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
745
+ vertex_list:
746
+ Vertex list to draw.
747
+
748
+ """
749
+ self.vertex_buffers.commit()
750
+ self.index_stream.commit()
751
+ self.instance_domain.draw_subset(geometry_map[mode], vertex_list)