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
@@ -37,6 +37,7 @@ responsibility to maintain the allocated regions.
37
37
  from __future__ import annotations
38
38
 
39
39
 
40
+
40
41
  class AllocatorMemoryException(Exception): # noqa: N818
41
42
  """The buffer is not large enough to fulfil an allocation.
42
43
 
@@ -56,7 +57,7 @@ class Allocator:
56
57
  sizes: list[int]
57
58
  starts: list[int]
58
59
 
59
- __slots__ = 'capacity', 'starts', 'sizes'
60
+ __slots__ = 'capacity', 'sizes', 'starts'
60
61
 
61
62
  def __init__(self, capacity: int) -> None:
62
63
  """Create an allocator for a buffer of the specified maximum capacity size."""
@@ -343,3 +344,116 @@ class Allocator:
343
344
 
344
345
  def __repr__(self) -> str:
345
346
  return f'<{self.__class__.__name__} {self!s}>'
347
+
348
+
349
+ class RangeAllocator:
350
+ """Tracks and merges (start, count) buffer subranges for drawing.
351
+
352
+ Used by rendering buckets to collect multiple
353
+ vertex list ranges that belong to the same group/state, and merge
354
+ contiguous ones into larger draw calls.
355
+
356
+ .. note:: This preserves insertion order when re-allocating, but sorts by
357
+ range start when rebuilding, so that the final merged ranges are contiguous for better batched drawing.
358
+
359
+ Example:
360
+ >>> allocator = RangeAllocator()
361
+ >>> allocator.add(0, 4)
362
+ >>> allocator.add(4, 4)
363
+ >>> allocator.add(8, 4)
364
+ >>> allocator.merged_ranges
365
+ [(0, 12)]
366
+ >>> allocator.remove(4, 4)
367
+ >>> allocator.merged_ranges
368
+ [(0, 4), (8, 4)]
369
+ >>> allocator.add(4, 4)
370
+ >>> allocator.merged_ranges
371
+ [(0, 12)]
372
+ """
373
+
374
+ _ranges: list[tuple[int, int]]
375
+ _merged: list[tuple[int, int]]
376
+ is_dirty: bool
377
+
378
+ __slots__ = ("_merged", "_ranges", "is_dirty")
379
+
380
+ def __init__(self) -> None:
381
+ """Initialize an empty range collector."""
382
+ self._ranges = []
383
+ self._merged = []
384
+ self.is_dirty = False
385
+
386
+ def add(self, start: int, count: int) -> None:
387
+ """Add a new range to be tracked.
388
+
389
+ Args:
390
+ start:
391
+ Starting index of the buffer range.
392
+ count:
393
+ Number of elements in the range.
394
+ """
395
+ self._ranges.append((start, count))
396
+ self.is_dirty = True
397
+
398
+ def remove(self, start: int, count: int) -> None:
399
+ """Remove a specific tracked range if it exists.
400
+
401
+ Args:
402
+ start:
403
+ Starting index of the buffer range.
404
+ count:
405
+ Number of elements in the range.
406
+ """
407
+ try:
408
+ self._ranges.remove((start, count))
409
+ self.is_dirty = True
410
+ except ValueError:
411
+ pass # Silently ignore if not found
412
+
413
+ def clear(self) -> None:
414
+ self._ranges.clear()
415
+ self._merged.clear()
416
+ self.is_dirty = False
417
+
418
+ def _rebuild(self) -> None:
419
+ """Rebuild merged contiguous ranges."""
420
+ if not self.is_dirty:
421
+ return
422
+
423
+ merged: list[tuple[int, int]] = []
424
+ for start, count in sorted(self._ranges, key=lambda r: r[0]):
425
+ if merged and start == merged[-1][0] + merged[-1][1]:
426
+ s0, c0 = merged[-1] # Extend previous block
427
+ merged[-1] = (s0, c0 + count)
428
+ else:
429
+ merged.append((start, count))
430
+ self._merged = merged
431
+ self.is_dirty = False
432
+
433
+ @property
434
+ def ranges(self) -> list[tuple[int, int]]:
435
+ """Return a list of all un-merged ranges tracked by this allocator."""
436
+ return self._ranges
437
+
438
+ @property
439
+ def merged_ranges(self) -> list[tuple[int, int]]:
440
+ """Return contiguous ranges.
441
+
442
+ Returns:
443
+ A list of ``(start, count)`` of draw ranges.
444
+ """
445
+ self._rebuild()
446
+ return self._merged
447
+
448
+ @property
449
+ def is_empty(self) -> bool:
450
+ return len(self._ranges) == 0
451
+
452
+ def __len__(self) -> int:
453
+ """Return the number of tracked (unmerged) ranges."""
454
+ return len(self._ranges)
455
+
456
+ def __iter__(self):
457
+ """Iterate over the current merged contiguous ranges."""
458
+ self._rebuild()
459
+ return iter(self._merged)
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Sequence
4
+
5
+ import pyglet
6
+ from pyglet.graphics.api.base import ResourceManagement
7
+
8
+ if TYPE_CHECKING:
9
+ from pyglet.graphics.api.base import GraphicsConfig
10
+ from pyglet.graphics.shader import ShaderType
11
+
12
+ core = None
13
+
14
+ resource_manager = ResourceManagement()
15
+
16
+
17
+ # Enforce WebGL if emscripten is detected.
18
+ # Create better fallback/choosing system later.
19
+ if pyglet.compat_platform == "emscripten":
20
+ pyglet.options.backend = "webgl"
21
+
22
+ if pyglet.options.backend in ("opengl", "gles3"):
23
+ from pyglet.graphics.api.gl.global_opengl import OpenGLBackend
24
+
25
+ core = OpenGLBackend("gles" if pyglet.options.backend == "gles3" else "gl")
26
+
27
+ from pyglet.graphics.api.gl.draw import Batch
28
+ from pyglet.graphics.api.gl.draw import get_default_shader, get_default_batch
29
+ from pyglet.graphics.api.gl.shader import ShaderProgram, Shader, ComputeShaderProgram
30
+
31
+ elif pyglet.options.backend in ("gl2", "gles2"):
32
+ from pyglet.graphics.api.gl2.global_opengl import OpenGL2Backend
33
+
34
+ core = OpenGL2Backend("gles" if pyglet.options.backend == "gles2" else "gl")
35
+
36
+ from pyglet.graphics.api.gl2.draw import Batch
37
+ from pyglet.graphics.api.gl2.draw import get_default_shader, get_default_batch
38
+ from pyglet.graphics.api.gl2.shader import ShaderProgram, Shader, ComputeShaderProgram
39
+
40
+ elif pyglet.options.backend == "webgl":
41
+ from pyglet.graphics.api.webgl import WebGLBackend
42
+
43
+ core = WebGLBackend()
44
+
45
+ from pyglet.graphics.api.webgl.draw import Batch
46
+ from pyglet.graphics.api.webgl.draw import get_default_shader, get_default_batch
47
+ from pyglet.graphics.api.webgl.shader import ShaderProgram, Shader, ComputeShaderProgram
48
+
49
+ elif pyglet.options.backend == "vulkan":
50
+ from pyglet.graphics.api.vulkan.instance import VulkanGlobal
51
+ core = VulkanGlobal()
52
+
53
+ from pyglet.graphics.api.vulkan.draw import Batch
54
+ from pyglet.graphics.api.vulkan.draw import get_default_shader, get_default_batch
55
+ from pyglet.graphics.api.vulkan.shader import ShaderProgram, Shader
56
+ else:
57
+ raise Exception("Backend not set. Cannot utilize a graphics API.")
58
+
59
+
60
+ def get_config(**kwargs: float | str | None) -> GraphicsConfig:
61
+ return core.get_config(**kwargs)
62
+
63
+
64
+ def get_default_configs() -> Sequence[GraphicsConfig]:
65
+ return core.get_default_configs()
66
+
67
+
68
+ def have_version(*args: float) -> bool:
69
+ return core.have_version(*args)
70
+
71
+
72
+ def have_extension(extension_name: str) -> bool:
73
+ return core.have_extension(extension_name)
74
+
75
+
76
+ def get_cached_shader(name: str, *sources: tuple[str, ShaderType]) -> ShaderProgram:
77
+ return core.get_cached_shader(name, *sources)
@@ -0,0 +1,299 @@
1
+ from __future__ import annotations
2
+
3
+ import atexit
4
+ import os
5
+ import weakref
6
+ from abc import ABC, abstractmethod
7
+ from typing import TYPE_CHECKING, Any, Protocol, get_type_hints, Sequence, Callable
8
+
9
+ if TYPE_CHECKING:
10
+ from pyglet.math import Mat4
11
+ from pyglet.graphics.api.gl import ObjectSpace
12
+ from pyglet.window import Window
13
+
14
+ class BackendGlobalObject(ABC): # Temp name for now.
15
+ """A container for backend resources and information that are required throughout the code.
16
+
17
+ Meant to be accessed from a global level.
18
+ """
19
+ windows: weakref.WeakKeyDictionary[Window, SurfaceContext]
20
+
21
+ def __init__(self) -> None:
22
+ self.windows = weakref.WeakKeyDictionary()
23
+ self._current_window = None
24
+
25
+ @property
26
+ @abstractmethod
27
+ def object_space(self) -> ObjectSpace:
28
+ ...
29
+
30
+ @abstractmethod
31
+ def get_surface_context(self, window: Window, config) -> SurfaceContext:
32
+ """After a window is created, this will be called.
33
+
34
+ This must return a BackendWindowObject object.
35
+ """
36
+
37
+ @abstractmethod
38
+ def get_default_configs(self) -> Sequence:
39
+ """Configs to use if none specified."""
40
+
41
+ @abstractmethod
42
+ def initialize_matrices(self, window: Window) -> None:
43
+ """Initialize the global matrices."""
44
+
45
+ @abstractmethod
46
+ def set_viewport(self, window, x: int, y: int, width: int, height: int) -> None:
47
+ """Set the global viewport."""
48
+
49
+ def load_package_shader(self, package, resource_name):
50
+ """Reads a binary resource from the given package or subpackage without external dependencies.
51
+
52
+ Args:
53
+ package: The full package path (e.g., 'pyglet.graphics.api.vulkan.shaders').
54
+ resource_name: The resource filename (e.g., 'primitives.vert.spv').
55
+
56
+ Returns:
57
+ The binary contents of the resource.
58
+ """
59
+ # Dynamically resolve the package's directory
60
+ package_path = os.path.dirname(__import__(package, fromlist=['']).__file__)
61
+ resource_path = os.path.join(package_path, resource_name)
62
+
63
+ # Read the file in binary mode
64
+ with open(resource_path, 'rb') as file:
65
+ return file.read()
66
+
67
+ class SurfaceContext(ABC): # Temp name for now.
68
+ """A container for backend resources and information that are tied to a specific Window.
69
+
70
+ In OpenGL this would be something like an OpenGL Context, or in Vulkan, a Surface.
71
+ """
72
+ clear_color = (0.2, 0.2, 0.2, 1.0)
73
+
74
+ def __init__(self, global_ctx: BackendGlobalObject, window: Window, config: Any) -> None:
75
+ self.core = global_ctx
76
+ self.window = window
77
+ self.config = config
78
+
79
+ @abstractmethod
80
+ def set_clear_color(self, r: float, g: float, b: float, a: float) -> None:
81
+ """Sets the clear color for the current Window.
82
+
83
+ Default value is black.
84
+ """
85
+ # Backends need to implement setting this value.
86
+
87
+ @abstractmethod
88
+ def attach(self, window: Window) -> None:
89
+ """Attaches the specified Window into the backend context.
90
+
91
+ This function is called automatically when the operating system Window has been created.
92
+ """
93
+
94
+ @abstractmethod
95
+ def destroy(self) -> None:
96
+ """Destroys the graphical context."""
97
+
98
+ @abstractmethod
99
+ def flip(self) -> None:
100
+ """Flips the buffers in the graphical context."""
101
+
102
+ @abstractmethod
103
+ def clear(self) -> None:
104
+ """Clears the framebuffer."""
105
+
106
+
107
+ class VerifiedGraphicsConfig:
108
+ """Determines if this config is complete and able to create a Window resource context.
109
+
110
+ This is kept separate as the original user config may be re-used for multiple windows.
111
+
112
+ .. note:: Keep any non-backend attributes as private. Create a property if public use is wanted.
113
+ """
114
+ def __init__(self, window: Window, config: GraphicsConfig) -> None: # noqa: D107
115
+ self._window = window
116
+ self._config = config
117
+
118
+ @property
119
+ def is_finalized(self) -> bool:
120
+ return True
121
+
122
+ @abstractmethod
123
+ def apply_format(self) -> None:
124
+ """Commit the selected finalized attributes to the backend."""
125
+
126
+ @property
127
+ def attributes(self) -> dict[str, Any]:
128
+ return {attrib: value for attrib, value in self.__dict__.items() if attrib[0] != '_'}
129
+
130
+ def __repr__(self) -> str:
131
+ return f"Attributes({self.attributes})"
132
+
133
+
134
+ class GraphicsConfig:
135
+ """User requested values for the graphics configuration.
136
+
137
+ A Config stores the user preferences for attributes such as the size of the colour and depth buffers,
138
+ double buffering, multisampling, anisotropic, and so on.
139
+
140
+ Different platform and architectures only support certain attributes. Attributes are defined within the
141
+ class attribute namespace.
142
+
143
+ These are merely a suggestion to the backends; there is no guarantee that a platform or driver accept the
144
+ combination of attributes together.
145
+ """
146
+
147
+ def __init__(self, **kwargs: float | str) -> None:
148
+ """Create a template config with the given attributes.
149
+
150
+ Specify attributes as keyword arguments, for example::
151
+
152
+ template = UserConfig(double_buffer=True)
153
+
154
+ """
155
+ self._finalized_config: VerifiedGraphicsConfig | None = None
156
+ self._attributes = {}
157
+ self._user_set_attributes = set()
158
+
159
+ # Fetch the type hints dynamically from the class itself
160
+ attribute_types = get_type_hints(self)
161
+
162
+ # Initialize defaults or user-specified values
163
+ for attr_name, attr_type in attribute_types.items():
164
+ default_value = getattr(self, attr_name, None)
165
+
166
+ # Set user-provided values or fallback to default
167
+ if attr_name in kwargs:
168
+ user_value = kwargs[attr_name]
169
+ if isinstance(user_value, attr_type):
170
+ self._attributes[attr_name] = user_value
171
+ self._user_set_attributes.add(attr_name) # Track user-set attributes
172
+ setattr(self, attr_name, user_value)
173
+ else:
174
+ msg = f"Incorrect type for {attr_name}. Expected {attr_type.__name__}."
175
+ raise TypeError(msg)
176
+ else:
177
+ self._attributes[attr_name] = default_value
178
+ setattr(self, attr_name, default_value)
179
+
180
+ @abstractmethod
181
+ def match(self, window: Window) -> VerifiedGraphicsConfig | None:
182
+ """Matches this config to a given platform Window.
183
+
184
+ The subclassed platform config must handle setting the FinalizedAttributes values.
185
+
186
+ Returns:
187
+ `True` or `False` the given window matches the OpenGL configuration.
188
+ """
189
+
190
+ @property
191
+ def is_finalized(self) -> bool:
192
+ return False
193
+
194
+ @classmethod
195
+ def available_attributes(cls) -> dict:
196
+ """Return a list of available attribute names, types, and their default values."""
197
+ attributes = {}
198
+ attribute_types = get_type_hints(cls)
199
+ for attr_name, attr_type in attribute_types.items():
200
+ default_value = getattr(cls, attr_name, None)
201
+ attributes[attr_name] = (attr_type, default_value)
202
+ return attributes
203
+
204
+ @property
205
+ def user_set_attributes(self) -> set[str]:
206
+ """Return a set of attribute names that were explicitly set by the user."""
207
+ return self._user_set_attributes
208
+
209
+
210
+ class WindowTransformations:
211
+ def __init__(self, window, projection, view, model):
212
+ self._window = window
213
+ self._projection = projection
214
+ self._view = view
215
+ self._model = model
216
+
217
+ @property
218
+ def projection(self) -> Mat4:
219
+ return self._projection
220
+
221
+ @projection.setter
222
+ def projection(self, projection: Mat4) -> None:
223
+ self._projection = projection
224
+
225
+ @property
226
+ def view(self) -> Mat4:
227
+ return self._view
228
+
229
+ @view.setter
230
+ def view(self, view: Mat4) -> None:
231
+ self._view = view
232
+
233
+ @property
234
+ def model(self) -> Mat4:
235
+ return self._model
236
+
237
+ @model.setter
238
+ def model(self, model: Mat4) -> None:
239
+ self._model = model
240
+
241
+
242
+ class UBOMatrixTransformations(WindowTransformations): # noqa: D101
243
+ ...
244
+
245
+ class GraphicsResource(Protocol): # noqa: D101
246
+ def delete(self) -> None:
247
+ ...
248
+
249
+ class ResourceManagement:
250
+ """A manager to handle the freeing of resources for an API.
251
+
252
+ In some graphical API's, the order in which you free resources can be very specific.
253
+ """
254
+ managers: list[GraphicsResource]
255
+ weak_resources: weakref.WeakSet[GraphicsResource]
256
+
257
+ def __init__(self) -> None: # noqa: D107
258
+ self._func = None
259
+ self.managers = []
260
+ self.weak_resources = weakref.WeakSet()
261
+ atexit.register(self.on_exit_cleanup)
262
+
263
+ def set_pre_cleanup_func(self, func: Callable) -> None:
264
+ """Register a function to be called before cleanup.
265
+
266
+ Some API's may need to enforce a sync before cleanup.
267
+ """
268
+ self._func = func
269
+
270
+ def register_manager(self, resource: GraphicsResource) -> None:
271
+ """A manager handles multiple resources, these will be called in reverse order on cleanup."""
272
+ self.managers.append(resource)
273
+
274
+ def register_resource(self, resource: GraphicsResource) -> None:
275
+ """Registers a resource as a weak reference.
276
+
277
+ Some resources do not have a manager, but they do need to be freed before others. Keeping them permanently
278
+ may prevent them from being garbage collected prior to shutdown.
279
+ """
280
+ self.weak_resources.add(resource)
281
+
282
+ def on_exit_cleanup(self) -> None:
283
+ """Cleans up all graphical resources that have been registered on application exit."""
284
+ self.cleanup_all()
285
+
286
+ def cleanup_all(self) -> None:
287
+ """Cleans up all graphical resources that have been registered.
288
+
289
+ Weak resources registered are destroyed first.
290
+
291
+ Managers are called last, and in reverse order of registered.
292
+ """
293
+ if self._func:
294
+ self._func()
295
+
296
+ for resource in self.weak_resources:
297
+ resource.delete()
298
+ for resource in reversed(self.managers):
299
+ resource.delete()
@@ -0,0 +1,58 @@
1
+ """OpenGL interface.
2
+
3
+ This package imports all OpenGL and registered OpenGL extension
4
+ functions. Functions have identical signatures to their C counterparts.
5
+
6
+ OpenGL is documented in full at the `OpenGL Reference Pages`_.
7
+
8
+ The `OpenGL Programming Guide`_, also known as "The Red Book", is a popular
9
+ reference manual organised by topic. It is available in digital and paper
10
+ editions.
11
+
12
+ .. _OpenGL Reference Pages: https://www.khronos.org/registry/OpenGL-Refpages/
13
+ .. _OpenGL Programming Guide: http://opengl-redbook.com/
14
+
15
+ The following subpackages are imported into this "mega" package already
16
+ (and so are available by importing ``pyglet.gl``):
17
+
18
+ ``pyglet.graphics.api.gl.gl``
19
+ OpenGL
20
+ ``pyglet.graphics.api.gl.gl.glext_arb``
21
+ ARB registered OpenGL extension functions
22
+ ``pyglet.graphics.api.gl.gl.gl_compat``
23
+ Deprecated OpenGL extension functions.
24
+
25
+ These subpackages are also available, but are not imported into this namespace
26
+ by default:
27
+
28
+ ``pyglet.graphics.api.gl.glext_nv``
29
+ nVidia OpenGL extension functions
30
+ ``pyglet.graphics.api.gl.agl``
31
+ AGL (Mac OS X OpenGL context functions)
32
+ ``pyglet.graphics.api.gl.glx``
33
+ GLX (Linux OpenGL context functions)
34
+ ``pyglet.graphics.api.gl.glxext_arb``
35
+ ARB registered GLX extension functions
36
+ ``pyglet.graphics.api.gl.glxext_nv``
37
+ nvidia GLX extension functions
38
+ ``pyglet.graphics.api.gl.wgl``
39
+ WGL (Windows OpenGL context functions)
40
+ ``pyglet.graphics.api.gl.wglext_arb``
41
+ ARB registered WGL extension functions
42
+ ``pyglet.graphics.api.gl.wglext_nv``
43
+ nvidia WGL extension functions
44
+
45
+ The information modules are provided for convenience, and are documented below.
46
+ """
47
+ from __future__ import annotations
48
+
49
+ import sys as _sys
50
+
51
+ import pyglet as _pyglet
52
+ from pyglet import compat_platform
53
+ from pyglet.graphics.api.gl.gl import * # Must always be imported before gl_info or bad things happen. # noqa: F403
54
+ from pyglet.graphics.api.gl.lib import GLException # noqa: F401
55
+ from .base import ObjectSpace # noqa: F401
56
+ from .context import OpenGLSurfaceContext
57
+
58
+ _is_pyglet_doc_run = hasattr(_sys, "is_pyglet_doc_run") and _sys.is_pyglet_doc_run
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class ObjectSpace:
5
+ """A container to store shared objects that are to be removed."""
6
+
7
+ def __init__(self) -> None:
8
+ """Initialize the context object space."""
9
+ # Objects scheduled for deletion the next time this object space is active.
10
+ self.doomed_textures = []
11
+ self.doomed_buffers = []
12
+ self.doomed_shader_programs = []
13
+ self.doomed_shaders = []
14
+ self.doomed_renderbuffers = []
15
+
16
+
17
+ class ContextException(Exception):
18
+ pass
19
+
20
+
21
+ class ConfigException(Exception):
22
+ pass
23
+
24
+