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
pyglet/resource.py CHANGED
@@ -51,21 +51,21 @@ from __future__ import annotations
51
51
 
52
52
  import os
53
53
  import sys
54
- import zipfile
55
54
  import weakref
56
-
55
+ import zipfile
57
56
  from io import BytesIO, StringIO
58
- from typing import TYPE_CHECKING, IO
57
+ from typing import IO, TYPE_CHECKING
59
58
 
60
59
  import pyglet
61
60
 
62
61
  if TYPE_CHECKING:
62
+ from pyglet.graphics.texture import Texture, TextureRegion, TextureArrayRegion
63
63
  from typing import Literal
64
- from pyglet.graphics import Batch
65
- from pyglet.graphics.shader import Shader
66
- from pyglet.image import AbstractImage, Texture, TextureRegion
64
+
65
+ from pyglet.graphics import Shader
66
+ from pyglet.image import ImageData
67
67
  from pyglet.image.animation import Animation
68
- from pyglet.image.atlas import TextureBin
68
+ from pyglet.graphics.atlas import TextureBin, TextureArrayBin
69
69
  from pyglet.media.codecs import Source
70
70
  from pyglet.model import Scene
71
71
  from pyglet.text.document import AbstractDocument
@@ -74,7 +74,7 @@ if TYPE_CHECKING:
74
74
  class ResourceNotFoundException(Exception):
75
75
  """The named resource was not found on the search path."""
76
76
 
77
- def __init__(self, name):
77
+ def __init__(self, name: str) -> None:
78
78
  message = (f"Resource '{name}' was not found on the path. "
79
79
  "Ensure that the filename has the correct capitalisation.")
80
80
  Exception.__init__(self, message)
@@ -83,7 +83,7 @@ class ResourceNotFoundException(Exception):
83
83
  class UndetectableShaderType(Exception):
84
84
  """The type of the Shader source could not be identified."""
85
85
 
86
- def __init__(self, name):
86
+ def __init__(self, name: str) -> None:
87
87
  message = (f"The Shader type of '{name}' could not be determined. "
88
88
  "Ensure that your source file has a standard extension, "
89
89
  "or provide a valid 'shader_type' parameter.")
@@ -111,22 +111,19 @@ def get_script_home() -> str:
111
111
  if meipass:
112
112
  # PyInstaller
113
113
  return meipass
114
- elif frozen in ('windows_exe', 'console_exe'):
114
+ if frozen in ('windows_exe', 'console_exe'):
115
115
  return os.path.dirname(sys.executable)
116
- elif frozen == 'macosx_app':
116
+ if frozen == 'macosx_app':
117
117
  # py2app
118
118
  return os.environ['RESOURCEPATH']
119
- else:
120
- main = sys.modules['__main__']
121
- if hasattr(main, '__file__'):
122
- return os.path.dirname(os.path.abspath(main.__file__))
123
- else:
124
- if 'python' in os.path.basename(sys.executable):
125
- # interactive
126
- return os.getcwd()
127
- else:
128
- # cx_Freeze
129
- return os.path.dirname(sys.executable)
119
+ main = sys.modules['__main__']
120
+ if hasattr(main, '__file__'):
121
+ return os.path.dirname(os.path.abspath(main.__file__))
122
+ if 'python' in os.path.basename(sys.executable):
123
+ # interactive
124
+ return os.getcwd()
125
+ # cx_Freeze
126
+ return os.path.dirname(sys.executable)
130
127
 
131
128
 
132
129
  def get_settings_path(name: str) -> str:
@@ -140,7 +137,7 @@ def get_settings_path(name: str) -> str:
140
137
  returned (usually under ``~/.config``).
141
138
 
142
139
  On Windows (including under Cygwin) the ``name`` directory in the user's
143
- ``Application Settings`` directory is returned.
140
+ ``Application Settings`` (AppData) directory is returned.
144
141
 
145
142
  On Mac OS X the ``name`` directory under ``~/Library/Application Support``
146
143
  is returned.
@@ -149,20 +146,20 @@ def get_settings_path(name: str) -> str:
149
146
  should use ``os.path.exists`` and ``os.makedirs`` to construct
150
147
  the directory if desired.
