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,302 @@
1
+ """OpenGL Buffer Objects.
2
+
3
+ :py:class:`~BufferObject` and a :py:class:`~BackedBufferObject` are provied.
4
+ The first is a lightweight abstraction over an OpenGL buffer, as created
5
+ with ``glGenBuffers``. The backed buffer object is similar, but provides a
6
+ full mirror of the data in CPU memory. This allows for delayed uploading of
7
+ changes to GPU memory, which can improve performance is some cases.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import ctypes
13
+ import sys
14
+ from functools import lru_cache
15
+ from typing import TYPE_CHECKING, Sequence
16
+
17
+ import js
18
+ import pyodide.ffi
19
+
20
+ import pyglet
21
+ from pyglet.customtypes import CType, CTypesPointer
22
+ from pyglet.graphics.api.webgl.gl import (
23
+ GL_ARRAY_BUFFER,
24
+ GL_BUFFER_SIZE,
25
+ GL_DYNAMIC_DRAW,
26
+ GL_ELEMENT_ARRAY_BUFFER,
27
+ GL_MAP_COHERENT_BIT,
28
+ GL_MAP_PERSISTENT_BIT,
29
+ GL_MAP_READ_BIT,
30
+ GL_MAP_WRITE_BIT,
31
+ GL_WRITE_ONLY,
32
+ )
33
+ from pyglet.graphics.buffer import AbstractBuffer
34
+
35
+ if TYPE_CHECKING:
36
+ from _ctypes import Array
37
+
38
+ from pyglet.graphics.api.webgl import OpenGLSurfaceContext
39
+ from pyglet.graphics.api.webgl.webgl_js import WebGLBuffer
40
+ from pyglet.graphics.shader import Attribute, GraphicsAttribute
41
+
42
+
43
+ class BufferObject(AbstractBuffer):
44
+ """Lightweight representation of an OpenGL Buffer Object.
45
+
46
+ The data in the buffer is not replicated in any system memory (unless it
47
+ is done so by the video driver). While this can reduce system memory usage,
48
+ performing multiple small updates to the buffer can be relatively slow.
49
+ The target of the buffer is ``GL_ARRAY_BUFFER`` internally to avoid
50
+ accidentally overriding other states when altering the buffer contents.
51
+ The intended target can be set when binding the buffer.
52
+ """
53
+
54
+ id: WebGLBuffer
55
+ usage: int
56
+ target: int
57
+ _context: OpenGLSurfaceContext | None
58
+
59
+ def __init__(self, context: OpenGLSurfaceContext, size: int, target: int = GL_ARRAY_BUFFER,
60
+ usage: int = GL_DYNAMIC_DRAW) -> None:
61
+ """Initialize the BufferObject with the given size and draw usage.
62
+
63
+ JS does not allow to directly map memory, so all of them must be backed.
64
+ """
65
+ super().__init__('b', size)
66
+ self.usage = usage
67
+ self.target = target
68
+ self._context = context
69
+ self._gl = self._context.gl
70
+
71
+ self.id = self._gl.createBuffer()
72
+
73
+ self._gl.bindBuffer(self.target, self.id)
74
+ self._gl.bufferData(self.target, self.size, self.usage)
75
+
76
+ def get_bytes(self) -> bytes: ...
77
+
78
+ def get_bytes_region(self, offset: int, length: int) -> bytes: ...
79
+
80
+ def get_data_region(self, start: int, length: int) -> ctypes.Array[CType]: ...
81
+
82
+ def set_bytes(self, data: bytes) -> None: ...
83
+
84
+ def set_bytes_region(self, start: int, length: int) -> None: ...
85
+
86
+ def set_data_ptr(self, offset: int, length: int, ptr: CTypesPointer) -> None: ...
87
+
88
+ def get_buffer_size(self):
89
+ return self._gl.getBufferParameter(self.target, GL_BUFFER_SIZE)
90
+
91
+ def invalidate(self) -> None:
92
+ self._gl.bufferData(self.target, None, self.usage)
93
+
94
+ def bind(self) -> None:
95
+ self._gl.bindBuffer(self.target, self.id)
96
+
97
+ def unbind(self) -> None:
98
+ self._gl.bindBuffer(self.target, 0)
99
+
100
+ def get_data(self) -> ctypes.Array[CType]:
101
+ data = js.Uint8Array.new(self.size)
102
+ self._gl.bindBuffer(self.target, self.id)
103
+ self._gl.getBufferSubData(self.target, 0, data)
104
+ py_buffer = data.buffer.to_py(depth=1)
105
+ return bytes(py_buffer)
106
+
107
+ def set_data(self, data: Sequence[int] | CTypesPointer) -> None:
108
+ byte_data = ctypes.string_at(data, ctypes.sizeof(data.contents))
109
+ buffer = pyodide.ffi.to_js(memoryview(byte_data))
110
+ js_array = js.Uint8Array.new(buffer)
111
+ self._gl.bindBuffer(self.target, self.id)
112
+ self._gl.bufferData(self.target, js_array, self.usage)
113
+
114
+ def set_data_region(self, data: Sequence[int] | CTypesPointer, start: int, length: int) -> None:
115
+ self._gl.bindBuffer(self.target, self.id)
116
+ self._gl.bufferSubData(self.target, start, data)
117
+
118
+ def map(self, bits=GL_WRITE_ONLY) -> CTypesPointer[ctypes.c_byte]:
119
+ raise NotImplementedError()
120
+
121
+ def map_range(self, start: int, size: int, ptr_type: type[CTypesPointer], bits=GL_MAP_WRITE_BIT) -> CTypesPointer:
122
+ raise NotImplementedError()
123
+
124
+ def unmap(self) -> None:
125
+ raise NotImplementedError()
126
+
127
+ def delete(self) -> None:
128
+ self._gl.deleteBuffer(self.id)
129
+ self.id = None
130
+
131
+ def __del__(self) -> None:
132
+ if self.id is not None:
133
+ try:
134
+ self._context.delete_buffer(self.id)
135
+ self.id = None
136
+ except (AttributeError, ImportError):
137
+ pass # Interpreter is shutting down
138
+
139
+ def resize(self, size: int) -> None:
140
+ # Map, create a copy, then reinitialize.
141
+ temp = (ctypes.c_byte * size)()
142
+
143
+ self._gl.bindBuffer(self.target, self.id)
144
+ data = glMapBufferRange(self.target, 0, self.size, GL_MAP_READ_BIT)
145
+ ctypes.memmove(temp, data, min(size, self.size))
146
+ glUnmapBuffer(self.target)
147
+
148
+ self.size = size
149
+ self._gl.bufferData(self.target, self.size, temp, self.usage)
150
+
151
+ def __repr__(self) -> str:
152
+ return f"{self.__class__.__name__}(id={self.id}, data_type={self.data_type}, size={self.size})"
153
+
154
+
155
+ class BackedBufferObject(BufferObject):
156
+ """A buffer with system-memory backed store.
157
+
158
+ Updates to the data via ``set_data`` and ``set_data_region`` will be held
159
+ in system memory until ``commit`` is called. The advantage is that fewer
160
+ OpenGL calls are needed, which can increase performance at the expense of
161
+ system memory.
162
+ """
163
+
164
+ data: CType
165
+ data_ptr: int
166
+ _dirty_min: int
167
+ _dirty_max: int
168
+ _dirty: bool
169
+ stride: int
170
+ element_count: int
171
+ ctype: CType
172
+
173
+ def __init__(
174
+ self, context: OpenGLSurfaceContext, size: int, c_type: CType, stride: int, element_count: int,
175
+ usage: int = GL_DYNAMIC_DRAW, target: int=GL_ARRAY_BUFFER,
176
+ ) -> None:
177
+ super().__init__(context, size, target, usage)
178
+
179
+ self.c_type = c_type
180
+ self._ctypes_size = ctypes.sizeof(c_type)
181
+ number = size // self._ctypes_size
182
+ self.data = (c_type * number)()
183
+ self.data_ptr = ctypes.addressof(self.data)
184
+
185
+ self._dirty_min = sys.maxsize
186
+ self._dirty_max = 0
187
+ self._dirty = False
188
+
189
+ self.stride = stride
190
+ self.element_count = element_count
191
+
192
+ def commit(self) -> None:
193
+ """Commits all saved changes to the underlying buffer before drawing.
194
+
195
+ Allows submitting multiple changes at once, rather than having to call glBufferSubData for every change.
196
+ """
197
+ if not self._dirty:
198
+ return
199
+
200
+ self._gl.bindBuffer(self.target, self.id)
201
+ size = self._dirty_max - self._dirty_min
202
+ if size > 0:
203
+ if size == self.size:
204
+ byte_data = ctypes.string_at(self.data_ptr, self.size)
205
+ buffer = pyodide.ffi.to_js(memoryview(byte_data))
206
+ js_array = js.Uint8Array.new(buffer)
207
+ self._gl.bufferData(self.target, js_array, self.usage)
208
+ else:
209
+ byte_data = ctypes.string_at(self.data_ptr + self._dirty_min, size)
210
+ buffer = pyodide.ffi.to_js(memoryview(byte_data))
211
+ js_array = js.Uint8Array.new(buffer)
212
+
213
+ self._gl.bufferSubData(self.target, self._dirty_min, js_array)
214
+
215
+ self._dirty_min = sys.maxsize
216
+ self._dirty_max = 0
217
+ self._dirty = False
218
+
219
+ @lru_cache(maxsize=None) # noqa: B019
220
+ def get_region(self, start: int, count: int) -> Array[CType]:
221
+ byte_start = self.stride * start # byte offset
222
+ array_count = self.element_count * count # number of values
223
+ ptr_type = ctypes.POINTER(self.c_type * array_count)
224
+ return ctypes.cast(self.data_ptr + byte_start, ptr_type).contents
225
+
226
+ def set_region(self, start: int, count: int, data: Sequence[float]) -> None:
227
+ array_start = self.element_count * start
228
+ array_end = self.element_count * count + array_start
229
+
230
+ self.data[array_start:array_end] = data
231
+
232
+ # replicated from self.invalidate_region
233
+ byte_start = self.stride * start
234
+ byte_end = byte_start + self.stride * count
235
+ # As of Python 3.11, this is faster than min/max:
236
+ if byte_start < self._dirty_min:
237
+ self._dirty_min = byte_start
238
+ if byte_end > self._dirty_max:
239
+ self._dirty_max = byte_end
240
+ self._dirty = True
241
+
242
+ def resize(self, size: int) -> None:
243
+ # size is the allocator size * attribute.stride
244
+ number = size // ctypes.sizeof(self.c_type)
245
+ data = (self.c_type * number)()
246
+ ctypes.memmove(data, self.data, min(size, self.size))
247
+ self.data = data
248
+ self.data_ptr = ctypes.addressof(data)
249
+ self.size = size
250
+
251
+ # Set the dirty range to be the entire buffer.
252
+ self._dirty_min = 0
253
+ self._dirty_max = self.size
254
+ self._dirty = True
255
+
256
+ self.get_region.cache_clear()
257
+
258
+ def invalidate(self) -> None:
259
+ super().invalidate()
260
+ self._dirty = True
261
+
262
+ def invalidate_region(self, start: int, count: int) -> None:
263
+ byte_start = self.stride * start
264
+ byte_end = byte_start + self.stride * count
265
+ # As of Python 3.11, this is faster than min/max:
266
+ if byte_start < self._dirty_min:
267
+ self._dirty_min = byte_start
268
+ if byte_end > self._dirty_max:
269
+ self._dirty_max = byte_end
270
+ self._dirty = True
271
+
272
+
273
+ class AttributeBufferObject(BackedBufferObject):
274
+ """A backed buffer used for Shader Program attributes."""
275
+
276
+ def __init__(self, context: OpenGLSurfaceContext, size: int, graphics_attr: GraphicsAttribute) -> None:
277
+ # size is the allocator size * attribute.stride (buffer size)
278
+ super().__init__(context, size, graphics_attr.attribute.c_type,
279
+ graphics_attr.view.stride,
280
+ graphics_attr.attribute.fmt.components)
281
+
282
+
283
+
284
+ class IndexedBufferObject(BackedBufferObject):
285
+ """A backed buffer used for indices."""
286
+
287
+ def __init__(self, context: OpenGLSurfaceContext, size: int, c_type: CType, stride: int, element_count: int,
288
+ usage: int = GL_DYNAMIC_DRAW) -> None:
289
+ super().__init__(context, size, c_type, stride, element_count, usage, GL_ELEMENT_ARRAY_BUFFER)
290
+
291
+ def bind_to_index_buffer(self) -> None:
292
+ """Binds this buffer as an index buffer on the active vertex array."""
293
+ self._gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.id)
294
+
295
+
296
+ class PersistentBufferObject(BackedBufferObject):
297
+ """A persistently mapped buffer.
298
+
299
+ Available in OpenGL 4.3+ contexts. Persistently mapped buffers
300
+ are mapped one time on creation, and can be updated at any time
301
+ without the need to map or unmap.
302
+ """
@@ -0,0 +1,234 @@
1
+ from __future__ import annotations
2
+
3
+ import weakref
4
+ from typing import TYPE_CHECKING, Any, Callable
5
+
6
+ import js
7
+ from pyodide.ffi import create_proxy
8
+
9
+ from pyglet.graphics.api.base import SurfaceContext
10
+ from pyglet.graphics.api.webgl import gl
11
+ from pyglet.graphics.api.webgl.gl import GL_COLOR_BUFFER_BIT
12
+ from pyglet.graphics.api.webgl.gl_info import GLInfo
13
+ from pyglet.graphics.api.webgl.shader import GLDataType
14
+
15
+ if TYPE_CHECKING:
16
+ from pyglet.graphics.api import WebGLBackend
17
+ from pyglet.graphics.api.webgl.config import OpenGLWindowConfig
18
+ from pyglet.graphics.api.webgl.webgl_js import WebGL2RenderingContext
19
+ from pyglet.window import Window
20
+ from pyglet.window.emscripten import EmscriptenWindow
21
+
22
+
23
+ class ObjectSpace:
24
+ """A container to store shared objects that are to be removed."""
25
+
26
+ def __init__(self) -> None:
27
+ """Initialize the context object space."""
28
+ # Objects scheduled for deletion the next time this object space is active.
29
+ self.doomed_textures = []
30
+ self.doomed_buffers = []
31
+ self.doomed_shader_programs = []
32
+ self.doomed_shaders = []
33
+ self.doomed_renderbuffers = []
34
+
35
+
36
+ class OpenGLSurfaceContext(SurfaceContext):
37
+ """A base OpenGL context for drawing.
38
+
39
+ Use ``DisplayConfig.create_context`` to create a context.
40
+ """
41
+
42
+ gl: WebGL2RenderingContext
43
+ config: OpenGLWindowConfig
44
+ context_share: OpenGLSurfaceContext | None
45
+
46
+ def __init__(
47
+ self,
48
+ global_ctx: WebGLBackend,
49
+ window: EmscriptenWindow,
50
+ config: OpenGLWindowConfig, # noqa: D417
51
+ context_share: OpenGLSurfaceContext | None = None,
52
+ ) -> None:
53
+ """Initialize a context.
54
+
55
+ This should only be created through the ``DisplayConfig.create_context`` method.
56
+
57
+ Args:
58
+ config:
59
+ An operating system specific config.
60
+ context_share:
61
+ A context to share objects with. Use ``None`` to disable sharing.
62
+ """
63
+ super().__init__(global_ctx, window, config)
64
+ self.global_ctx = global_ctx
65
+ self.window = window
66
+ self.config = config
67
+ self.context_share = context_share
68
+ self.is_current = False
69
+
70
+ # The GL Context.
71
+ self.gl = self.window.canvas.getContext("webgl2")
72
+
73
+ self._info = GLInfo()
74
+ self._info.query(self.gl)
75
+ self.object_space = ObjectSpace()
76
+
77
+ self._draw_proxy = create_proxy(self.window.draw)
78
+
79
+ self._clear_color = (0.0, 0.0, 0.0, 1.0)
80
+
81
+ self.doomed_vaos = []
82
+ self.doomed_framebuffers = []
83
+
84
+ self.cached_programs = weakref.WeakValueDictionary()
85
+ self._create_uniform_dicts()
86
+
87
+ def get_info(self) -> GLInfo:
88
+ """Get the :py:class:`~GLInfo` instance for this context."""
89
+ return self._info
90
+
91
+ def resized(self, width, height): ...
92
+
93
+ def detach(self):
94
+ self.context = None
95
+
96
+ def __repr__(self) -> str:
97
+ return f"{self.__class__.__name__}(id={id(self)}, share={self.context_share})"
98
+
99
+ def __enter__(self) -> None:
100
+ self.set_current()
101
+
102
+ def __exit__(self, *_args) -> None: # noqa: ANN002
103
+ return
104
+
105
+ def set_clear_color(self, r: float, g: float, b: float, a: float) -> None:
106
+ self._clear_color = (r, g, b, a)
107
+
108
+ def clear(self) -> None:
109
+ self.gl.clear(GL_COLOR_BUFFER_BIT)
110
+
111
+ def flip(self):
112
+ pass
113
+
114
+ def destroy(self) -> None:
115
+ """Release the Context.
116
+
117
+ The context will not be useable after being destroyed. Each platform
118
+ has its own convention for releasing the context and the buffer(s)
119
+ that depend on it in the correct order; this should never be called
120
+ by an application.
121
+ """
122
+ # self.detach()
123
+ #
124
+ if self.core.current_context is self:
125
+ self.core.current_context = None
126
+ # #gl_info.remove_active_context()
127
+
128
+ def attach(self, window: Window) -> None:
129
+ # if not self.config.compatible(canvas):
130
+ # msg = f'Cannot attach {canvas} to {self}'
131
+ # raise RuntimeError(msg)
132
+ self.window = window
133
+
134
+ def before_draw(self) -> None:
135
+ self.gl.clearColor(*self._clear_color)
136
+ self.gl.clear(GL_COLOR_BUFFER_BIT)
137
+
138
+ def set_current(self) -> None:
139
+ return
140
+ """Make this the active Context.
141
+
142
+ Setting the Context current will also delete any OpenGL
143
+ objects that have been queued for deletion. IE: any objects
144
+ that were created in this Context, but have been called for
145
+ deletion while another Context was active.
146
+ """
147
+ assert self.window is not None, "Window has not been attached."
148
+
149
+ # Not per-thread
150
+ self.global_ctx.current_context = self
151
+ gl.current_context = self
152
+
153
+ # Set active context.
154
+ # gl_info.set_active_context()
155
+
156
+ if not self._info.was_queried:
157
+ self._info.query()
158
+
159
+ if self.object_space.doomed_textures:
160
+ self._delete_objects(self.object_space.doomed_textures, gl.glDeleteTextures)
161
+ if self.object_space.doomed_buffers:
162
+ self._delete_objects(self.object_space.doomed_buffers, gl.glDeleteBuffers)
163
+ if self.object_space.doomed_shader_programs:
164
+ self._delete_objects_one_by_one(self.object_space.doomed_shader_programs, gl.glDeleteProgram)
165
+ if self.object_space.doomed_shaders:
166
+ self._delete_objects_one_by_one(self.object_space.doomed_shaders, gl.glDeleteShader)
167
+ if self.object_space.doomed_renderbuffers:
168
+ self._delete_objects(self.object_space.doomed_renderbuffers, gl.glDeleteRenderbuffers)
169
+
170
+ if self.doomed_vaos:
171
+ self._delete_objects(self.doomed_vaos, gl.glDeleteVertexArrays)
172
+ if self.doomed_framebuffers:
173
+ self._delete_objects(self.doomed_framebuffers, gl.glDeleteFramebuffers)
174
+
175
+ def _create_uniform_dicts(self) -> None:
176
+ self._uniform_setters: dict[int, tuple[GLDataType, Callable, int]] = {
177
+ # uniform: gl_type, setter, length
178
+ gl.GL_BOOL: (gl.GLint, self.gl.uniform1i, 1),
179
+ gl.GL_BOOL_VEC2: (gl.GLint, self.gl.uniform2iv, 2),
180
+ gl.GL_BOOL_VEC3: (gl.GLint, self.gl.uniform3iv, 3),
181
+ gl.GL_BOOL_VEC4: (gl.GLint, self.gl.uniform4iv, 4),
182
+ gl.GL_INT: (gl.GLint, self.gl.uniform1i, 1),
183
+ gl.GL_INT_VEC2: (gl.GLint, self.gl.uniform2iv, 2),
184
+ gl.GL_INT_VEC3: (gl.GLint, self.gl.uniform3iv, 3),
185
+ gl.GL_INT_VEC4: (gl.GLint, self.gl.uniform4iv, 4),
186
+ gl.GL_FLOAT: (gl.GLfloat, self.gl.uniform1f, 1),
187
+ gl.GL_FLOAT_VEC2: (gl.GLfloat, self.gl.uniform2fv, 2),
188
+ gl.GL_FLOAT_VEC3: (gl.GLfloat, self.gl.uniform3fv, 3),
189
+ gl.GL_FLOAT_VEC4: (gl.GLfloat, self.gl.uniform4fv, 4),
190
+ # 1D Samplers
191
+ gl.GL_SAMPLER_1D: (gl.GLint, self.gl.uniform1i, 1),
192
+ gl.GL_SAMPLER_1D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
193
+ gl.GL_INT_SAMPLER_1D: (gl.GLint, self.gl.uniform1i, 1),
194
+ gl.GL_INT_SAMPLER_1D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
195
+ gl.GL_UNSIGNED_INT_SAMPLER_1D: (gl.GLint, self.gl.uniform1i, 1),
196
+ gl.GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
197
+ # 2D Samplers
198
+ gl.GL_SAMPLER_2D: (gl.GLint, self.gl.uniform1i, 1),
199
+ gl.GL_SAMPLER_2D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
200
+ gl.GL_INT_SAMPLER_2D: (gl.GLint, self.gl.uniform1iv, 1),
201
+ gl.GL_INT_SAMPLER_2D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
202
+ gl.GL_UNSIGNED_INT_SAMPLER_2D: (gl.GLint, self.gl.uniform1iv, 1),
203
+ gl.GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
204
+ # Multisample
205
+ gl.GL_SAMPLER_2D_MULTISAMPLE: (gl.GLint, self.gl.uniform1iv, 1),
206
+ gl.GL_INT_SAMPLER_2D_MULTISAMPLE: (gl.GLint, self.gl.uniform1iv, 1),
207
+ gl.GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: (gl.GLint, self.gl.uniform1iv, 1),
208
+ # Cube Samplers
209
+ gl.GL_SAMPLER_CUBE: (gl.GLint, self.gl.uniform1iv, 1),
210
+ gl.GL_INT_SAMPLER_CUBE: (gl.GLint, self.gl.uniform1iv, 1),
211
+ gl.GL_UNSIGNED_INT_SAMPLER_CUBE: (gl.GLint, self.gl.uniform1iv, 1),
212
+ gl.GL_SAMPLER_CUBE_MAP_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
213
+ gl.GL_INT_SAMPLER_CUBE_MAP_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
214
+ gl.GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
215
+ # 3D Samplers
216
+ gl.GL_SAMPLER_3D: (gl.GLint, self.gl.uniform1iv, 1),
217
+ gl.GL_INT_SAMPLER_3D: (gl.GLint, self.gl.uniform1iv, 1),
218
+ gl.GL_UNSIGNED_INT_SAMPLER_3D: (gl.GLint, self.gl.uniform1iv, 1),
219
+ gl.GL_FLOAT_MAT2: (gl.GLfloat, self.gl.uniformMatrix2fv, 4),
220
+ gl.GL_FLOAT_MAT3: (gl.GLfloat, self.gl.uniformMatrix3fv, 6),
221
+ gl.GL_FLOAT_MAT4: (gl.GLfloat, self.gl.uniformMatrix4fv, 16),
222
+ # Images
223
+ gl.GL_IMAGE_1D: (gl.GLint, self.gl.uniform1iv, 1),
224
+ gl.GL_IMAGE_2D: (gl.GLint, self.gl.uniform1iv, 1),
225
+ gl.GL_IMAGE_2D_RECT: (gl.GLint, self.gl.uniform1iv, 1),
226
+ gl.GL_IMAGE_3D: (gl.GLint, self.gl.uniform1iv, 1),
227
+ gl.GL_IMAGE_1D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
228
+ gl.GL_IMAGE_2D_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
229
+ gl.GL_IMAGE_2D_MULTISAMPLE: (gl.GLint, self.gl.uniform1iv, 1),
230
+ gl.GL_IMAGE_2D_MULTISAMPLE_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
231
+ gl.GL_IMAGE_BUFFER: (gl.GLint, self.gl.uniform1iv, 1),
232
+ gl.GL_IMAGE_CUBE: (gl.GLint, self.gl.uniform1iv, 1),
233
+ gl.GL_IMAGE_CUBE_MAP_ARRAY: (gl.GLint, self.gl.uniform1iv, 1),
234
+ }