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,703 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+ from typing import Iterator, Literal, TYPE_CHECKING
5
+
6
+ import pyglet
7
+ from pyglet.enums import AddressMode, ComponentFormat, TextureFilter, TextureType
8
+ from pyglet.image.base import (
9
+ _AbstractImage,
10
+ _AbstractImageSequence,
11
+ ImageData,
12
+ ImageDataRegion,
13
+ ImageException,
14
+ ImageGrid,
15
+ _AbstractGrid,
16
+ CompressionFormat,
17
+ )
18
+
19
+ if TYPE_CHECKING:
20
+ from pyglet.graphics.api.base import SurfaceContext
21
+
22
+
23
+ class TextureArraySizeExceeded(ImageException):
24
+ """Exception occurs ImageData dimensions are larger than the array supports."""
25
+
26
+
27
+ class TextureArrayDepthExceeded(ImageException):
28
+ """Exception occurs when depth has hit the maximum supported of the array."""
29
+
30
+
31
+ class TextureSequence(_AbstractImageSequence):
32
+ """Interface for a sequence of textures.
33
+
34
+ Typical implementations store multiple :py:class:`~pyglet.graphics.TextureRegion`s
35
+ within one :py:class:`~pyglet.graphics.Texture` to minimise state changes.
36
+ """
37
+
38
+ def __getitem__(self, item) -> TextureBase:
39
+ raise NotImplementedError
40
+
41
+ def __setitem__(self, item, texture: type[TextureBase]) -> _AbstractImage:
42
+ raise NotImplementedError
43
+
44
+ def __len__(self) -> int:
45
+ raise NotImplementedError
46
+
47
+ def __iter__(self) -> Iterator[TextureBase]:
48
+ raise NotImplementedError
49
+
50
+ def get_texture_sequence(self) -> TextureSequence:
51
+ return self
52
+
53
+
54
+ class TextureBase(_AbstractImage):
55
+ """An image loaded into GPU memory.
56
+
57
+ Typically, you will get an instance of Texture by accessing calling
58
+ the ``get_texture()`` method of any AbstractImage class (such as ImageData).
59
+ """
60
+
61
+ region_class: TextureRegionBase # Set to TextureRegion after it's defined
62
+ """The class to use when constructing regions of this texture.
63
+ The class should be a subclass of TextureRegion.
64
+ """
65
+
66
+ tex_coords = (0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0)
67
+ """12-tuple of float, named (u1, v1, r1, u2, v2, r2, ...).
68
+ ``u, v, r`` give the 3D texture coordinates for vertices 1-4. The vertices
69
+ are specified in the order bottom-left, bottom-right, top-right and top-left.
70
+ """
71
+
72
+ tex_coords_order: tuple[int, int, int, int] = (0, 1, 2, 3)
73
+ """The default vertex winding order for a quad.
74
+ This defaults to counter-clockwise, starting at the bottom-left.
75
+ """
76
+
77
+ target: int
78
+ """The GL texture target (e.g., ``GL_TEXTURE_2D``)."""
79
+
80
+ level: int = 0
81
+ """The mipmap level of this texture."""
82
+
83
+ images = 1
84
+
85
+ default_filters: TextureFilter | tuple[TextureFilter, TextureFilter] = TextureFilter.LINEAR, TextureFilter.LINEAR
86
+ """The default minification and magnification filters, as a tuple.
87
+ Both default to LINEAR. If a texture is created without specifying
88
+ a filter, these defaults will be used.
89
+ """
90
+
91
+ x: int = 0
92
+ y: int = 0
93
+ z: int = 0
94
+
95
+ def __init__(self, width: int, height: int, tex_id: int,
96
+ tex_type: TextureType = TextureType.TYPE_2D,
97
+ internal_format: ComponentFormat = ComponentFormat.RGBA,
98
+ internal_format_size: int = 8,
99
+ internal_format_type: str = "b",
100
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
101
+ address_mode: AddressMode = AddressMode.REPEAT,
102
+ anisotropic_level: int = 0,
103
+ ) -> None:
104
+ super().__init__(width, height)
105
+ self.id = tex_id
106
+ self.tex_type = tex_type
107
+
108
+ # Use class defaults if None:
109
+ filters = filters or self.default_filters
110
+
111
+ if isinstance(filters, TextureFilter):
112
+ self.min_filter = filters
113
+ self.mag_filter = filters
114
+ else:
115
+ self.min_filter, self.mag_filter = filters
116
+
117
+ self.address_mode = address_mode
118
+ self.internal_format = internal_format
119
+ self.internal_format_size = internal_format_size
120
+ self.internal_format_type = internal_format_type
121
+ self.anisotropic_level = anisotropic_level
122
+
123
+ def delete(self) -> None:
124
+ """Delete this texture and the memory it occupies.
125
+
126
+ Textures are invalid after deletion, and may no longer be used.
127
+ """
128
+ self.id = None
129
+
130
+ #def __del__(self):
131
+ # raise NotImplementedError
132
+
133
+ def bind(self, texture_unit: int = 0) -> None:
134
+ """Bind to a specific Texture Unit by number."""
135
+ raise NotImplementedError
136
+
137
+ # def bind_image_texture(self, unit: int, level: int = 0, layered: bool = False,
138
+ # layer: int = 0, access: int = GL_READ_WRITE, fmt: int = GL_RGBA32F):
139
+ # """Bind as an ImageTexture for use with a :py:class:`~pyglet.shader.ComputeShaderProgram`.
140
+ #
141
+ # .. note:: OpenGL 4.3, or 4.2 with the GL_ARB_compute_shader extention is required.
142
+ # """
143
+ # raise NotImplementedError
144
+
145
+ @classmethod
146
+ def create(cls, width: int, height: int,
147
+ tex_type: TextureType = TextureType.TYPE_2D,
148
+ internal_format: ComponentFormat = ComponentFormat.RGBA,
149
+ data_type: str = "b",
150
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
151
+ address_mode: AddressMode = AddressMode.REPEAT,
152
+ anisotropic_level: int = 0,
153
+ blank_data: bool = True,
154
+ context: SurfaceContext | None = None) -> TextureBase:
155
+ """Create a Texture.
156
+
157
+ Create a Texture with the specified dimensions, target and format.
158
+ On return, the texture will be bound.
159
+
160
+ Args:
161
+ width:
162
+ Width of texture in pixels.
163
+ height:
164
+ Height of texture in pixels.
165
+ tex_type:
166
+ The type of texture.
167
+ internal_format:
168
+ The components of the internal format.
169
+ data_type:
170
+ The data type of the internal format, as a struct string value.
171
+ filters:
172
+ The texture filter for the min and mag filters. If a single value is passed, both values will
173
+ be used as the filter.
174
+ address_mode:
175
+ The wrapping address mode of the texture.
176
+ anisotropic_level:
177
+ The anisotropic level of the texture.
178
+ blank_data:
179
+ If True, initialize the texture data with all zeros. If False, do not pass initial data.
180
+ context:
181
+ If multiple contexts are being used, a specified context the texture is tied to.
182
+ """
183
+ raise NotImplementedError
184
+
185
+ @classmethod
186
+ def create_from_image(cls, image_data: ImageData | ImageDataRegion,
187
+ tex_type: TextureType = TextureType.TYPE_2D,
188
+ internal_format_size: int = 8,
189
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
190
+ address_mode: AddressMode = AddressMode.REPEAT,
191
+ anisotropic_level: int = 0,
192
+ context: SurfaceContext | None = None,
193
+ ) -> TextureBase:
194
+ """Create a Texture from image data.
195
+
196
+ On return, the texture will be bound.
197
+
198
+ Args:
199
+ image_data:
200
+ The image instance.
201
+ tex_type:
202
+ The type of texture.
203
+ internal_format_size:
204
+ The bit size of the internal format.
205
+ filters:
206
+ The texture filter for the min and mag filters. If a single value is passed, both values will
207
+ be used as the filter.
208
+ address_mode:
209
+ The wrapping address mode of the texture.
210
+ anisotropic_level:
211
+ The anisotropic level of the texture.
212
+ context:
213
+ If multiple contexts are being used, a specified context the texture will be tied to.
214
+ """
215
+
216
+ def get_image_data(self, z: int = 0) -> ImageData:
217
+ """To be removed and replaced with fetch."""
218
+ raise NotImplementedError
219
+
220
+ def get_texture(self) -> TextureBase:
221
+ return self
222
+
223
+ def blit(self, x: int, y: int, z: int = 0, width: int | None = None, height: int | None = None) -> None:
224
+ """Blit the texture to the screen.
225
+
226
+ Removed as of 3.0. Instead, consider creating a :py:class:`~pyglet.sprite.Sprite` with the Texture,
227
+ and drawing it as part of a larger :py:class:`~pyglet.graphics.Batch`.
228
+ """
229
+ raise NotImplementedError("This method has been removed. See the 3.0 migration documentation.")
230
+
231
+ def fetch(self, z: int = 0) -> ImageData:
232
+ """Fetch the image data of this texture by reading pixel data back from the GPU.
233
+
234
+ This can be a somewhat costly operation.
235
+
236
+ Modifying the returned ImageData object has no effect on the
237
+ texture itself. Uploading ImageData back to the GPU/texture
238
+ can be done with the :py:meth:`~Texture.upload` method.
239
+
240
+ Args:
241
+ z:
242
+ For 3D textures, the image slice to retrieve.
243
+ """
244
+ raise NotImplementedError
245
+
246
+ def get_mipmapped_texture(self) -> TextureBase:
247
+ raise NotImplementedError(f"Not implemented for {self}.")
248
+
249
+ def upload(self, image: ImageData | ImageDataRegion, x: int, y: int, z: int) -> None:
250
+ """Upload image data into the Texture at specific coordinates.
251
+
252
+ You must have this texture bound before uploading data.
253
+
254
+ The image's anchor point will be aligned to the given ``x`` and ``y``
255
+ coordinates. If this texture is a 3D texture, the ``z``
256
+ parameter gives the image slice to blit into.
257
+ """
258
+ raise NotImplementedError(f"Not implemented for {self}")
259
+
260
+ def get_region(self, x: int, y: int, width: int, height: int) -> TextureRegionBase:
261
+ return self.region_class(x, y, 0, width, height, self)
262
+
263
+ def get_transform(self, flip_x: bool = False, flip_y: bool = False,
264
+ rotate: Literal[0, 90, 180, 270, 360] = 0) -> TextureRegionBase:
265
+ """Create a copy of this image applying a simple transformation.
266
+
267
+ The transformation is applied to the texture coordinates only;
268
+ :py:meth:`~pyglet.image.AbstractImage.get_image_data` will return the
269
+ untransformed data. The transformation is applied around the anchor point.
270
+
271
+ Args:
272
+ flip_x:
273
+ If True, the returned image will be flipped horizontally.
274
+ flip_y:
275
+ If True, the returned image will be flipped vertically.
276
+ rotate:
277
+ Degrees of clockwise rotation of the returned image. Only
278
+ 90-degree increments are supported.
279
+ """
280
+ transform = self.get_region(0, 0, self.width, self.height)
281
+ bl, br, tr, tl = 0, 1, 2, 3
282
+ transform.anchor_x = self.anchor_x
283
+ transform.anchor_y = self.anchor_y
284
+ if flip_x:
285
+ bl, br, tl, tr = br, bl, tr, tl
286
+ transform.anchor_x = self.width - self.anchor_x
287
+ if flip_y:
288
+ bl, br, tl, tr = tl, tr, bl, br
289
+ transform.anchor_y = self.height - self.anchor_y
290
+ rotate %= 360
291
+ if rotate < 0:
292
+ rotate += 360
293
+ if rotate == 0:
294
+ pass
295
+ elif rotate == 90:
296
+ bl, br, tr, tl = br, tr, tl, bl
297
+ transform.anchor_x, transform.anchor_y = transform.anchor_y, transform.width - transform.anchor_x
298
+ elif rotate == 180:
299
+ bl, br, tr, tl = tr, tl, bl, br
300
+ transform.anchor_x = transform.width - transform.anchor_x
301
+ transform.anchor_y = transform.height - transform.anchor_y
302
+ elif rotate == 270:
303
+ bl, br, tr, tl = tl, bl, br, tr
304
+ transform.anchor_x, transform.anchor_y = transform.height - transform.anchor_y, transform.anchor_x
305
+ else:
306
+ raise ImageException("Only 90 degree rotations are supported.")
307
+ if rotate in (90, 270):
308
+ transform.width, transform.height = transform.height, transform.width
309
+ transform._set_tex_coords_order(bl, br, tr, tl)
310
+ return transform
311
+
312
+ def _set_tex_coords_order(self, bl, br, tr, tl):
313
+ tex_coords = (self.tex_coords[:3],
314
+ self.tex_coords[3:6],
315
+ self.tex_coords[6:9],
316
+ self.tex_coords[9:])
317
+ self.tex_coords = tex_coords[bl] + tex_coords[br] + tex_coords[tr] + tex_coords[tl]
318
+
319
+ order = self.tex_coords_order
320
+ self.tex_coords_order = (order[bl], order[br], order[tr], order[tl])
321
+
322
+ @property
323
+ def uv(self) -> tuple[float, float, float, float]:
324
+ """Tuple containing the left, bottom, right, top 2D texture coordinates."""
325
+ tex_coords = self.tex_coords
326
+ return tex_coords[0], tex_coords[1], tex_coords[3], tex_coords[7]
327
+
328
+ @property
329
+ def filters(self) -> tuple[TextureFilter, TextureFilter]:
330
+ """The current Texture filters.
331
+
332
+ Providing a single TextureFilter will adjust both minification and magnification filters. Otherwise, a tuple
333
+ can be provided to adjust each individually.
334
+ """
335
+ return self.min_filter, self.mag_filter
336
+
337
+
338
+ def __repr__(self) -> str:
339
+ return f"{self.__class__.__name__}(id={self.id}, size={self.width}x{self.height})"
340
+
341
+
342
+ class TextureRegionBase(TextureBase):
343
+ """A rectangular region of a texture, presented as if it were a separate texture."""
344
+
345
+ def __init__(self, x: int, y: int, z: int, width: int, height: int, owner: TextureBase):
346
+ super().__init__(width, height, owner.id, owner.tex_type, owner.internal_format,
347
+ owner.internal_format_size, owner.internal_format_type, owner.filters, owner.address_mode,
348
+ owner.anisotropic_level)
349
+
350
+ self.x = x
351
+ self.y = y
352
+ self.z = z
353
+ self._width = width
354
+ self._height = height
355
+ self.owner = owner
356
+ owner_u1 = owner.tex_coords[0]
357
+ owner_v1 = owner.tex_coords[1]
358
+ owner_u2 = owner.tex_coords[3]
359
+ owner_v2 = owner.tex_coords[7]
360
+ scale_u = owner_u2 - owner_u1
361
+ scale_v = owner_v2 - owner_v1
362
+ u1 = x / owner.width * scale_u + owner_u1
363
+ v1 = y / owner.height * scale_v + owner_v1
364
+ u2 = (x + width) / owner.width * scale_u + owner_u1
365
+ v2 = (y + height) / owner.height * scale_v + owner_v1
366
+ r = z / owner.images + owner.tex_coords[2]
367
+ self.tex_coords = (u1, v1, r, u2, v1, r, u2, v2, r, u1, v2, r)
368
+ raise Exception
369
+
370
+ def fetch(self, _z = 0) -> ImageDataRegion:
371
+ image_data = self.owner.get_image_data(self.z)
372
+ return image_data.get_region(self.x, self.y, self.width, self.height)
373
+
374
+ def get_image_data(self) -> ImageDataRegion:
375
+ return self.fetch()
376
+
377
+ def get_region(self, x: int, y: int, width: int, height: int) -> TextureRegionBase:
378
+ x += self.x
379
+ y += self.y
380
+ region = self.region_class(x, y, self.z, width, height, self.owner)
381
+ region._set_tex_coords_order(*self.tex_coords_order)
382
+ return region
383
+
384
+ def upload(self, source: ImageData, x: int, y: int, z: int) -> None:
385
+ assert source.width <= self._width and source.height <= self._height, f"{source} is larger than {self}"
386
+ self.owner.upload(source, x + self.x, y + self.y, z + self.z)
387
+
388
+ def __repr__(self) -> str:
389
+ return (f"{self.__class__.__name__}(id={self.id},"
390
+ f" size={self.width}x{self.height}, owner={self.owner.width}x{self.owner.height})")
391
+
392
+ def delete(self) -> None:
393
+ """Deleting a TextureRegion has no effect. Operate on the owning texture instead."""
394
+
395
+ def __del__(self):
396
+ pass
397
+
398
+
399
+ class UniformTextureSequence(TextureSequence):
400
+ """Interface for a sequence of textures, each with the same dimensions."""
401
+
402
+
403
+ class TextureArrayRegionBase(TextureRegionBase):
404
+ """A region of a TextureArray, presented as if it were a separate texture."""
405
+
406
+ def __repr__(self):
407
+ return f"{self.__class__.__name__}(id={self.id}, size={self.width}x{self.height}, layer={self.z})"
408
+
409
+
410
+ class TextureArrayBase(TextureBase, UniformTextureSequence):
411
+ def __init__(self, width, height, tex_id, max_depth,
412
+ internal_format: ComponentFormat = ComponentFormat.RGBA,
413
+ internal_format_size: int = 8,
414
+ internal_format_type: str = "b",
415
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
416
+ address_mode: AddressMode = AddressMode.REPEAT,
417
+ anisotropic_level: int = 0,
418
+ ):
419
+ super().__init__(width, height, tex_id, TextureType.TYPE_2D_ARRAY, internal_format, internal_format_size,
420
+ internal_format_type, filters, address_mode, anisotropic_level)
421
+ self.max_depth = max_depth
422
+ self.items = []
423
+
424
+ @classmethod
425
+ def create(cls, width: int, height: int,
426
+ internal_format: ComponentFormat = ComponentFormat.RGBA,
427
+ internal_format_size: int = 8,
428
+ internal_format_type: str = "b",
429
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
430
+ address_mode: AddressMode = AddressMode.REPEAT,
431
+ anisotropic_level: int = 0,
432
+ max_depth: int = 256) -> TextureArray:
433
+ """Create an empty TextureArray.
434
+
435
+ You may specify the maximum depth, or layers, the Texture Array should have. This defaults
436
+ to 256, but will be hardware and driver dependent.
437
+
438
+ Args:
439
+ width:
440
+ Width of the texture.
441
+ height:
442
+ Height of the texture.
443
+ descriptor:
444
+ Texture description.
445
+ max_depth:
446
+ The number of layers in the texture array.
447
+
448
+ .. versionadded:: 2.0
449
+ """
450
+ raise NotImplementedError
451
+
452
+ def _verify_size(self, image: _AbstractImage) -> None:
453
+ if image.width > self.width or image.height > self.height:
454
+ raise TextureArraySizeExceeded(
455
+ f'Image ({image.width}x{image.height}) exceeds the size of the TextureArray ({self.width}x'
456
+ f'{self.height})')
457
+
458
+ def add(self, image: ImageData) -> TextureArrayRegion:
459
+ if len(self.items) >= self.max_depth:
460
+ raise TextureArrayDepthExceeded("TextureArray is full.")
461
+
462
+ self._verify_size(image)
463
+ start_length = len(self.items)
464
+ item = self.region_class(0, 0, start_length, image.width, image.height, self)
465
+
466
+ self.blit_into(image, image.anchor_x, image.anchor_y, start_length)
467
+ self.items.append(item)
468
+ return item
469
+
470
+ def allocate(self, *images: _AbstractImage) -> list[TextureArrayRegion]:
471
+ """Allocates multiple images at once."""
472
+ raise NotImplementedError
473
+
474
+ @classmethod
475
+ @abstractmethod
476
+ def create_for_image_grid(cls, grid) -> TextureArray:
477
+ ...
478
+
479
+ def __len__(self) -> int:
480
+ return len(self.items)
481
+
482
+ def __getitem__(self, index) -> TextureArrayRegion:
483
+ return self.items[index]
484
+
485
+ def __setitem__(self, index, value) -> None:
486
+ raise NotImplementedError
487
+
488
+ def __iter__(self) -> Iterator[TextureRegionBase]:
489
+ return iter(self.items)
490
+
491
+
492
+ class Texture3D(TextureBase, UniformTextureSequence):
493
+ """A texture with more than one image slice.
494
+
495
+ Use the :py:meth:`create_for_images` or :py:meth:`create_for_image_grid`
496
+ classmethod to construct a Texture3D.
497
+ """
498
+ item_width: int = 0
499
+ item_height: int = 0
500
+ items: tuple
501
+
502
+ @classmethod
503
+ def create_for_images(cls, images,
504
+ internal_format_size: int = 8,
505
+ internal_format_type: str = "b",
506
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
507
+ address_mode: AddressMode = AddressMode.REPEAT,
508
+ anisotropic_level: int = 0, blank_data=True):
509
+ raise NotImplementedError
510
+
511
+ @classmethod
512
+ def create_for_image_grid(cls, grid,
513
+ internal_format: ComponentFormat = ComponentFormat.RGBA,
514
+ internal_format_size: int = 8,
515
+ internal_format_type: str = "b",
516
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
517
+ address_mode: AddressMode = AddressMode.REPEAT,
518
+ anisotropic_level: int = 0):
519
+ return cls.create_for_images(grid[:], internal_format, internal_format_size, internal_format_type,
520
+ filters, address_mode, anisotropic_level)
521
+
522
+ def __len__(self):
523
+ return len(self.items)
524
+
525
+ def __getitem__(self, index):
526
+ return self.items[index]
527
+
528
+ def __setitem__(self, index, value):
529
+ raise NotImplementedError
530
+
531
+ def __iter__(self) -> Iterator[TextureRegionBase]:
532
+ return iter(self.items)
533
+
534
+
535
+
536
+ class TextureGridBase(_AbstractGrid):
537
+ """A texture containing a regular grid of texture regions.
538
+
539
+ To construct, create an :py:class:`~pyglet.image.ImageGrid` first::
540
+
541
+ image_grid = ImageGrid(...)
542
+ texture_grid = TextureGrid(image_grid)
543
+
544
+ The texture grid can be accessed as a single texture, or as a sequence
545
+ of :py:class:`~pyglet.graphics.TextureRegion`. When accessing as a sequence, you can specify
546
+ integer indexes, in which the images are arranged in rows from the
547
+ bottom-left to the top-right::
548
+
549
+ # assume the texture_grid is 3x3:
550
+ current_texture = texture_grid[3] # get the middle-left image
551
+
552
+ You can also specify tuples in the sequence methods, which are addressed
553
+ as ``row, column``::
554
+
555
+ # equivalent to the previous example:
556
+ current_texture = texture_grid[1, 0]
557
+
558
+ When using tuples in a slice, the returned sequence is over the
559
+ rectangular region defined by the slice::
560
+
561
+ # returns center, center-right, center-top, top-right images in that
562
+ # order:
563
+ images = texture_grid[(1,1):]
564
+ # equivalent to
565
+ images = texture_grid[(1,1):(3,3)]
566
+
567
+ """
568
+ def __init__(self, texture: Texture | TextureRegion, rows: int, columns: int, item_width: int,
569
+ item_height: int, row_padding: int = 0, column_padding: int = 0) -> None:
570
+ """Construct a grid for the given image.
571
+
572
+ You can specify parameters for the grid, for example setting
573
+ the padding between cells. Grids are always aligned to the
574
+ bottom-left corner of the image.
575
+
576
+ Args:
577
+ texture:
578
+ A texture or region over which to construct the grid.
579
+ rows:
580
+ Number of rows in the grid.
581
+ columns:
582
+ Number of columns in the grid.
583
+ item_width:
584
+ Width of each column. If unspecified, is calculated such
585
+ that the entire texture width is used.
586
+ item_height:
587
+ Height of each row. If unspecified, is calculated such that
588
+ the entire texture height is used.
589
+ row_padding:
590
+ Pixels separating adjacent rows. The padding is only
591
+ inserted between rows, not at the edges of the grid.
592
+ column_padding:
593
+ Pixels separating adjacent columns. The padding is only
594
+ inserted between columns, not at the edges of the grid.
595
+ """
596
+ if isinstance(texture, TextureRegion):
597
+ owner = texture.owner
598
+ else:
599
+ owner = texture
600
+
601
+ item_width = item_width or (texture.width - column_padding * (columns - 1)) // columns
602
+ item_height = item_height or (texture.height - row_padding * (rows - 1)) // rows
603
+ self.texture = owner
604
+ super().__init__(rows, columns, item_width, item_height, row_padding, column_padding)
605
+
606
+ @classmethod
607
+ def from_image_grid(cls, image_grid: ImageGrid) -> TextureGridBase:
608
+ texture = image_grid.image.get_texture()
609
+ return cls(
610
+ texture,
611
+ image_grid.rows,
612
+ image_grid.columns,
613
+ image_grid.item_width,
614
+ image_grid.item_height,
615
+ image_grid.row_padding,
616
+ image_grid.column_padding,
617
+ )
618
+
619
+
620
+ TextureBase.region_class = TextureRegionBase
621
+
622
+ TextureArrayBase.region_class = TextureArrayRegionBase
623
+ TextureArrayRegionBase.region_class = TextureArrayRegionBase
624
+
625
+ class CompressedTextureBase(_AbstractImage):
626
+ tex_coords = (0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0)
627
+ """12-tuple of float, named (u1, v1, r1, u2, v2, r2, ...).
628
+ ``u, v, r`` give the 3D texture coordinates for vertices 1-4. The vertices
629
+ are specified in the order bottom-left, bottom-right, top-right and top-left.
630
+ """
631
+
632
+ tex_coords_order: tuple[int, int, int, int] = (0, 1, 2, 3)
633
+ """The default vertex winding order for a quad.
634
+ This defaults to counter-clockwise, starting at the bottom-left.
635
+ """
636
+
637
+ target: int
638
+ """The GL texture target (e.g., ``GL_TEXTURE_2D``)."""
639
+
640
+ level: int = 0
641
+ """The mipmap level of this texture."""
642
+
643
+ images = 1
644
+
645
+ x: int = 0
646
+ y: int = 0
647
+ z: int = 0
648
+
649
+ def __init__(self, width: int, height: int, tex_id: int,
650
+ compression_format: CompressionFormat,
651
+ tex_type: TextureType = TextureType.TYPE_2D,
652
+ filters: TextureFilter | tuple[TextureFilter, TextureFilter] | None = None,
653
+ address_mode: AddressMode = AddressMode.REPEAT,
654
+ anisotropic_level: int = 0,
655
+ ) -> None:
656
+ super().__init__(width, height)
657
+ self.id = tex_id
658
+ self.tex_type = tex_type
659
+
660
+ if isinstance(filters, TextureFilter):
661
+ self.min_filter = filters
662
+ self.mag_filter = filters
663
+ else:
664
+ self.min_filter, self.mag_filter = filters
665
+
666
+ self.address_mode = address_mode
667
+ self.internal_format = compression_format
668
+ self.anisotropic_level = anisotropic_level
669
+
670
+ def get_texture(self) -> CompressedTextureBase:
671
+ return self
672
+
673
+ if pyglet.options.backend in ("opengl", "gles3", "gl2", "gles2"):
674
+ from pyglet.graphics.api.gl.framebuffer import ( # noqa: F401
675
+ Framebuffer,
676
+ Renderbuffer,
677
+ get_max_color_attachments,
678
+ get_screenshot,
679
+ )
680
+ from pyglet.graphics.api.gl.texture import (
681
+ CompressedTexture, # noqa: F401
682
+ Texture,
683
+ TextureRegion,
684
+ Texture3D,
685
+ TextureArray,
686
+ TextureArrayRegion,
687
+ TextureGrid,
688
+ get_max_texture_size,
689
+ get_max_array_texture_layers,
690
+ )
691
+ elif pyglet.options.backend in ("webgl"):
692
+ from pyglet.graphics.api.webgl.texture import (
693
+ Texture,
694
+ TextureRegion,
695
+ Texture3D, # noqa: F401
696
+ TextureArray,
697
+ TextureArrayRegion,
698
+ TextureGrid, # noqa: F401
699
+ get_max_texture_size, # noqa: F401
700
+ get_max_array_texture_layers, # noqa: F401
701
+ )
702
+ elif pyglet.options.backend == "vulkan":
703
+ pass