151
148
  """
149
+ # In Pyodide (browser) use IDBFS-mounted directory
150
+ if sys.platform == "emscripten":
151
+ return f"/data/{name}"
152
152
  if pyglet.compat_platform in ('cygwin', 'win32'):
153
153
  if 'APPDATA' in os.environ:
154
154
  return os.path.join(os.environ['APPDATA'], name)
155
- else:
156
- return os.path.expanduser(f'~/{name}')
157
- elif pyglet.compat_platform == 'darwin':
155
+ return os.path.expanduser(f'~/{name}')
156
+ if pyglet.compat_platform == 'darwin':
158
157
  return os.path.expanduser(f'~/Library/Application Support/{name}')
159
- elif pyglet.compat_platform.startswith('linux'):
158
+ if pyglet.compat_platform.startswith('linux'):
160
159
  if 'XDG_CONFIG_HOME' in os.environ:
161
160
  return os.path.join(os.environ['XDG_CONFIG_HOME'], name)
162
- else:
163
- return os.path.expanduser(f'~/.config/{name}')
164
- else:
165
- return os.path.expanduser(f'~/.{name}')
161
+ return os.path.expanduser(f'~/.config/{name}')
162
+ return os.path.expanduser(f'~/.{name}')
166
163
 
167
164
 
168
165
  def get_data_path(name: str) -> str:
@@ -176,7 +173,7 @@ def get_data_path(name: str) -> str:
176
173
  (usually under ``~/.local/share``).
177
174
 
178
175
  On Windows (including under Cygwin) the ``name`` directory in the user's
179
- ``Application Settings`` directory is returned.
176
+ ``Application Settings`` (AppData) directory is returned.
180
177
 
181
178
  On Mac OS X the ``name`` directory under ``~/Library/Application Support``
182
179
  is returned.
@@ -185,20 +182,20 @@ def get_data_path(name: str) -> str:
185
182
  should use ``os.path.exists`` and ``os.makedirs`` to construct
186
183
  the directory if desired.
187
184
  """
185
+ # In Pyodide (browser) use IDBFS-mounted directory
186
+ if sys.platform == "emscripten":
187
+ return f"/data/{name}"
188
188
  if pyglet.compat_platform in ('cygwin', 'win32'):
189
189
  if 'APPDATA' in os.environ:
190
190
  return os.path.join(os.environ['APPDATA'], name)
191
- else:
192
- return os.path.expanduser(f'~/{name}')
193
- elif pyglet.compat_platform == 'darwin':
191
+ return os.path.expanduser(f'~/{name}')
192
+ if pyglet.compat_platform == 'darwin':
194
193
  return os.path.expanduser(f'~/Library/Application Support/{name}')
195
- elif pyglet.compat_platform.startswith('linux'):
194
+ if pyglet.compat_platform.startswith('linux'):
196
195
  if 'XDG_DATA_HOME' in os.environ:
197
196
  return os.path.join(os.environ['XDG_DATA_HOME'], name)
198
- else:
199
- return os.path.expanduser(f'~/.local/share/{name}')
200
- else:
201
- return os.path.expanduser(f'~/.{name}')
197
+ return os.path.expanduser(f'~/.local/share/{name}')
198
+ return os.path.expanduser(f'~/.{name}')
202
199
 
203
200
 
204
201
  class Location:
@@ -239,7 +236,7 @@ class FileLocation(Location):
239
236
  class ZIPLocation(Location):
240
237
  """Location within a ZIP file."""
241
238
 
242
- def __init__(self, zipfileobj: zipfile.ZipFile, directory: str | None):
239
+ def __init__(self, zipfileobj: zipfile.ZipFile, directory: str | None) -> None:
243
240
  """Create a location given an open ZIP file and a path within that file.
244
241
 
245
242
  Args:
@@ -252,7 +249,7 @@ class ZIPLocation(Location):
252
249
  self.zip = zipfileobj
253
250
  self.dir = directory
254
251
 
255
- def open(self, filename: str, mode='rb') -> BytesIO | StringIO:
252
+ def open(self, filename: str, mode: str='rb') -> BytesIO | StringIO:
256
253
  """Open a file from inside the ZipFile.
257
254
 
258
255
  Args:
@@ -268,7 +265,7 @@ class ZIPLocation(Location):
268
265
  return StringIO(_bytes.decode())
269
266
  return BytesIO(_bytes)
270
267
 
271
- def __repr__(self):
268
+ def __repr__(self) -> str:
272
269
  return f"{self.__class__.__name__}(dir='{self.dir}')"
273
270
 
274
271
 
@@ -330,13 +327,15 @@ class Loader:
330
327
 
331
328
  # Map bin size to list of atlases
332
329
  self._texture_atlas_bins = {}
330
+ self._texture_array_bins = {}
333
331
 
334
332
  # map name to image etc.
335
- self._cached_textures = weakref.WeakValueDictionary()
336
333
  self._cached_images = weakref.WeakValueDictionary()
