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