pyglet 2.1.12__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 +4 -17
  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 +27 -5
  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 +147 -177
  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.12.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.12.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.12.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.12.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
@@ -8,792 +8,13 @@ See the :ref:`guide_graphics` for details on how to use this graphics API.
8
8
  """
9
9
  from __future__ import annotations
10
10
 
11
- import ctypes
12
- import weakref
13
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Sequence, Tuple
14
11
 
15
- import pyglet
16
- from pyglet.gl.gl import (
17
- GL_TEXTURE0,
18
- GL_UNSIGNED_BYTE,
19
- GL_UNSIGNED_INT,
20
- GL_UNSIGNED_SHORT,
21
- GLuint,
22
- glActiveTexture,
23
- glBindTexture,
24
- glBindVertexArray,
25
- glDeleteVertexArrays,
26
- glDrawArrays,
27
- glDrawElements,
28
- glFlush,
29
- glGenVertexArrays,
30
- )
31
- from pyglet.graphics import shader, vertexdomain
32
- from pyglet.graphics.vertexarray import VertexArray # noqa: F401
33
- from pyglet.graphics.vertexbuffer import BufferObject
12
+ from pyglet.graphics.base import GeometryMode # noqa: F401
13
+ from pyglet.graphics import api # noqa: F401
14
+ from pyglet.graphics.draw import Group, ShaderGroup # noqa: F401
15
+ from pyglet.graphics.state import State # noqa: F401
16
+ from pyglet.graphics.api import Batch, get_default_shader, get_default_batch, core, Shader, ShaderProgram, ComputeShaderProgram # noqa: F401
17
+ from pyglet.graphics.texture import Texture, TextureGrid, Texture3D, TextureArray # noqa: F401
18
+ from pyglet.graphics.atlas import TextureBin, TextureArrayBin, TextureAtlas # noqa: F401
19
+ from pyglet.graphics.framebuffer import Framebuffer, Renderbuffer # noqa: F401
34
20
 
35
- if TYPE_CHECKING:
36
- from pyglet.graphics.shader import ShaderProgram
37
- from pyglet.graphics.vertexdomain import IndexedVertexList, VertexList
38
-
39
- _debug_graphics_batch = pyglet.options['debug_graphics_batch']
40
-
41
-
42
- def draw(size: int, mode: int, **data: Any) -> None:
43
- """Draw a primitive immediately.
44
-
45
- :warning: This function is deprecated as of 2.0.4, and will be removed
46
- in the next release.
47
-
48
- Args:
49
- size:
50
- Number of vertices given
51
- mode:
52
- OpenGL drawing mode, e.g. ``GL_TRIANGLES``, avoiding quotes.
53
- **data: keyword arguments for passing vertex attribute data.
54
- The keyword should be the vertex attribute name, and the
55
- argument should be a tuple of (format, data). For example:
56
- `position=('f', array)`
57
-
58
- """
59
- # Create and bind a throwaway VAO
60
- vao_id = GLuint()
61
- glGenVertexArrays(1, vao_id)
62
- glBindVertexArray(vao_id)
63
- # Activate shader program:
64
- program = get_default_shader()
65
- program.use()
66
-
67
- buffers = []
68
- for name, (fmt, array) in data.items():
69
- location = program.attributes[name]['location']
70
- count = program.attributes[name]['count']
71
- gl_type = vertexdomain._gl_types[fmt[0]]
72
- normalize = 'n' in fmt
73
- attribute = shader.Attribute(name, location, count, gl_type, normalize, False)
74
- assert size == len(array) // attribute.count, f'Data for {fmt} is incorrect length'
75
-
76
- buffer = BufferObject(size * attribute.stride)
77
- data = (attribute.c_type * len(array))(*array)
78
- buffer.set_data(data)
79
-
80
- attribute.enable()
81
- attribute.set_pointer(buffer.ptr)
82
- buffers.append(buffer) # Don't garbage collect it.
83
-
84
- glDrawArrays(mode, 0, size)
85
-
86
- # Deactivate shader program:
87
- program.stop()
88
- # Discard everything after drawing:
89
- del buffers
90
- glBindVertexArray(0)
91
- glDeleteVertexArrays(1, vao_id)
92
-
93
-
94
- def draw_indexed(size: int, mode: int, indices: Sequence[int], **data: Any) -> None:
95
- """Draw a primitive with indexed vertices immediately.
96
-
97
- :warning: This function is deprecated as of 2.0.4, and will be removed
98
- in the next release.
99
-
100
- Args:
101
- size:
102
- Number of vertices given
103
- mode:
104
- OpenGL drawing mode, e.g. ``GL_TRIANGLES``
105
- indices:
106
- Sequence of integers giving indices into the vertex list.
107
- **data: keyword arguments for passing vertex attribute data.
108
- The keyword should be the vertex attribute name, and the
109
- argument should be a tuple of (format, data). For example:
110
- `position=('f', array)`
111
-
112
- """
113
- # Create and bind a throwaway VAO
114
- vao_id = GLuint()
115
- glGenVertexArrays(1, vao_id)
116
- glBindVertexArray(vao_id)
117
- # Activate shader program:
118
- program = get_default_shader()
119
- program.use()
120
-
121
- buffers = []
122
- for name, (fmt, array) in data.items():
123
- location = program.attributes[name]['location']
124
- count = program.attributes[name]['count']
125
- gl_type = vertexdomain._gl_types[fmt[0]] # noqa: SLF001
126
- normalize = 'n' in fmt
127
- attribute = shader.Attribute(name, location, count, gl_type, normalize, False)
128
- assert size == len(array) // attribute.count, f'Data for {fmt} is incorrect length'
129
-
130
- buffer = BufferObject(size * attribute.stride)
131
- data = (attribute.c_type * len(array))(*array)
132
- buffer.set_data(data)
133
-
134
- attribute.enable()
135
- attribute.set_pointer(buffer.ptr)
136
- buffers.append(buffer) # Don't garbage collect it.
137
-
138
- if size <= 0xff:
139
- index_type = GL_UNSIGNED_BYTE
140
- index_c_type = ctypes.c_ubyte
141
- elif size <= 0xffff:
142
- index_type = GL_UNSIGNED_SHORT
143
- index_c_type = ctypes.c_ushort
144
- else:
145
- index_type = GL_UNSIGNED_INT
146
- index_c_type = ctypes.c_uint
147
-
148
- # With GL 3.3 vertex arrays indices needs to be in a buffer
149
- # bound to the ELEMENT_ARRAY slot
150
- index_array = (index_c_type * len(indices))(*indices)
151
- index_buffer = BufferObject(ctypes.sizeof(index_array))
152
- index_buffer.set_data(index_array)
153
- index_buffer.bind_to_index_buffer()
154
-
155
- glDrawElements(mode, len(indices), index_type, 0)
156
- glFlush()
157
-
158
- # Deactivate shader program:
159
- program.stop()
160
- # Discard everything after drawing:
161
- del buffers
162
- del index_buffer
163
- glBindVertexArray(0)
164
- glDeleteVertexArrays(1, vao_id)
165
-
166
-
167
- # Default Shader source:
168
-
169
- _vertex_source: str = """#version 330 core
170
- in vec3 position;
171
- in vec4 colors;
172
- in vec3 tex_coords;
173
- out vec4 vertex_colors;
174
- out vec3 texture_coords;
175
-
176
- uniform WindowBlock
177
- {
178
- mat4 projection;
179
- mat4 view;
180
- } window;
181
-
182
- void main()
183
- {
184
- gl_Position = window.projection * window.view * vec4(position, 1.0);
185
-
186
- vertex_colors = colors;
187
- texture_coords = tex_coords;
188
- }
189
- """
190
-
191
- _fragment_source: str = """#version 330 core
192
- in vec4 vertex_colors;
193
- in vec3 texture_coords;
194
- out vec4 final_colors;
195
-
196
- uniform sampler2D our_texture;
197
-
198
- void main()
199
- {
200
- final_colors = texture(our_texture, texture_coords.xy) + vertex_colors;
201
- }
202
- """
203
-
204
- # Default blit source
205
- _blit_vertex_source: str = """#version 330 core
206
- in vec3 position;
207
- in vec3 tex_coords;
208
- out vec3 texture_coords;
209
-
210
- uniform WindowBlock
211
- {
212
- mat4 projection;
213
- mat4 view;
214
- } window;
215
-
216
- void main()
217
- {
218
- gl_Position = window.projection * window.view * vec4(position, 1.0);
219
-
220
- texture_coords = tex_coords;
221
- }
222
- """
223
-
224
- _blit_fragment_source: str = """#version 330 core
225
- in vec3 texture_coords;
226
- out vec4 final_colors;
227
-
228
- uniform sampler2D our_texture;
229
-
230
- void main()
231
- {
232
- final_colors = texture(our_texture, texture_coords.xy);
233
- }
234
- """
235
-
236
- def get_default_batch() -> Batch:
237
- """Batch used globally for objects that have no Batch specified."""
238
- try:
239
- return pyglet.gl.current_context.pyglet_graphics_default_batch
240
- except AttributeError:
241
- pyglet.gl.current_context.pyglet_graphics_default_batch = Batch()
242
- return pyglet.gl.current_context.pyglet_graphics_default_batch
243
-
244
-
245
- def get_default_shader() -> ShaderProgram:
246
- """A default basic shader for default batches."""
247
- try:
248
- return pyglet.gl.current_context.object_space.pyglet_graphics_default_shader
249
- except AttributeError:
250
- _vertex_shader = shader.Shader(_vertex_source, 'vertex')
251
- _fragment_shader = shader.Shader(_fragment_source, 'fragment')
252
- _shader_program = shader.ShaderProgram(_vertex_shader, _fragment_shader)
253
- pyglet.gl.current_context.object_space.pyglet_graphics_default_shader = _shader_program
254
- return pyglet.gl.current_context.object_space.pyglet_graphics_default_shader
255
-
256
- def get_default_blit_shader() -> ShaderProgram:
257
- """A default basic shader for blitting, provides no blending."""
258
- try:
259
- return pyglet.gl.current_context.object_space.pyglet_graphics_default_blit_shader
260
- except AttributeError:
261
- _vertex_shader = shader.Shader(_blit_vertex_source, 'vertex')
262
- _fragment_shader = shader.Shader(_blit_fragment_source, 'fragment')
263
- _shader_program = shader.ShaderProgram(_vertex_shader, _fragment_shader)
264
- pyglet.gl.current_context.object_space.pyglet_graphics_default_blit_shader = _shader_program
265
- return pyglet.gl.current_context.object_space.pyglet_graphics_default_blit_shader
266
-
267
- _domain_class_map: dict[tuple[bool, bool], type[vertexdomain.VertexDomain]] = {
268
- # Indexed, Instanced : Domain
269
- (False, False): vertexdomain.VertexDomain,
270
- (True, False): vertexdomain.IndexedVertexDomain,
271
- (False, True): vertexdomain.InstancedVertexDomain,
272
- (True, True): vertexdomain.InstancedIndexedVertexDomain,
273
- }
274
-
275
- DomainKey = Tuple[bool, int, int, str]
276
-
277
- class Batch:
278
- """Manage a collection of drawables for batched rendering.
279
-
280
- Many drawable pyglet objects accept an optional `Batch` argument in their
281
- constructors. By giving a `Batch` to multiple objects, you can tell pyglet
282
- that you expect to draw all of these objects at once, so it can optimise its
283
- use of OpenGL. Hence, drawing a `Batch` is often much faster than drawing
284
- each contained drawable separately.
285
-
286
- The following example creates a batch, adds two sprites to the batch, and
287
- then draws the entire batch::
288
-
289
- batch = pyglet.graphics.Batch()
290
- car = pyglet.sprite.Sprite(car_image, batch=batch)
291
- boat = pyglet.sprite.Sprite(boat_image, batch=batch)
292
-
293
- def on_draw():
294
- batch.draw()
295
-
296
- While any drawables can be added to a `Batch`, only those with the same
297
- draw mode, shader program, and group can be optimised together.
298
-
299
- Internally, a `Batch` manages a set of VertexDomains along with
300
- information about how the domains are to be drawn. To implement batching on
301
- a custom drawable, get your vertex domains from the given batch instead of
302
- setting them up yourself.
303
- """
304
- _draw_list: list[Callable]
305
- top_groups: list[Group]
306
- group_children: dict[Group, list[Group]]
307
- group_map: dict[Group, dict[DomainKey, vertexdomain.VertexDomain]]
308
-
309
- def __init__(self) -> None:
310
- """Create a graphics batch."""
311
- # Mapping to find domain.
312
- # group -> (attributes, mode, indexed) -> domain
313
- self.group_map = {}
314
-
315
- # Mapping of group to list of children.
316
- self.group_children = {}
317
-
318
- # List of top-level groups
319
- self.top_groups = []
320
-
321
- self._draw_list = []
322
- self._draw_list_dirty = False
323
-
324
- self._context = pyglet.gl.current_context
325
-
326
- self._instance_count = 0
327
-
328
- def invalidate(self) -> None:
329
- """Force the batch to update the draw list.
330
-
331
- This method can be used to force the batch to re-compute the draw list
332
- when the ordering of groups has changed.
333
-
334
- .. versionadded:: 1.2
335
- """
336
- self._draw_list_dirty = True
337
-
338
- def update_shader(self, vertex_list: VertexList | IndexedVertexList, mode: int, group: Group,
339
- program: ShaderProgram) -> bool:
340
- """Migrate a vertex list to another domain that has the specified shader attributes.
341
-
342
- The results are undefined if `mode` is not correct or if `vertex_list`
343
- does not belong to this batch (they are not checked and will not
344
- necessarily throw an exception immediately).
345
-
346
- Args:
347
- vertex_list:
348
- A vertex list currently belonging to this batch.
349
- mode:
350
- The current GL drawing mode of the vertex list.
351
- group:
352
- The new group to migrate to.
353
- program:
354
- The new shader program to migrate to.
355
-
356
- Returns:
357
- False if the domain's no longer match. The caller should handle this scenario.
358
- """
359
- # No new attributes.
360
- attributes = program.attributes.copy()
361
-
362
- # Formats may differ (normalization) than what is declared in the shader.
363
- # Make those adjustments and attempt to get a domain.
364
- for a_name in attributes:
365
- if (a_name in vertex_list.initial_attribs and
366
- vertex_list.initial_attribs[a_name]['format'] != attributes[a_name]['format']):
367
- attributes[a_name]['format'] = vertex_list.initial_attribs[a_name]['format']
368
-
369
- domain = self.get_domain(vertex_list.indexed, vertex_list.instanced, mode, group, attributes)
370
-
371
- # TODO: Allow migration if we can restore original vertices somehow. Much faster.
372
- # If the domain's don't match, we need to re-create the vertex list. Tell caller no match.
373
- if domain != vertex_list.domain:
374
- return False
375
-
376
- return True
377
-
378
- def migrate(self, vertex_list: VertexList | IndexedVertexList, mode: int, group: Group, batch: Batch) -> None:
379
- """Migrate a vertex list to another batch and/or group.
380
-
381
- `vertex_list` and `mode` together identify the vertex list to migrate.
382
- `group` and `batch` are new owners of the vertex list after migration.
383
-
384
- The results are undefined if `mode` is not correct or if `vertex_list`
385
- does not belong to this batch (they are not checked and will not
386
- necessarily throw an exception immediately).
387
-
388
- ``batch`` can remain unchanged if only a group change is desired.
389
-
390
- Args:
391
- vertex_list:
392
- A vertex list currently belonging to this batch.
393
- mode:
394
- The current GL drawing mode of the vertex list.
395
- group:
396
- The new group to migrate to.
397
- batch:
398
- The batch to migrate to (or the current batch).
399
-
400
- """
401
- attributes = vertex_list.domain.attribute_meta
402
- domain = batch.get_domain(vertex_list.indexed, vertex_list.instanced, mode, group, attributes)
403
- vertex_list.migrate(domain)
404
-
405
- def _convert_to_instanced(self, domain: vertexdomain.VertexDomain | vertexdomain.IndexedVertexDomain,
406
- instance_attributes: Sequence[
407
- str]) -> (vertexdomain.InstancedVertexDomain |
408
- vertexdomain.InstancedIndexedVertexDomain):
409
- """Takes a domain from inside the Batch and creates a new instanced version."""
410
- # Search for the existing domain.
411
- for group, domain_map in self.group_map.items():
412
- for key, mapped_domain in domain_map.items():
413
- if domain == mapped_domain:
414
- # Set instance attributes.
415
- new_attributes = mapped_domain.attribute_meta.copy()
416
- for name, attribute_dict in new_attributes.items():
417
- if name in instance_attributes:
418
- attribute_dict['instance'] = True
419
- dindexed, dinstanced, dmode, _ = key
420
-
421
- assert dinstanced == 0, "Cannot convert an instanced domain."
422
- return self.get_domain(dindexed, True, dmode, group, new_attributes)
423
-
424
- msg = "Domain was not found and could not be converted."
425
- raise Exception(msg)
426
-
427
- def get_domain(self, indexed: bool, instanced: bool, mode: int, group: Group,
428
- attributes: dict[str, Any]) -> (
429
- vertexdomain.VertexDomain | vertexdomain.IndexedVertexDomain | vertexdomain.InstancedVertexDomain |
430
- vertexdomain.InstancedIndexedVertexDomain):
431
- """Get, or create, the vertex domain corresponding to the given arguments.
432
-
433
- mode is the render mode such as GL_LINES or GL_TRIANGLES
434
- """
435
- # Batch group
436
- if group not in self.group_map:
437
- self._add_group(group)
438
-
439
- domain_map = self.group_map[group]
440
-
441
- # If instanced, ensure a separate domain, as multiple instance sources can match the key.
442
- if instanced:
443
- self._instance_count += 1
444
- key = (indexed, self._instance_count, mode, str(attributes))
445
- else:
446
- # Find domain given formats, indices and mode
447
- key = (indexed, 0, mode, str(attributes))
448
-
449
- try:
450
- domain = domain_map[key]
451
- except KeyError:
452
- # Create domain
453
- domain = _domain_class_map[(indexed, instanced)](attributes)
454
- domain_map[key] = domain
455
- self._draw_list_dirty = True
456
-
457
- return domain
458
-
459
- def _add_group(self, group: Group) -> None:
460
- self.group_map[group] = {}
461
- if group.parent is None:
462
- self.top_groups.append(group)
463
- else:
464
- if group.parent not in self.group_map:
465
- self._add_group(group.parent)
466
- if group.parent not in self.group_children:
467
- self.group_children[group.parent] = []
468
- self.group_children[group.parent].append(group)
469
-
470
- group._assigned_batches.add(self) # noqa: SLF001
471
- self._draw_list_dirty = True
472
-
473
- def _update_draw_list(self) -> None:
474
- """Visit group tree in preorder and create a list of bound methods to call."""
475
-
476
- def visit(group: Group) -> list:
477
- draw_list = []
478
-
479
- # Draw domains using this group
480
- domain_map = self.group_map[group]
481
-
482
- # indexed, instanced, mode, program, str(attributes))
483
- for (indexed, instanced, mode, formats), domain in list(domain_map.items()):
484
- # Remove unused domains from batch
485
- if domain.is_empty:
486
- del domain_map[(indexed, instanced, mode, formats)]
487
- continue
488
- draw_list.append((lambda d, m: lambda: d.draw(m))(domain, mode)) # noqa: PLC3002
489
-
490
- # Sort and visit child groups of this group
491
- children = self.group_children.get(group)
492
- if children:
493
- children.sort()
494
- for child in list(children):
495
- if child.visible:
496
- draw_list.extend(visit(child))
497
-
498
- if children or domain_map:
499
- return [group.set_state, *draw_list, group.unset_state]
500
-
501
- # Remove unused group from batch
502
- del self.group_map[group]
503
- group._assigned_batches.remove(self) # noqa: SLF001
504
- if group.parent:
505
- self.group_children[group.parent].remove(group)
506
- try:
507
- del self.group_children[group]
508
- except KeyError:
509
- pass
510
- try:
511
- self.top_groups.remove(group)
512
- except ValueError:
513
- pass
514
-
515
- return []
516
-
517
- self._draw_list = []
518
-
519
- self.top_groups.sort()
520
- for top_group in list(self.top_groups):
521
- if top_group.visible:
522
- self._draw_list.extend(visit(top_group))
523
-
524
- self._draw_list_dirty = False
525
-
526
- if _debug_graphics_batch:
527
- self._dump_draw_list()
528
-
529
- def _dump_draw_list(self) -> None:
530
- def dump(group: Group, indent: str = '') -> None:
531
- print(indent, 'Begin group', group)
532
- domain_map = self.group_map[group]
533
- for domain in domain_map.values():
534
- print(indent, ' ', domain)
535
- for start, size in zip(*domain.allocator.get_allocated_regions()):
536
- print(indent, ' ', 'Region %d size %d:' % (start, size))
537
- for key, buffer in domain.attrib_name_buffers.items():
538
- print(indent, ' ', end=' ')
539
- try:
540
- region = buffer.get_region(start, size)
541
- print(key, region.array[:])
542
- except: # noqa: E722
543
- print(key, '(unmappable)')
544
- for child in self.group_children.get(group, ()):
545
- dump(child, indent + ' ')
546
- print(indent, 'End group', group)
547
-
548
- print(f'Draw list for {self!r}:')
549
- for group in self.top_groups:
550
- dump(group)
551
-
552
- def draw(self) -> None:
553
- """Draw the batch."""
554
- if self._draw_list_dirty:
555
- self._update_draw_list()
556
-
557
- for func in self._draw_list:
558
- func()
559
-
560
- def draw_subset(self, vertex_lists: Sequence[VertexList | IndexedVertexList]) -> None:
561
- """Draw only some vertex lists in the batch.
562
-
563
- The use of this method is highly discouraged, as it is quite
564
- inefficient. Usually an application can be redesigned so that batches
565
- can always be drawn in their entirety, using `draw`.
566
-
567
- The given vertex lists must belong to this batch; behaviour is
568
- undefined if this condition is not met.
569
-
570
- Args:
571
- vertex_lists:
572
- Vertex lists to draw.
573
-
574
- """
575
-
576
- # Horrendously inefficient.
577
- def visit(group: Group) -> None:
578
- group.set_state()
579
-
580
- # Draw domains using this group
581
- domain_map = self.group_map[group]
582
- for (_, _, mode, _, _), domain in domain_map.items():
583
- for alist in vertex_lists:
584
- if alist.domain is domain:
585
- alist.draw(mode)
586
-
587
- # Sort and visit child groups of this group
588
- children = self.group_children.get(group)
589
- if children:
590
- children.sort()
591
- for child in children:
592
- if child.visible:
593
- visit(child)
594
-
595
- group.unset_state()
596
-
597
- self.top_groups.sort()
598
- for top_group in self.top_groups:
599
- if top_group.visible:
600
- visit(top_group)
601
-
602
-
603
- class Group:
604
- """Group of common OpenGL state.
605
-
606
- ``Group`` provides extra control over how drawables are handled within a
607
- ``Batch``. When a batch draws a drawable, it ensures its group's state is set;
608
- this can include binding textures, shaders, or setting any other parameters.
609
- It also sorts the groups before drawing.
610
-
611
- In the following example, the background sprite is guaranteed to be drawn
612
- before the car and the boat::
613
-
614
- batch = pyglet.graphics.Batch()
615
- background = pyglet.graphics.Group(order=0)
616
- foreground = pyglet.graphics.Group(order=1)
617
-
618
- background = pyglet.sprite.Sprite(background_image, batch=batch, group=background)
619
- car = pyglet.sprite.Sprite(car_image, batch=batch, group=foreground)
620
- boat = pyglet.sprite.Sprite(boat_image, batch=batch, group=foreground)
621
-
622
- def on_draw():
623
- batch.draw()
624
- """
625
-
626
- def __init__(self, order: int = 0, parent: Group | None = None) -> None:
627
- """Initialize a rendering group.
628
-
629
- Args:
630
- order:
631
- Set the order to render above or below other Groups.
632
- Lower orders are drawn first.
633
- parent:
634
- Group to contain this Group; its state will be set before this Group's state.
635
- """
636
- self._order = order
637
- self.parent = parent
638
- self._visible = True
639
- self._assigned_batches = weakref.WeakSet()
640
-
641
- @property
642
- def order(self) -> int:
643
- """Rendering order of this group compared to others.
644
-
645
- Lower numbers are drawn first.
646
- """
647
- return self._order
648
-
649
- @property
650
- def visible(self) -> bool:
651
- """Visibility of the group in the rendering pipeline.
652
-
653
- Determines whether this Group is visible in any of the Batches
654
- it is assigned to. If ``False``, objects in this Group will not
655
- be rendered.
656
- """
657
- return self._visible
658
-
659
- @visible.setter
660
- def visible(self, value: bool) -> None:
661
- self._visible = value
662
-
663
- for batch in self._assigned_batches:
664
- batch.invalidate()
665
-
666
- @property
667
- def batches(self) -> tuple[Batch, ...]:
668
- """Which graphics Batches this Group is a part of.
669
-
670
- Read Only.
671
- """
672
- return tuple(self._assigned_batches)
673
-
674
- def __lt__(self, other: Group) -> bool:
675
- return self._order < other.order
676
-
677
- def __eq__(self, other: Group) -> bool:
678
- """Comparison function used to determine if another Group is providing the same state.
679
-
680
- When the same state is determined, those groups will be consolidated into one draw call.
681
-
682
- If subclassing, then care must be taken to ensure this function can compare to another of the same group.
683
-
684
- :see: ``__hash__`` function, both must be implemented.
685
- """
686
- return (self.__class__ is other.__class__ and
687
- self._order == other.order and
688
- self.parent == other.parent)
689
-
690
- def __hash__(self) -> int:
691
- """This is an immutable return to establish the permanent identity of the object.
692
-
693
- This is used by Python with ``__eq__`` to determine if something is unique.
694
-
695
- For simplicity, the hash should be a tuple containing your unique identifiers of your Group.
696
-
697
- By default, this is (``order``, ``parent``).
698
-
699
- :see: ``__eq__`` function, both must be implemented.
700
- """
701
- return hash((self._order, self.parent))
702
-
703
- def __repr__(self) -> str:
704
- return f"{self.__class__.__name__}(order={self._order})"
705
-
706
- def set_state(self) -> None:
707
- """Apply the OpenGL state change.
708
-
709
- The default implementation does nothing.
710
- """
711
-
712
- def unset_state(self) -> None:
713
- """Repeal the OpenGL state change.
714
-
715
- The default implementation does nothing.
716
- """
717
-
718
- def set_state_recursive(self) -> None:
719
- """Set this group and its ancestry.
720
-
721
- Call this method if you are using a group in isolation: the
722
- parent groups will be called in top-down order, with this class's
723
- ``set`` being called last.
724
- """
725
- if self.parent:
726
- self.parent.set_state_recursive()
727
- self.set_state()
728
-
729
- def unset_state_recursive(self) -> None:
730
- """Unset this group and its ancestry.
731
-
732
- The inverse of ``set_state_recursive``.
733
- """
734
- self.unset_state()
735
- if self.parent:
736
- self.parent.unset_state_recursive()
737
-
738
-
739
- # Example Groups.
740
-
741
- class ShaderGroup(Group):
742
- """A group that enables and binds a ShaderProgram."""
743
-
744
- def __init__(self, program: ShaderProgram, order: int = 0, parent: Group | None = None) -> None: # noqa: D107
745
- super().__init__(order, parent)
746
- self.program = program
747
-
748
- def set_state(self) -> None:
749
- self.program.use()
750
-
751
- def unset_state(self) -> None:
752
- self.program.stop()
753
-
754
- def __eq__(self, other: ShaderGroup) -> bool:
755
- return (self.__class__ is other.__class__ and
756
- self._order == other.order and
757
- self.program == other.program and
758
- self.parent == other.parent)
759
-
760
- def __hash__(self) -> int:
761
- return hash((self._order, self.parent, self.program))
762
-
763
-
764
- class TextureGroup(Group):
765
- """A group that enables and binds a texture.
766
-
767
- TextureGroups are equal if their textures' targets and names are equal.
768
- """
769
-
770
- def __init__(self, texture: pyglet.image.Texture, order: int = 0, parent: Group | None = None) -> None:
771
- """Create a texture group.
772
-
773
- Args:
774
- texture:
775
- Texture to bind.
776
- order:
777
- Change the order to render above or below other Groups.
778
- parent:
779
- Parent group.
780
- """
781
- super().__init__(order, parent)
782
- self.texture = texture
783
-
784
- def set_state(self) -> None:
785
- glActiveTexture(GL_TEXTURE0)
786
- glBindTexture(self.texture.target, self.texture.id)
787
-
788
- def __hash__(self) -> int:
789
- return hash((self.texture.target, self.texture.id, self.order, self.parent))
790
-
791
- def __eq__(self, other: TextureGroup) -> bool:
792
- return (self.__class__ is other.__class__ and
793
- self.texture.target == other.texture.target and
794
- self.texture.id == other.texture.id and
795
- self.order == other.order and
796
- self.parent == other.parent)
797
-
798
- def __repr__(self) -> str:
799
- return f'{self.__class__.__name__}(id={self.texture.id})'