334
+ self._cached_textures = weakref.WeakValueDictionary()
335
+ self._cached_texture_arrays = weakref.WeakValueDictionary()
337
336
  self._cached_animations = weakref.WeakValueDictionary()
338
337
 
339
- def _ensure_index(self):
338
+ def _ensure_index(self) -> None:
340
339
  if self._index is None:
341
340
  self.reindex()
342
341
 
@@ -344,7 +343,7 @@ class Loader:
344
343
  if name not in self._index:
345
344
  self._index[name] = locationobj
346
345
 
347
- def reindex(self):
346
+ def reindex(self) -> None:
348
347
  """Refresh the file index.
349
348
 
350
349
  You must call this method if ``resource.path`` is changed,
@@ -471,7 +470,7 @@ class Loader:
471
470
  fileobj = self.file(filename)
472
471
  font.add_file(fileobj)
473
472
 
474
- def _alloc_image(self, name: str, use_atlas: bool, border: int) -> AbstractImage:
473
+ def _alloc_texture(self, name: str, use_atlas: bool, border: int) -> Texture | TextureRegion:
475
474
  fileobj = self.file(name)
476
475
  try:
477
476
  img = pyglet.image.load(name, file=fileobj)
@@ -487,13 +486,24 @@ class Loader:
487
486
 
488
487
  return img.get_texture()
489
488
 
489
+ def _get_texture_array_bin(self, width: int, height: int) -> TextureArrayBin:
490
+ bin_size = (width, height)
491
+ try:
492
+ texture_array_bin = self._texture_array_bins[bin_size]
493
+ except KeyError:
494
+ texture_array_bin = pyglet.graphics.atlas.TextureArrayBin(width, height)
495
+ self._texture_array_bins[bin_size] = texture_array_bin
496
+
497
+ return texture_array_bin
498
+
490
499
  def _get_texture_atlas_bin(self, width: int, height: int, border: int) -> TextureBin | None:
491
- """A heuristic for determining the atlas bin to use for a given image
492
- size. Returns None if the image should not be placed in an atlas (too
493
- big), otherwise the bin (a list of TextureAtlas).
500
+ """A heuristic for determining the atlas bin to use for a given image size.
501
+
502
+ Returns:
503
+ None if the image should not be placed in an atlas (too big), otherwise the bin (a list of TextureAtlas).
494
504
  """
495
505
  # Large images are not placed in an atlas
496
- max_texture_size = pyglet.image.get_max_texture_size()
506
+ max_texture_size = pyglet.graphics.texture.get_max_texture_size()
497
507
  max_size = min(2048, max_texture_size) - border
498
508
  if width > max_size or height > max_size:
499
509
  return None
@@ -507,19 +517,32 @@ class Loader:
507
517
  try:
508
518
  texture_bin = self._texture_atlas_bins[bin_size]
509
519
  except KeyError:
510
- texture_bin = pyglet.image.atlas.TextureBin()
520
+ texture_bin = pyglet.graphics.atlas.TextureBin()
511
521
  self._texture_atlas_bins[bin_size] = texture_bin
512
522
 
513
523
  return texture_bin
514
524
 
515
- def image(self, name: str, flip_x: bool = False, flip_y: bool = False, rotate: Literal[0, 90, 180, 270, 360] = 0,
516
- atlas: bool = True, border: int = 1) -> Texture | TextureRegion:
517
- """Load an image with optional transformation.
525
+ def image(self, name: str) -> ImageData:
526
+ """Load an image and decode the properties associated with it.
527
+
528
+ This data is not GPU backed, and represents the raw pixel data, format, and pitch. See :py:class:`~pyglet.image.IamgeData`
529
+ """
530
+ self._ensure_index()
531
+ if name in self._cached_images:
532
+ return self._cached_images[name]
533
+
534
+ file_obj = self.file(name)
535
+ img = pyglet.image.load(name, file=file_obj)
536
+ self._cached_images[name] = img
537
+ return img
518
538
 
519
- This is similar to `texture`, except the resulting image will be
520
- packed into a :py:class:`~pyglet.image.atlas.TextureBin` (TextureAtlas)
521
- if it is an appropriate size for packing. This is more efficient than
522
- loading images into separate textures.
539
+ def texture(self, name: str, flip_x: bool = False, flip_y: bool = False, rotate: Literal[0, 90, 180, 270, 360] = 0,
540
+ atlas: bool = True, border: int = 1) -> Texture | TextureRegion:
541
+ """Loads an image into a GPU backed texture with optional transformations.
542
+
543
+ By default, the resulting texture will be packed into a
544
+ :py:class:`~pyglet.graphics.atlas.TextureBin` (TextureAtlas) if it is an appropriate size for packing.
545
+ This is more efficient than loading images into separate textures.
523
546
 
