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
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Callable, Sequence
|
|
4
|
+
|
|
5
|
+
import pyglet
|
|
6
|
+
from pyglet.graphics.api.webgl import vertexdomain
|
|
7
|
+
from pyglet.graphics.api.webgl.enums import geometry_map
|
|
8
|
+
from pyglet.graphics.draw import BatchBase, _DomainKey, Group
|
|
9
|
+
|
|
10
|
+
_debug_graphics_batch = pyglet.options.debug_graphics_batch
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyglet.graphics import GeometryMode
|
|
14
|
+
from pyglet.graphics.api.webgl.vertexdomain import IndexedVertexList, VertexList
|
|
15
|
+
from pyglet.graphics.api.webgl.shader import ShaderProgram
|
|
16
|
+
from pyglet.graphics.api.webgl.context import OpenGLSurfaceContext
|
|
17
|
+
from pyglet.graphics.state import State
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Default Shader source:
|
|
21
|
+
|
|
22
|
+
_vertex_source: str = """#version 330 core
|
|
23
|
+
in vec3 position;
|
|
24
|
+
in vec4 colors;
|
|
25
|
+
|
|
26
|
+
out vec4 vertex_colors;
|
|
27
|
+
|
|
28
|
+
uniform WindowBlock
|
|
29
|
+
{
|
|
30
|
+
mat4 projection;
|
|
31
|
+
mat4 view;
|
|
32
|
+
} window;
|
|
33
|
+
|
|
34
|
+
void main()
|
|
35
|
+
{
|
|
36
|
+
gl_Position = window.projection * window.view * vec4(position, 1.0);
|
|
37
|
+
|
|
38
|
+
vertex_colors = colors;
|
|
39
|
+
}
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
_fragment_source: str = """#version 330 core
|
|
43
|
+
in vec4 vertex_colors;
|
|
44
|
+
out vec4 final_colors;
|
|
45
|
+
|
|
46
|
+
void main()
|
|
47
|
+
{
|
|
48
|
+
final_colors = vertex_colors;
|
|
49
|
+
}
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_default_batch() -> Batch:
|
|
54
|
+
"""Batch used globally for objects that have no Batch specified."""
|
|
55
|
+
return pyglet.graphics.api.core.get_default_batch()
|
|
56
|
+
# try:
|
|
57
|
+
# return pyglet.graphics.api.core.current_context.pyglet_graphics_default_batch
|
|
58
|
+
# except AttributeError:
|
|
59
|
+
# pyglet.graphics.api.core.current_context.pyglet_graphics_default_batch = Batch()
|
|
60
|
+
# return pyglet.graphics.api.core.current_context.pyglet_graphics_default_batch
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_default_shader() -> ShaderProgram:
|
|
64
|
+
"""A default basic shader for default batches."""
|
|
65
|
+
return pyglet.graphics.api.core.get_cached_shader(
|
|
66
|
+
"default_graphics",
|
|
67
|
+
(_vertex_source, 'vertex'),
|
|
68
|
+
(_fragment_source, 'fragment'),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
_domain_class_map: dict[tuple[bool, bool], type[vertexdomain.VertexDomain]] = {
|
|
73
|
+
# Indexed, Instanced : Domain
|
|
74
|
+
(False, False): vertexdomain.VertexDomain,
|
|
75
|
+
(True, False): vertexdomain.IndexedVertexDomain,
|
|
76
|
+
(False, True): vertexdomain.InstancedVertexDomain,
|
|
77
|
+
(True, True): vertexdomain.InstancedIndexedVertexDomain,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Batch(BatchBase):
|
|
82
|
+
"""Manage a collection of drawables for batched rendering.
|
|
83
|
+
|
|
84
|
+
Many drawable pyglet objects accept an optional `Batch` argument in their
|
|
85
|
+
constructors. By giving a `Batch` to multiple objects, you can tell pyglet
|
|
86
|
+
that you expect to draw all of these objects at once, so it can optimise its
|
|
87
|
+
use of OpenGL. Hence, drawing a `Batch` is often much faster than drawing
|
|
88
|
+
each contained drawable separately.
|
|
89
|
+
|
|
90
|
+
The following example creates a batch, adds two sprites to the batch, and
|
|
91
|
+
then draws the entire batch::
|
|
92
|
+
|
|
93
|
+
batch = pyglet.graphics.Batch()
|
|
94
|
+
car = pyglet.sprite.Sprite(car_image, batch=batch)
|
|
95
|
+
boat = pyglet.sprite.Sprite(boat_image, batch=batch)
|
|
96
|
+
|
|
97
|
+
def on_draw():
|
|
98
|
+
batch.draw()
|
|
99
|
+
|
|
100
|
+
While any drawables can be added to a `Batch`, only those with the same
|
|
101
|
+
draw mode, shader program, and group can be optimised together.
|
|
102
|
+
|
|
103
|
+
Internally, a `Batch` manages a set of VertexDomains along with
|
|
104
|
+
information about how the domains are to be drawn. To implement batching on
|
|
105
|
+
a custom drawable, get your vertex domains from the given batch instead of
|
|
106
|
+
setting them up yourself.
|
|
107
|
+
"""
|
|
108
|
+
_draw_list: list[Callable]
|
|
109
|
+
top_groups: list[Group]
|
|
110
|
+
group_children: dict[Group, list[Group]]
|
|
111
|
+
group_map: dict[Group, dict[_DomainKey, vertexdomain.VertexDomain]]
|
|
112
|
+
|
|
113
|
+
def __init__(self, context: OpenGLSurfaceContext | None = None, initial_count: int = 32) -> None:
|
|
114
|
+
"""Initialize the batch for use.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
context:
|
|
118
|
+
The OpenGL Surface context this batch will be a part of.
|
|
119
|
+
initial_count:
|
|
120
|
+
The initial element count of the buffers created by the domains in the batch.
|
|
121
|
+
|
|
122
|
+
Increase this value if you plan to load large amounts of vertices, as it will reduce the need for
|
|
123
|
+
resizing buffers, which can be slow.
|
|
124
|
+
"""
|
|
125
|
+
# Mapping to find domain.
|
|
126
|
+
# group -> (attributes, mode, indexed) -> domain
|
|
127
|
+
super().__init__(initial_count)
|
|
128
|
+
self._context = context or pyglet.graphics.api.core.current_context
|
|
129
|
+
assert self._context is not None, "A context needs to exist before you create this."
|
|
130
|
+
|
|
131
|
+
def invalidate(self) -> None:
|
|
132
|
+
"""Force the batch to update the draw list.
|
|
133
|
+
|
|
134
|
+
This method can be used to force the batch to re-compute the draw list
|
|
135
|
+
when the ordering of groups has changed.
|
|
136
|
+
|
|
137
|
+
.. versionadded:: 1.2
|
|
138
|
+
"""
|
|
139
|
+
self._draw_list_dirty = True
|
|
140
|
+
|
|
141
|
+
def update_shader(self, vertex_list: VertexList | IndexedVertexList, mode: GeometryMode, group: Group,
|
|
142
|
+
program: ShaderProgram) -> bool:
|
|
143
|
+
"""Migrate a vertex list to another domain that has the specified shader attributes.
|
|
144
|
+
|
|
145
|
+
The results are undefined if `mode` is not correct or if `vertex_list`
|
|
146
|
+
does not belong to this batch (they are not checked and will not
|
|
147
|
+
necessarily throw an exception immediately).
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
vertex_list:
|
|
151
|
+
A vertex list currently belonging to this batch.
|
|
152
|
+
mode:
|
|
153
|
+
The current GL drawing mode of the vertex list.
|
|
154
|
+
group:
|
|
155
|
+
The new group to migrate to.
|
|
156
|
+
program:
|
|
157
|
+
The new shader program to migrate to.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
False if the domain's no longer match. The caller should handle this scenario.
|
|
161
|
+
"""
|
|
162
|
+
# No new attributes.
|
|
163
|
+
attributes = program.attributes.copy()
|
|
164
|
+
|
|
165
|
+
# Formats may differ (normalization) than what is declared in the shader.
|
|
166
|
+
# Make those adjustments and attempt to get a domain.
|
|
167
|
+
for a_name in attributes:
|
|
168
|
+
if (a_name in vertex_list.initial_attribs and
|
|
169
|
+
vertex_list.initial_attribs[a_name]['format'] != attributes[a_name]['format']):
|
|
170
|
+
attributes[a_name]['format'] = vertex_list.initial_attribs[a_name]['format']
|
|
171
|
+
|
|
172
|
+
domain = self.get_domain(vertex_list.indexed, vertex_list.instanced, mode, group, attributes)
|
|
173
|
+
|
|
174
|
+
# TODO: Allow migration if we can restore original vertices somehow. Much faster.
|
|
175
|
+
# If the domain's don't match, we need to re-create the vertex list. Tell caller no match.
|
|
176
|
+
if domain != vertex_list.domain:
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
def migrate(self, vertex_list: VertexList | IndexedVertexList, mode: GeometryMode, group: Group,
|
|
182
|
+
batch: Batch) -> None:
|
|
183
|
+
"""Migrate a vertex list to another batch and/or group.
|
|
184
|
+
|
|
185
|
+
`vertex_list` and `mode` together identify the vertex list to migrate.
|
|
186
|
+
`group` and `batch` are new owners of the vertex list after migration.
|
|
187
|
+
|
|
188
|
+
The results are undefined if `mode` is not correct or if `vertex_list`
|
|
189
|
+
does not belong to this batch (they are not checked and will not
|
|
190
|
+
necessarily throw an exception immediately).
|
|
191
|
+
|
|
192
|
+
``batch`` can remain unchanged if only a group change is desired.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
vertex_list:
|
|
196
|
+
A vertex list currently belonging to this batch.
|
|
197
|
+
mode:
|
|
198
|
+
The current GL drawing mode of the vertex list.
|
|
199
|
+
group:
|
|
200
|
+
The new group to migrate to.
|
|
201
|
+
batch:
|
|
202
|
+
The batch to migrate to (or the current batch).
|
|
203
|
+
|
|
204
|
+
"""
|
|
205
|
+
attributes = vertex_list.domain.attribute_meta
|
|
206
|
+
domain = batch.get_domain(vertex_list.indexed, vertex_list.instanced, mode, group, attributes)
|
|
207
|
+
|
|
208
|
+
if domain != vertex_list.domain:
|
|
209
|
+
vertex_list.migrate(domain, group)
|
|
210
|
+
else:
|
|
211
|
+
# If the same domain, no need to move vertices, just update the group.
|
|
212
|
+
vertex_list.update_group(group)
|
|
213
|
+
|
|
214
|
+
# Updating group can potentially change draw order though.
|
|
215
|
+
self._draw_list_dirty = True
|
|
216
|
+
|
|
217
|
+
def get_domain(self, indexed: bool, instanced: bool, mode: GeometryMode, group: Group,
|
|
218
|
+
attributes: dict[str, Any]) -> vertexdomain.VertexDomain | vertexdomain.IndexedVertexDomain | vertexdomain.InstancedVertexDomain | vertexdomain.InstancedIndexedVertexDomain:
|
|
219
|
+
"""Get, or create, the vertex domain corresponding to the given arguments.
|
|
220
|
+
|
|
221
|
+
mode is the render mode such as GL_LINES or GL_TRIANGLES
|
|
222
|
+
"""
|
|
223
|
+
# Group map just used for group lookup now, not domains.
|
|
224
|
+
if group not in self.group_map:
|
|
225
|
+
self._add_group(group)
|
|
226
|
+
|
|
227
|
+
# If instanced, ensure a separate domain, as multiple instance sources can match the key.
|
|
228
|
+
# Find domain given formats, indices and mode
|
|
229
|
+
key = _DomainKey(indexed, instanced, mode, str(attributes))
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
domain = self._domain_registry[key]
|
|
233
|
+
except KeyError:
|
|
234
|
+
# Create domain
|
|
235
|
+
domain = _domain_class_map[(indexed, instanced)](self._context, self.initial_count, attributes)
|
|
236
|
+
self._domain_registry[key] = domain
|
|
237
|
+
self._draw_list_dirty = True
|
|
238
|
+
return domain
|
|
239
|
+
|
|
240
|
+
def _add_group(self, group: Group) -> None:
|
|
241
|
+
self.group_map[group] = {}
|
|
242
|
+
if group.parent is None:
|
|
243
|
+
self.top_groups.append(group)
|
|
244
|
+
else:
|
|
245
|
+
if group.parent not in self.group_map:
|
|
246
|
+
self._add_group(group.parent)
|
|
247
|
+
if group.parent not in self.group_children:
|
|
248
|
+
self.group_children[group.parent] = []
|
|
249
|
+
self.group_children[group.parent].append(group)
|
|
250
|
+
|
|
251
|
+
group._assigned_batches.add(self) # noqa: SLF001
|
|
252
|
+
self._draw_list_dirty = True
|
|
253
|
+
|
|
254
|
+
def _cleanup_groups(self, group: Group) -> None:
|
|
255
|
+
"""Safely remove empty groups from all tracking structures."""
|
|
256
|
+
del self.group_map[group]
|
|
257
|
+
group._assigned_batches.remove(self) # noqa: SLF001
|
|
258
|
+
if group.parent:
|
|
259
|
+
self.group_children[group.parent].remove(group)
|
|
260
|
+
try: # noqa: SIM105
|
|
261
|
+
del self.group_children[group]
|
|
262
|
+
except KeyError:
|
|
263
|
+
pass
|
|
264
|
+
try: # noqa: SIM105
|
|
265
|
+
self.top_groups.remove(group)
|
|
266
|
+
except ValueError:
|
|
267
|
+
pass
|
|
268
|
+
# Remove bucket from all domains.
|
|
269
|
+
for domain in self._domain_registry.values():
|
|
270
|
+
if domain.has_bucket(group):
|
|
271
|
+
del domain._vertex_buckets[group] # noqa: SLF001
|
|
272
|
+
|
|
273
|
+
def _create_draw_list(self) -> list[Callable]:
|
|
274
|
+
"""Rebuild draw list by walking the group tree and minimizing state transitions."""
|
|
275
|
+
def visit(group: Group) -> list[Callable]:
|
|
276
|
+
draw_list = []
|
|
277
|
+
if not group.visible:
|
|
278
|
+
return draw_list
|
|
279
|
+
|
|
280
|
+
# Determine if any vertices are drawable.
|
|
281
|
+
is_drawable = False
|
|
282
|
+
for dkey, domain in self._domain_registry.items():
|
|
283
|
+
if domain.is_empty or not domain.get_drawable_bucket(group):
|
|
284
|
+
self._empty_domains.add(dkey)
|
|
285
|
+
continue
|
|
286
|
+
is_drawable = True
|
|
287
|
+
break
|
|
288
|
+
|
|
289
|
+
# State has nothing drawable and no children to affect.
|
|
290
|
+
# Even if it has states, nothing to apply it to. Clean them and return early.
|
|
291
|
+
if not is_drawable and not self.group_children.get(group):
|
|
292
|
+
self._cleanup_groups(group)
|
|
293
|
+
return []
|
|
294
|
+
|
|
295
|
+
# If drawable, then find the domains to draw.
|
|
296
|
+
if is_drawable:
|
|
297
|
+
for dkey, domain in self._domain_registry.items():
|
|
298
|
+
bucket = domain.get_drawable_bucket(group)
|
|
299
|
+
if not bucket:
|
|
300
|
+
continue
|
|
301
|
+
|
|
302
|
+
draw_list.append((domain, dkey.mode, group))
|
|
303
|
+
|
|
304
|
+
# Recurse into visible children
|
|
305
|
+
children = self.group_children.get(group, [])
|
|
306
|
+
for child in sorted(children):
|
|
307
|
+
if child.visible:
|
|
308
|
+
draw_list.extend(visit(child))
|
|
309
|
+
|
|
310
|
+
if children or is_drawable:
|
|
311
|
+
return [(None, 'set', group), *draw_list, (None, 'unset', group)]
|
|
312
|
+
|
|
313
|
+
return draw_list
|
|
314
|
+
|
|
315
|
+
_draw_list = []
|
|
316
|
+
|
|
317
|
+
self.top_groups.sort()
|
|
318
|
+
|
|
319
|
+
for top in list(self.top_groups):
|
|
320
|
+
if top.visible:
|
|
321
|
+
_draw_list.extend(visit(top))
|
|
322
|
+
|
|
323
|
+
return _draw_list
|
|
324
|
+
|
|
325
|
+
@staticmethod
|
|
326
|
+
def _vao_bind_fn(domain): # noqa: ANN001, ANN205
|
|
327
|
+
def _bind_vao(_ctx) -> None: # noqa: ANN001
|
|
328
|
+
domain.bind_vao()
|
|
329
|
+
|
|
330
|
+
return _bind_vao
|
|
331
|
+
|
|
332
|
+
@staticmethod
|
|
333
|
+
def _draw_bucket_fn(domain, buckets, mode_func): # noqa: ANN001, ANN205
|
|
334
|
+
def _draw(_ctx) -> None: # noqa: ANN001
|
|
335
|
+
domain.draw_buckets(mode_func, buckets)
|
|
336
|
+
|
|
337
|
+
return _draw
|
|
338
|
+
|
|
339
|
+
def _optimize_draw_list(self, draw_list: list[tuple]) -> list[Callable]:
|
|
340
|
+
"""Turn a flattened (domain/mode/group) list into optimized callables.
|
|
341
|
+
|
|
342
|
+
States that are equal (by __eq__) are treated as the same logical GPU state.
|
|
343
|
+
Intermediate unset/set pairs for identical states are removed, preserving
|
|
344
|
+
dependency ordering and teardown safety.
|
|
345
|
+
"""
|
|
346
|
+
calls: list[Callable] = []
|
|
347
|
+
active_states: dict[type, State] = {} # (type, key) -> instance
|
|
348
|
+
|
|
349
|
+
def _next_same_type_set(idx: int, state_type: type) -> None | State:
|
|
350
|
+
for j in range(idx + 1, len(draw_list)):
|
|
351
|
+
dom2, mode2, group2 = draw_list[j]
|
|
352
|
+
if dom2 is None and mode2 == "set":
|
|
353
|
+
for s2 in group2._expanded_states: # noqa: SLF001
|
|
354
|
+
if type(s2) is state_type:
|
|
355
|
+
return s2 # first same-type set we see in the future
|
|
356
|
+
return None
|
|
357
|
+
|
|
358
|
+
def flush_buckets() -> None:
|
|
359
|
+
nonlocal current_buckets, last_mode, last_domain
|
|
360
|
+
if not current_buckets:
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
calls.append(self._draw_bucket_fn(last_domain, list(current_buckets), geometry_map[last_mode]))
|
|
364
|
+
current_buckets.clear()
|
|
365
|
+
|
|
366
|
+
def _emit_set(_state: State) -> None:
|
|
367
|
+
stype = type(_state)
|
|
368
|
+
current = active_states.get(stype)
|
|
369
|
+
|
|
370
|
+
# state is same
|
|
371
|
+
if current == _state:
|
|
372
|
+
return
|
|
373
|
+
|
|
374
|
+
# state changed
|
|
375
|
+
if current_buckets:
|
|
376
|
+
flush_buckets()
|
|
377
|
+
|
|
378
|
+
# unset previous
|
|
379
|
+
if current and current.unsets_state:
|
|
380
|
+
calls.append(current.unset_state)
|
|
381
|
+
|
|
382
|
+
# set new state
|
|
383
|
+
if _state.sets_state:
|
|
384
|
+
calls.append(_state.set_state)
|
|
385
|
+
|
|
386
|
+
active_states[stype] = _state
|
|
387
|
+
|
|
388
|
+
def _emit_unset(_state: State, idx: int) -> None:
|
|
389
|
+
stype = type(_state)
|
|
390
|
+
current = active_states.get(stype)
|
|
391
|
+
if current is None:
|
|
392
|
+
return
|
|
393
|
+
|
|
394
|
+
next_set = _next_same_type_set(idx, stype)
|
|
395
|
+
if next_set == current:
|
|
396
|
+
return # will remain active
|
|
397
|
+
|
|
398
|
+
# state is about to end
|
|
399
|
+
flush_buckets()
|
|
400
|
+
|
|
401
|
+
if current.unsets_state:
|
|
402
|
+
calls.append(current.unset_state)
|
|
403
|
+
active_states.pop(stype, None)
|
|
404
|
+
|
|
405
|
+
last_domain = None
|
|
406
|
+
last_mode = None
|
|
407
|
+
current_buckets = []
|
|
408
|
+
|
|
409
|
+
for i, (domain, mode, group) in enumerate(draw_list):
|
|
410
|
+
if domain is None:
|
|
411
|
+
# This is a state boundary. See if it *actually* changes state; if so, flush first.
|
|
412
|
+
if mode == "set":
|
|
413
|
+
for s in group._expanded_states:
|
|
414
|
+
_emit_set(s)
|
|
415
|
+
|
|
416
|
+
elif mode == "unset":
|
|
417
|
+
for s in reversed(group._expanded_states):
|
|
418
|
+
_emit_unset(s, i)
|
|
419
|
+
|
|
420
|
+
continue
|
|
421
|
+
|
|
422
|
+
# Drawable
|
|
423
|
+
bucket = domain.get_drawable_bucket(group)
|
|
424
|
+
if not bucket or bucket.is_empty:
|
|
425
|
+
continue
|
|
426
|
+
|
|
427
|
+
if last_domain is None:
|
|
428
|
+
calls.append(self._vao_bind_fn(domain))
|
|
429
|
+
elif domain != last_domain:
|
|
430
|
+
# New VAO: flush previous batch, bind new VAO
|
|
431
|
+
flush_buckets()
|
|
432
|
+
calls.append(self._vao_bind_fn(domain))
|
|
433
|
+
elif mode != last_mode:
|
|
434
|
+
# Same VAO but different primitive mode: flush
|
|
435
|
+
flush_buckets()
|
|
436
|
+
|
|
437
|
+
current_buckets.append(bucket)
|
|
438
|
+
last_domain = domain
|
|
439
|
+
last_mode = mode
|
|
440
|
+
|
|
441
|
+
# Final flush
|
|
442
|
+
flush_buckets()
|
|
443
|
+
|
|
444
|
+
return calls
|
|
445
|
+
|
|
446
|
+
def _dump_draw_list_call_order(self, draw_list: list[Callable], include_dc: bool=True) -> None:
|
|
447
|
+
import inspect
|
|
448
|
+
|
|
449
|
+
print("=== DRAW ORDER ===")
|
|
450
|
+
|
|
451
|
+
def fn_label(_fn: Callable) -> str:
|
|
452
|
+
r = repr(_fn)
|
|
453
|
+
if "unset_state" in r:
|
|
454
|
+
return "UNSET"
|
|
455
|
+
if "set_state" in r:
|
|
456
|
+
return "SET"
|
|
457
|
+
if "_vao_call_fn" in r:
|
|
458
|
+
return "VAO"
|
|
459
|
+
if "make_draw_buckets_fn" in r:
|
|
460
|
+
return "DRAW"
|
|
461
|
+
return "CALL"
|
|
462
|
+
|
|
463
|
+
def fn_name(_fn: Callable) -> str:
|
|
464
|
+
if inspect.ismethod(_fn):
|
|
465
|
+
dc_info = f" ({_fn.__self__})" if include_dc else ""
|
|
466
|
+
return f"{_fn.__self__.__class__.__name__}.{_fn.__name__}{dc_info}"
|
|
467
|
+
if inspect.isfunction(_fn):
|
|
468
|
+
return _fn.__name__
|
|
469
|
+
return _fn.__class__.__name__
|
|
470
|
+
|
|
471
|
+
for i, fn in enumerate(draw_list):
|
|
472
|
+
label = fn_label(fn)
|
|
473
|
+
name = fn_name(fn)
|
|
474
|
+
print(f"{i:03d} ({label}): {name}")
|
|
475
|
+
print("==================")
|
|
476
|
+
|
|
477
|
+
def _set_draw_functions(self, draw_list: list) -> list[Callable]:
|
|
478
|
+
"""Takes a draw list and turns them into function calls.
|
|
479
|
+
|
|
480
|
+
Does not optimize any states. All states are called.
|
|
481
|
+
"""
|
|
482
|
+
calls: list[Callable] = []
|
|
483
|
+
last_domain = None
|
|
484
|
+
|
|
485
|
+
for i, (domain, mode, group) in enumerate(draw_list):
|
|
486
|
+
if domain is None:
|
|
487
|
+
# This is a state boundary. See if it *actually* changes state; if so, flush first.
|
|
488
|
+
if mode == "set":
|
|
489
|
+
calls.extend([s.set_state for s in group._expanded_states if s.sets_state])
|
|
490
|
+
|
|
491
|
+
elif mode == "unset":
|
|
492
|
+
calls.extend(reversed([s.unset_state for s in group._expanded_states if s.unsets_state]))
|
|
493
|
+
|
|
494
|
+
continue
|
|
495
|
+
|
|
496
|
+
# Drawable
|
|
497
|
+
bucket = domain.get_drawable_bucket(group)
|
|
498
|
+
if not bucket or bucket.is_empty:
|
|
499
|
+
continue
|
|
500
|
+
|
|
501
|
+
if last_domain is None or domain != last_domain:
|
|
502
|
+
calls.append(self._vao_bind_fn(domain))
|
|
503
|
+
|
|
504
|
+
calls.append(self._draw_bucket_fn(domain, [bucket], geometry_map[mode]))
|
|
505
|
+
last_domain = domain
|
|
506
|
+
|
|
507
|
+
return calls
|
|
508
|
+
|
|
509
|
+
def _dump_draw_list(self) -> None:
|
|
510
|
+
def dump(group: Group, indent: str = '') -> None:
|
|
511
|
+
print(indent, 'Begin group', group)
|
|
512
|
+
for domain in self._domain_registry.values():
|
|
513
|
+
if domain.has_bucket(group):
|
|
514
|
+
# Domain header
|
|
515
|
+
domain_info = repr(domain).split('@')[-1].replace('>', '')
|
|
516
|
+
print(f"{indent} > Domain: {domain.__class__.__name__}@{domain_info}")
|
|
517
|
+
|
|
518
|
+
# Regions
|
|
519
|
+
starts, sizes = domain.vertex_buffers.allocator.get_allocated_regions()
|
|
520
|
+
for start, size in zip(starts, sizes):
|
|
521
|
+
print(f"{indent} - Region start={start:<4} size={size:<4}")
|
|
522
|
+
attribs = ', '.join(domain.attrib_name_buffers.keys())
|
|
523
|
+
print(f"{indent} (Attributes: {attribs})")
|
|
524
|
+
for child in self.group_children.get(group, ()):
|
|
525
|
+
dump(child, indent + ' ')
|
|
526
|
+
print(indent, 'End group', group)
|
|
527
|
+
|
|
528
|
+
print(f'Draw list for {self!r}:')
|
|
529
|
+
for group in self.top_groups:
|
|
530
|
+
dump(group)
|
|
531
|
+
|
|
532
|
+
def _update_draw_list(self) -> None:
|
|
533
|
+
if self._draw_list_dirty:
|
|
534
|
+
draw_list = self._create_draw_list()
|
|
535
|
+
if pyglet.options.optimize_states:
|
|
536
|
+
self._draw_list = self._optimize_draw_list(draw_list)
|
|
537
|
+
else:
|
|
538
|
+
self._draw_list = self._set_draw_functions(draw_list)
|
|
539
|
+
self._draw_list_dirty = False
|
|
540
|
+
|
|
541
|
+
def draw(self) -> None:
|
|
542
|
+
"""Draw the batch."""
|
|
543
|
+
self._update_draw_list()
|
|
544
|
+
|
|
545
|
+
for func in self._draw_list:
|
|
546
|
+
func(self._context)
|
|
547
|
+
|
|
548
|
+
self.delete_empty_domains()
|
|
549
|
+
|
|
550
|
+
def draw_subset(self, vertex_lists: Sequence[VertexList | IndexedVertexList]) -> None:
|
|
551
|
+
"""Draw only some vertex lists in the batch.
|
|
552
|
+
|
|
553
|
+
The use of this method is highly discouraged, as it is quite
|
|
554
|
+
inefficient. Usually an application can be redesigned so that batches
|
|
555
|
+
can always be drawn in their entirety, using `draw`.
|
|
556
|
+
|
|
557
|
+
The given vertex lists must belong to this batch; behaviour is
|
|
558
|
+
undefined if this condition is not met.
|
|
559
|
+
|
|
560
|
+
Args:
|
|
561
|
+
vertex_lists:
|
|
562
|
+
Vertex lists to draw.
|
|
563
|
+
|
|
564
|
+
"""
|
|
565
|
+
|
|
566
|
+
# Horrendously inefficient.
|
|
567
|
+
def visit(group: Group) -> None:
|
|
568
|
+
group.set_state_all(self._context)
|
|
569
|
+
|
|
570
|
+
# Draw domains using this group
|
|
571
|
+
domain_map = self.group_map[group]
|
|
572
|
+
for (_, _, mode, _, _), domain in domain_map.items():
|
|
573
|
+
for alist in vertex_lists:
|
|
574
|
+
if alist.domain is domain:
|
|
575
|
+
alist.draw(mode)
|
|
576
|
+
|
|
577
|
+
# Sort and visit child groups of this group
|
|
578
|
+
children = self.group_children.get(group)
|
|
579
|
+
if children:
|
|
580
|
+
children.sort()
|
|
581
|
+
for child in children:
|
|
582
|
+
if child.visible:
|
|
583
|
+
visit(child)
|
|
584
|
+
|
|
585
|
+
group.unset_state_all(self._context)
|
|
586
|
+
|
|
587
|
+
self.top_groups.sort()
|
|
588
|
+
for top_group in self.top_groups:
|
|
589
|
+
if top_group.visible:
|
|
590
|
+
visit(top_group)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pyglet.graphics import GeometryMode
|
|
4
|
+
from pyglet.graphics.api.webgl.gl import (
|
|
5
|
+
GL_LINEAR, GL_NEAREST, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, \
|
|
6
|
+
GL_TEXTURE_CUBE_MAP, \
|
|
7
|
+
GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_TEXTURE_WRAP_S, \
|
|
8
|
+
GL_TEXTURE_WRAP_T,
|
|
9
|
+
GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
|
10
|
+
GL_TRIANGLE_FAN,
|
|
11
|
+
GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR,
|
|
12
|
+
GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, \
|
|
13
|
+
GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR,
|
|
14
|
+
GL_ONE_MINUS_CONSTANT_COLOR, \
|
|
15
|
+
GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL,
|
|
16
|
+
GL_GEQUAL, GL_ALWAYS)
|
|
17
|
+
|
|
18
|
+
from pyglet.enums import BlendFactor, TextureFilter, TextureType, TextureWrapping, CompareOp
|
|
19
|
+
|
|
20
|
+
geometry_map = {
|
|
21
|
+
GeometryMode.POINTS: GL_POINTS,
|
|
22
|
+
GeometryMode.LINES: GL_LINES,
|
|
23
|
+
GeometryMode.LINE_STRIP: GL_LINE_STRIP,
|
|
24
|
+
GeometryMode.TRIANGLES: GL_TRIANGLES,
|
|
25
|
+
GeometryMode.TRIANGLE_STRIP: GL_TRIANGLE_STRIP,
|
|
26
|
+
GeometryMode.TRIANGLE_FAN: GL_TRIANGLE_FAN,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
blend_factor_map = {
|
|
30
|
+
BlendFactor.ZERO: GL_ZERO,
|
|
31
|
+
BlendFactor.ONE: GL_ONE,
|
|
32
|
+
BlendFactor.SRC_COLOR: GL_SRC_COLOR,
|
|
33
|
+
BlendFactor.ONE_MINUS_SRC_COLOR: GL_ONE_MINUS_SRC_COLOR,
|
|
34
|
+
BlendFactor.DST_COLOR: GL_DST_COLOR,
|
|
35
|
+
BlendFactor.ONE_MINUS_DST_COLOR: GL_ONE_MINUS_DST_COLOR,
|
|
36
|
+
BlendFactor.SRC_ALPHA: GL_SRC_ALPHA,
|
|
37
|
+
BlendFactor.ONE_MINUS_SRC_ALPHA: GL_ONE_MINUS_SRC_ALPHA,
|
|
38
|
+
BlendFactor.DST_ALPHA: GL_DST_ALPHA,
|
|
39
|
+
BlendFactor.ONE_MINUS_DST_ALPHA: GL_ONE_MINUS_DST_ALPHA,
|
|
40
|
+
BlendFactor.CONSTANT_COLOR: GL_CONSTANT_COLOR,
|
|
41
|
+
BlendFactor.ONE_MINUS_CONSTANT_COLOR: GL_ONE_MINUS_CONSTANT_COLOR,
|
|
42
|
+
BlendFactor.CONSTANT_ALPHA: GL_CONSTANT_ALPHA,
|
|
43
|
+
BlendFactor.ONE_MINUS_CONSTANT_ALPHA: GL_ONE_MINUS_CONSTANT_ALPHA,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
texture_map = {
|
|
47
|
+
# Filters
|
|
48
|
+
TextureFilter.LINEAR: GL_LINEAR,
|
|
49
|
+
TextureFilter.NEAREST: GL_NEAREST,
|
|
50
|
+
|
|
51
|
+
# Texture Types
|
|
52
|
+
TextureType.TYPE_1D: GL_TEXTURE_1D,
|
|
53
|
+
TextureType.TYPE_2D: GL_TEXTURE_2D,
|
|
54
|
+
TextureType.TYPE_3D: GL_TEXTURE_3D,
|
|
55
|
+
TextureType.TYPE_CUBE_MAP: GL_TEXTURE_CUBE_MAP,
|
|
56
|
+
TextureType.TYPE_1D_ARRAY: GL_TEXTURE_1D_ARRAY,
|
|
57
|
+
TextureType.TYPE_2D_ARRAY: GL_TEXTURE_2D_ARRAY,
|
|
58
|
+
TextureType.TYPE_CUBE_MAP_ARRAY: GL_TEXTURE_CUBE_MAP_ARRAY,
|
|
59
|
+
|
|
60
|
+
# Wrapping
|
|
61
|
+
TextureWrapping.WRAP_R: GL_TEXTURE_WRAP_R,
|
|
62
|
+
TextureWrapping.WRAP_S: GL_TEXTURE_WRAP_S,
|
|
63
|
+
TextureWrapping.WRAP_T: GL_TEXTURE_WRAP_T,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
compare_op_map = {
|
|
68
|
+
CompareOp.NEVER: GL_NEVER,
|
|
69
|
+
CompareOp.LESS: GL_LESS,
|
|
70
|
+
CompareOp.EQUAL: GL_EQUAL,
|
|
71
|
+
CompareOp.LESS_OR_EQUAL: GL_LEQUAL,
|
|
72
|
+
CompareOp.GREATER: GL_GREATER,
|
|
73
|
+
CompareOp.NOT_EQUAL: GL_NOTEQUAL,
|
|
74
|
+
CompareOp.GREATER_OR_EQUAL: GL_GEQUAL,
|
|
75
|
+
CompareOp.ALWAYS: GL_ALWAYS,
|
|
76
|
+
}
|