524
547
  Args:
525
548
  name:
@@ -539,15 +562,55 @@ class Loader:
539
562
  Leaves specified pixels of blank space around each image in
540
563
  an atlas, which may help reduce texture bleeding.
541
564
 
542
- .. note:: When using ``flip_x/y`` or ``rotate``, the actual image
565
+ .. note:: When using ``flip_x/y`` or ``rotate``, the actual pixel
543
566
  data is not modified. Instead, the texture coordinates
544
567
  are manipulated to produce the desired result.
545
568
  """
546
569
  self._ensure_index()
547
- if name in self._cached_images:
548
- identity = self._cached_images[name]
570
+ if name in self._cached_textures:
571
+ identity = self._cached_textures[name]
549
572
  else:
550
- identity = self._cached_images[name] = self._alloc_image(name, atlas, border)
573
+ identity = self._cached_textures[name] = self._alloc_texture(name, atlas, border)
574
+
575
+ if not rotate and not flip_x and not flip_y:
576
+ return identity
577
+
578
+ return identity.get_transform(flip_x, flip_y, rotate)
579
+
580
+ def texture_array(self, name: str, flip_x: bool = False, flip_y: bool = False,
581
+ rotate: Literal[0, 90, 180, 270, 360] = 0) -> TextureArrayRegion:
582
+ """Loads an image into a GPU backed texture array with optional transformations.
583
+
584
+ By default, the resulting texture array will be packed into a
585
+ :py:class:`~pyglet.graphics.atlas.TextureArrayBin` based on the dimensions of the loaded image.
586
+
587
+ Args:
588
+ name:
589
+ The filename of the image source to load.
590
+ flip_x:
591
+ If ``True``, the returned image will be flipped horizontally.
592
+ flip_y:
593
+ If ``True``, the returned image will be flipped vertically.
594
+ rotate:
595
+ The returned image will be rotated clockwise by the given
596
+ number of degrees (a multiple of 90).
597
+
598
+ .. note:: When using ``flip_x/y`` or ``rotate``, the actual pixel
599
+ data is not modified. Instead, the texture coordinates
600
+ are manipulated to produce the desired result.
601
+ """
602
+ self._ensure_index()
603
+ if name in self._cached_texture_arrays:
604
+ identity = self._cached_texture_arrays[name]
605
+ else:
606
+ fileobj = self.file(name)
607
+ try:
608
+ img = pyglet.image.load(name, file=fileobj)
609
+ finally:
610
+ fileobj.close()
611
+
612
+ _bin = self._get_texture_array_bin(img.width, img.height)
613
+ identity = self._cached_texture_arrays[name] = _bin.add(img)
551
614
 
552
615
  if not rotate and not flip_x and not flip_y:
553
616
  return identity
@@ -647,24 +710,12 @@ class Loader:
647
710
  # Don't open the file if it's streamed from disk
648
711
  file_path = os.path.join(file_location.path, name)
649
712
  return media.load(file_path, streaming=streaming)
650
- else:
651
- fileobj = file_location.open(name)
713
+ fileobj = file_location.open(name)
652
714
 
653
- return media.load(name, file=fileobj, streaming=streaming)
715
+ return media.load(name, file=fileobj, streaming=streaming)
654
716
  except KeyError:
655
717
  raise ResourceNotFoundException(name)
656
718
 
657
- def texture(self, name: str) -> Texture:
658
- """Load an image as a single OpenGL texture."""
659
- self._ensure_index()
660
- if name in self._cached_textures:
661
- return self._cached_textures[name]
662
-
663
- fileobj = self.file(name)
664
- textureobj = pyglet.image.load(name, file=fileobj).get_texture()
665
- self._cached_textures[name] = textureobj
666
- return textureobj
667
-
668
719
  def scene(self, name: str) -> Scene:
669
720
  """Load a 3D Scene."""
670
721
  self._ensure_index()
@@ -724,7 +775,7 @@ class Loader:
724
775
  if shader_type not in shader_extensions.values():
725
776
  raise UndetectableShaderType(name=name)
726
777
 
727
- return pyglet.graphics.shader.Shader(source_string, shader_type)
778
+ return pyglet.graphics.Shader(source_string, shader_type)
728
779
 
729
780
 
730
781
  #: Default resource search path.