pyglet 2.1.12__py3-none-any.whl → 3.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +4 -17
- 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 +27 -5
- 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 +147 -177
- 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.12.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
- pyglet-3.0.dev1.dist-info/RECORD +322 -0
- {pyglet-2.1.12.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.12.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.12.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,751 @@
|
|
|
1
|
+
"""Manage related vertex attributes within a single vertex domain.
|
|
2
|
+
|
|
3
|
+
A vertex "domain" consists of a set of attribute descriptions that together
|
|
4
|
+
describe the layout of one or more vertex buffers which are used together to
|
|
5
|
+
specify the vertices in a primitive. Additionally, the domain manages the
|
|
6
|
+
buffers used to store the data and will resize them as necessary to accommodate
|
|
7
|
+
new vertices.
|
|
8
|
+
|
|
9
|
+
Domains can optionally be indexed, in which case they also manage a buffer
|
|
10
|
+
containing vertex indices. This buffer is grown separately and has no size
|
|
11
|
+
relation to the attribute buffers.
|
|
12
|
+
|
|
13
|
+
Applications can create vertices (and optionally, indices) within a domain
|
|
14
|
+
with the :py:meth:`VertexDomain.create` method. This returns a
|
|
15
|
+
:py:class:`VertexList` representing the list of vertices created. The vertex
|
|
16
|
+
attribute data within the group can be modified, and the changes will be made
|
|
17
|
+
to the underlying buffers automatically.
|
|
18
|
+
|
|
19
|
+
The entire domain can be efficiently drawn in one step with the
|
|
20
|
+
:py:meth:`VertexDomain.draw` method, assuming all the vertices comprise
|
|
21
|
+
primitives of the same OpenGL primitive mode.
|
|
22
|
+
"""
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import ctypes
|
|
26
|
+
from typing import TYPE_CHECKING, Any, Sequence
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
from pyglet.graphics.api.gl import (
|
|
30
|
+
GL_BYTE,
|
|
31
|
+
GL_DOUBLE,
|
|
32
|
+
GL_FLOAT,
|
|
33
|
+
GL_INT,
|
|
34
|
+
GL_SHORT,
|
|
35
|
+
GL_UNSIGNED_BYTE,
|
|
36
|
+
GL_UNSIGNED_INT,
|
|
37
|
+
GL_UNSIGNED_SHORT,
|
|
38
|
+
GLint,
|
|
39
|
+
GLintptr,
|
|
40
|
+
GLsizei,
|
|
41
|
+
GLvoid,
|
|
42
|
+
vertexarray, OpenGLSurfaceContext,
|
|
43
|
+
)
|
|
44
|
+
from pyglet.graphics.api.gl.buffer import AttributeBufferObject, IndexedBufferObject
|
|
45
|
+
from pyglet.graphics.api.gl.enums import geometry_map
|
|
46
|
+
from pyglet.graphics.api.gl.shader import GLAttribute
|
|
47
|
+
from pyglet.graphics.instance import InstanceBucket, BaseInstanceDomain, VertexInstanceBase
|
|
48
|
+
from pyglet.graphics.vertexdomain import (
|
|
49
|
+
VertexStream,
|
|
50
|
+
VertexArrayBinding,
|
|
51
|
+
VertexArrayProtocol,
|
|
52
|
+
InstanceStream,
|
|
53
|
+
IndexStream,
|
|
54
|
+
_RunningIndexSupport,
|
|
55
|
+
VertexGroupBucket,
|
|
56
|
+
VertexDomainBase,
|
|
57
|
+
IndexedVertexDomainBase,
|
|
58
|
+
VertexListBase,
|
|
59
|
+
IndexedVertexListBase,
|
|
60
|
+
InstancedVertexDomainBase,
|
|
61
|
+
InstancedIndexedVertexDomainBase,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if TYPE_CHECKING:
|
|
65
|
+
from ctypes import Array
|
|
66
|
+
from pyglet.graphics.shader import AttributeView
|
|
67
|
+
from pyglet.graphics import GeometryMode, Group
|
|
68
|
+
from pyglet.graphics.shader import Attribute
|
|
69
|
+
from pyglet.customtypes import CType, DataTypes
|
|
70
|
+
|
|
71
|
+
_c_types = {
|
|
72
|
+
GL_BYTE: ctypes.c_byte,
|
|
73
|
+
GL_UNSIGNED_BYTE: ctypes.c_ubyte,
|
|
74
|
+
GL_SHORT: ctypes.c_short,
|
|
75
|
+
GL_UNSIGNED_SHORT: ctypes.c_ushort,
|
|
76
|
+
GL_INT: ctypes.c_int,
|
|
77
|
+
GL_UNSIGNED_INT: ctypes.c_uint,
|
|
78
|
+
GL_FLOAT: ctypes.c_float,
|
|
79
|
+
GL_DOUBLE: ctypes.c_double,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_gl_types = {
|
|
83
|
+
'b': GL_BYTE,
|
|
84
|
+
'B': GL_UNSIGNED_BYTE,
|
|
85
|
+
'h': GL_SHORT,
|
|
86
|
+
'H': GL_UNSIGNED_SHORT,
|
|
87
|
+
'i': GL_INT,
|
|
88
|
+
'I': GL_UNSIGNED_INT,
|
|
89
|
+
'f': GL_FLOAT,
|
|
90
|
+
'd': GL_DOUBLE,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _make_attribute_property(name: str) -> property:
|
|
95
|
+
def _attribute_getter(self: VertexList) -> Array[float | int]:
|
|
96
|
+
buffer = self.domain.attrib_name_buffers[name]
|
|
97
|
+
region = buffer.get_region(self.start, self.count)
|
|
98
|
+
buffer.invalidate_region(self.start, self.count)
|
|
99
|
+
return region
|
|
100
|
+
|
|
101
|
+
def _attribute_setter(self: VertexList, data: Any) -> None:
|
|
102
|
+
buffer = self.domain.attrib_name_buffers[name]
|
|
103
|
+
buffer.set_region(self.start, self.count, data)
|
|
104
|
+
|
|
105
|
+
return property(_attribute_getter, _attribute_setter)
|
|
106
|
+
|
|
107
|
+
class _GLVertexStreamMix(VertexStream):
|
|
108
|
+
_ctx: OpenGLSurfaceContext
|
|
109
|
+
|
|
110
|
+
def __init__(self, ctx: OpenGLSurfaceContext, initial_size: int, attrs: Sequence[Attribute], *, divisor: int = 0):
|
|
111
|
+
super().__init__(ctx, initial_size, attrs, divisor=divisor)
|
|
112
|
+
|
|
113
|
+
def get_graphics_attribute(self, attribute: Attribute, view: AttributeView) -> GLAttribute:
|
|
114
|
+
return GLAttribute(attribute, view)
|
|
115
|
+
|
|
116
|
+
def get_buffer(self, size: int, attribute) -> AttributeBufferObject:
|
|
117
|
+
# TODO: use persistent buffer if we have GL support for it:
|
|
118
|
+
# attribute.buffer = PersistentBufferObject(attribute.stride * self.allocator.capacity, attribute, self.vao)
|
|
119
|
+
return AttributeBufferObject(self._ctx, size, attribute)
|
|
120
|
+
|
|
121
|
+
def bind_into(self, vao) -> None:
|
|
122
|
+
for attribute, buffer in zip(self.attribute_names.values(), self.buffers):
|
|
123
|
+
buffer.bind()
|
|
124
|
+
attribute.enable()
|
|
125
|
+
attribute.set_pointer()
|
|
126
|
+
attribute.set_divisor()
|
|
127
|
+
|
|
128
|
+
class GLVertexStream(_GLVertexStreamMix, VertexStream): # noqa: D101
|
|
129
|
+
def __init__(self, ctx: OpenGLSurfaceContext, initial_size: int, attrs: Sequence[Attribute]) -> None:
|
|
130
|
+
"""Contains data for vertex stream.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
ctx:
|
|
134
|
+
The core context that owns this stream.
|
|
135
|
+
initial_size:
|
|
136
|
+
Initial buffer size.
|
|
137
|
+
attrs:
|
|
138
|
+
Attributes that will be used.
|
|
139
|
+
"""
|
|
140
|
+
super().__init__(ctx, initial_size, attrs)
|
|
141
|
+
|
|
142
|
+
class GLInstanceStream(_GLVertexStreamMix, InstanceStream): # noqa: D101
|
|
143
|
+
_ctx: OpenGLSurfaceContext
|
|
144
|
+
|
|
145
|
+
def __init__(self, ctx: OpenGLSurfaceContext, initial_size: int, attrs: Sequence[Attribute], # noqa: D107
|
|
146
|
+
*, divisor: int = 0) -> None:
|
|
147
|
+
super().__init__(ctx, initial_size, attrs, divisor=divisor)
|
|
148
|
+
|
|
149
|
+
class GLVertexArrayBinding(VertexArrayBinding): # noqa: D101
|
|
150
|
+
|
|
151
|
+
def _create_vao(self) -> VertexArrayProtocol:
|
|
152
|
+
return vertexarray.VertexArray(self._ctx)
|
|
153
|
+
|
|
154
|
+
def _link(self) -> None:
|
|
155
|
+
self.vao.bind()
|
|
156
|
+
for stream in self.streams:
|
|
157
|
+
stream.bind_into(self.vao)
|
|
158
|
+
self.vao.unbind()
|
|
159
|
+
|
|
160
|
+
def bind(self) -> None:
|
|
161
|
+
self.vao.bind()
|
|
162
|
+
|
|
163
|
+
def unbind(self) -> None:
|
|
164
|
+
self.vao.unbind()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class VertexList(VertexListBase):
|
|
168
|
+
"""A list of vertices within a :py:class:`VertexDomain`.
|
|
169
|
+
|
|
170
|
+
Use :py:meth:`VertexDomain.create` to construct this list.
|
|
171
|
+
"""
|
|
172
|
+
count: int
|
|
173
|
+
start: int
|
|
174
|
+
domain: VertexDomain
|
|
175
|
+
indexed: bool = False
|
|
176
|
+
instanced: bool = False
|
|
177
|
+
initial_attribs: dict
|
|
178
|
+
|
|
179
|
+
bucket: VertexGroupBucket | None
|
|
180
|
+
|
|
181
|
+
def __init__(self, domain: VertexDomain, group: Group, start: int, count: int) -> None: # noqa: D107
|
|
182
|
+
super().__init__(domain, group, start, count)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class InstanceVertexList(VertexList):
|
|
187
|
+
"""A list of vertices within an :py:class:`InstancedVertexDomain` that are not indexed."""
|
|
188
|
+
instanced: bool = True
|
|
189
|
+
|
|
190
|
+
def __init__(self, domain: VertexDomain, group: Group, start: int, count: int, bucket: InstanceBucket) -> None: # noqa: D107
|
|
191
|
+
super().__init__(domain, group, start, count)
|
|
192
|
+
self.instance_bucket = bucket
|
|
193
|
+
self.instance_bucket.create_instance()
|
|
194
|
+
|
|
195
|
+
def create_instance(self, **attributes: Any) -> VertexInstanceBase:
|
|
196
|
+
return self.instance_bucket.create_instance(**attributes)
|
|
197
|
+
|
|
198
|
+
def set_attribute_data(self, name: str, data: Any) -> None:
|
|
199
|
+
if self.initial_attribs[name].fmt.is_instanced:
|
|
200
|
+
stream = self.instance_bucket.stream
|
|
201
|
+
count = 1
|
|
202
|
+
start = 0
|
|
203
|
+
else:
|
|
204
|
+
stream = self.domain.attrib_name_buffers[name]
|
|
205
|
+
count = self.count
|
|
206
|
+
start = self.start
|
|
207
|
+
buffer = stream.attrib_name_buffers[name]
|
|
208
|
+
|
|
209
|
+
array_start = buffer.element_count * start
|
|
210
|
+
array_end = buffer.element_count * count + array_start
|
|
211
|
+
try:
|
|
212
|
+
buffer.data[array_start:array_end] = data
|
|
213
|
+
buffer.invalidate_region(start, count)
|
|
214
|
+
except ValueError:
|
|
215
|
+
msg = f"Invalid data size for '{buffer}'. Expected {array_end - array_start}, got {len(data)}."
|
|
216
|
+
raise ValueError(msg) from None
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class IndexedVertexList(IndexedVertexListBase):
|
|
221
|
+
"""A list of vertices within an :py:class:`IndexedVertexDomain` that are indexed.
|
|
222
|
+
|
|
223
|
+
Use :py:meth:`IndexedVertexDomain.create` to construct this list.
|
|
224
|
+
"""
|
|
225
|
+
domain: IndexedVertexDomain | InstancedIndexedVertexDomain
|
|
226
|
+
indexed: bool = True
|
|
227
|
+
|
|
228
|
+
index_count: int
|
|
229
|
+
index_start: int
|
|
230
|
+
|
|
231
|
+
def __init__(self, domain: IndexedVertexDomain, group: Group, start: int, count: int, index_start: int, # noqa: D107
|
|
232
|
+
index_count: int) -> None:
|
|
233
|
+
super().__init__(domain, group, start, count, index_start, index_count)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class InstanceIndexedVertexList(VertexList):
|
|
237
|
+
"""A list of vertices within an :py:class:`IndexedVertexDomain` that are indexed.
|
|
238
|
+
|
|
239
|
+
Use :py:meth:`IndexedVertexDomain.create` to construct this list.
|
|
240
|
+
"""
|
|
241
|
+
domain: IndexedVertexDomain | InstancedIndexedVertexDomain
|
|
242
|
+
indexed: bool = True
|
|
243
|
+
instanced: bool = True
|
|
244
|
+
|
|
245
|
+
index_count: int
|
|
246
|
+
index_start: int
|
|
247
|
+
|
|
248
|
+
instance_bucket: InstanceBucket
|
|
249
|
+
|
|
250
|
+
def __init__(self, domain: IndexedVertexDomain, group: Group, start: int, count: int,
|
|
251
|
+
index_start: int, index_count: int, index_type: DataTypes, base_vertex: int,
|
|
252
|
+
instance_bucket: InstanceBucket) -> None:
|
|
253
|
+
self.index_start = index_start
|
|
254
|
+
self.index_count = index_count
|
|
255
|
+
self.index_type = index_type
|
|
256
|
+
self.base_vertex = base_vertex
|
|
257
|
+
self.instance_bucket = instance_bucket
|
|
258
|
+
self.instance_bucket.create_instance()
|
|
259
|
+
self.start_base_vertex = start if self.supports_base_vertex else 0
|
|
260
|
+
super().__init__(domain, group, start, count)
|
|
261
|
+
|
|
262
|
+
def delete(self) -> None:
|
|
263
|
+
"""Delete this group."""
|
|
264
|
+
raise Exception
|
|
265
|
+
super().delete()
|
|
266
|
+
self.domain.index_allocator.dealloc(self.index_start, self.index_count)
|
|
267
|
+
|
|
268
|
+
def migrate(self, domain: InstancedIndexedVertexDomain) -> None:
|
|
269
|
+
old_domain = self.domain
|
|
270
|
+
|
|
271
|
+
# Moved vertex data here.
|
|
272
|
+
super().migrate(domain)
|
|
273
|
+
|
|
274
|
+
# Remove from bucket and enter into new bucket.
|
|
275
|
+
new_bucket = domain.instance_domain.get_elements_bucket(mode=0,
|
|
276
|
+
first_index=self.index_start,
|
|
277
|
+
index_count=self.index_count,
|
|
278
|
+
index_type="I")
|
|
279
|
+
|
|
280
|
+
# Move instance data.
|
|
281
|
+
old_domain.instance_domain.move_all(self.instance_bucket, new_bucket)
|
|
282
|
+
|
|
283
|
+
def create_instance(self, **attributes: Any) -> None:
|
|
284
|
+
return self.instance_bucket.create_instance(**attributes)
|
|
285
|
+
|
|
286
|
+
def set_attribute_data(self, name: str, data: Any) -> None:
|
|
287
|
+
if self.initial_attribs[name].fmt.is_instanced:
|
|
288
|
+
stream = self.instance_bucket.stream
|
|
289
|
+
count = 1
|
|
290
|
+
start = 0
|
|
291
|
+
else:
|
|
292
|
+
stream = self.domain.attrib_name_buffers[name]
|
|
293
|
+
count = self.count
|
|
294
|
+
start = self.start
|
|
295
|
+
buffer = stream.attrib_name_buffers[name]
|
|
296
|
+
|
|
297
|
+
array_start = buffer.element_count * start
|
|
298
|
+
array_end = buffer.element_count * count + array_start
|
|
299
|
+
try:
|
|
300
|
+
buffer.data[array_start:array_end] = data
|
|
301
|
+
buffer.invalidate_region(start, count)
|
|
302
|
+
except ValueError:
|
|
303
|
+
msg = f"Invalid data size for '{buffer}'. Expected {array_end - array_start}, got {len(data)}."
|
|
304
|
+
raise ValueError(msg) from None
|
|
305
|
+
|
|
306
|
+
def dealloc_from_group(self, vertex_list):
|
|
307
|
+
"""Removes a vertex list from a specific state in this domain."""
|
|
308
|
+
vertex_list.bucket.remove_vertex_list(vertex_list)
|
|
309
|
+
|
|
310
|
+
class VertexDomain(VertexDomainBase):
|
|
311
|
+
"""Management of a set of vertex lists.
|
|
312
|
+
|
|
313
|
+
Construction of a vertex domain is usually done with the
|
|
314
|
+
:py:func:`create_domain` function.
|
|
315
|
+
"""
|
|
316
|
+
_vertex_buckets: dict[Group, VertexGroupBucket]
|
|
317
|
+
streams: list[GLVertexStream | GLInstanceStream | GLIndexStream]
|
|
318
|
+
per_instance: list[Attribute]
|
|
319
|
+
per_vertex: list[Attribute]
|
|
320
|
+
|
|
321
|
+
attribute_meta: dict[str, Attribute]
|
|
322
|
+
buffer_attributes: list[tuple[AttributeBufferObject, Attribute]]
|
|
323
|
+
vao: GLVertexArrayBinding
|
|
324
|
+
attribute_names: dict[str, Attribute]
|
|
325
|
+
attrib_name_buffers: dict[str, GLVertexStream]
|
|
326
|
+
_vertexlist_class: type
|
|
327
|
+
|
|
328
|
+
_vertex_class: type[VertexList] = VertexList
|
|
329
|
+
|
|
330
|
+
def __init__(self, context: OpenGLSurfaceContext, initial_count: int, attribute_meta: dict[str, Attribute]) -> None:
|
|
331
|
+
super().__init__(context, initial_count, attribute_meta)
|
|
332
|
+
|
|
333
|
+
def _has_multi_draw_extension(self, ctx: OpenGLSurfaceContext) -> bool:
|
|
334
|
+
return ctx.get_info().have_extension("GL_EXT_multi_draw_arrays")
|
|
335
|
+
|
|
336
|
+
def draw_bucket(self, mode: int, bucket) -> None:
|
|
337
|
+
bucket.draw(self, mode)
|
|
338
|
+
|
|
339
|
+
def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
|
|
340
|
+
regions = []
|
|
341
|
+
for bucket in buckets:
|
|
342
|
+
regions.extend(bucket.merged_ranges)
|
|
343
|
+
|
|
344
|
+
start_list = [region[0] for region in regions]
|
|
345
|
+
size_list = [region[1] for region in regions]
|
|
346
|
+
primcount = len(regions)
|
|
347
|
+
if self._supports_multi_draw:
|
|
348
|
+
starts = (GLint * primcount)(*start_list)
|
|
349
|
+
sizes = (GLsizei * primcount)(*size_list)
|
|
350
|
+
self._context.glMultiDrawArrays(mode, starts, sizes, primcount)
|
|
351
|
+
else:
|
|
352
|
+
for start, size in zip(start_list, size_list):
|
|
353
|
+
self._context.glDrawArrays(mode, start, size)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _create_vertex_class(self) -> type:
|
|
357
|
+
return type(self._vertex_class.__name__, (self._vertex_class,), self.vertex_buffers._property_dict)
|
|
358
|
+
|
|
359
|
+
def _create_vao(self) -> VertexArrayBinding:
|
|
360
|
+
return GLVertexArrayBinding(self._context, self._streams)
|
|
361
|
+
|
|
362
|
+
def _create_streams(self, size: int) -> list[VertexStream | IndexStream | InstanceStream]:
|
|
363
|
+
self.vertex_buffers = GLVertexStream(self._context, size, self.per_vertex)
|
|
364
|
+
return [self.vertex_buffers]
|
|
365
|
+
|
|
366
|
+
def draw_range(self, mode: int, start: int, count: int) -> None:
|
|
367
|
+
"""Draw a range of vertices.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
"""
|
|
371
|
+
self._context.glDrawArrays(mode, start, count)
|
|
372
|
+
|
|
373
|
+
def draw(self, mode: int) -> None:
|
|
374
|
+
"""Draw all vertices in the domain.
|
|
375
|
+
|
|
376
|
+
All vertices in the domain are drawn at once. This is the
|
|
377
|
+
most efficient way to render primitives.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
mode:
|
|
381
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
382
|
+
|
|
383
|
+
"""
|
|
384
|
+
self.vao.bind()
|
|
385
|
+
self.vertex_buffers.commit()
|
|
386
|
+
|
|
387
|
+
starts, sizes = self.vertex_buffers.allocator.get_allocated_regions()
|
|
388
|
+
primcount = len(starts)
|
|
389
|
+
if primcount == 0:
|
|
390
|
+
pass
|
|
391
|
+
elif primcount == 1:
|
|
392
|
+
# Common case
|
|
393
|
+
self._context.glDrawArrays(mode, starts[0], sizes[0])
|
|
394
|
+
else:
|
|
395
|
+
starts = (GLint * primcount)(*starts)
|
|
396
|
+
sizes = (GLsizei * primcount)(*sizes)
|
|
397
|
+
self._context.glMultiDrawArrays(mode, starts, sizes, primcount)
|
|
398
|
+
|
|
399
|
+
def draw_subset(self, mode: GeometryMode, vertex_list: VertexList) -> None:
|
|
400
|
+
"""Draw a specific VertexList in the domain.
|
|
401
|
+
|
|
402
|
+
The `vertex_list` parameter specifies a :py:class:`VertexList`
|
|
403
|
+
to draw. Only primitives in that list will be drawn.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
mode:
|
|
407
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
408
|
+
vertex_list:
|
|
409
|
+
Vertex list to draw.
|
|
410
|
+
|
|
411
|
+
"""
|
|
412
|
+
self.vao.bind()
|
|
413
|
+
self.vertex_buffers.commit()
|
|
414
|
+
self._context.glDrawArrays(geometry_map[mode], vertex_list.start, vertex_list.count)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
class GLInstanceDomainArrays(BaseInstanceDomain):
|
|
418
|
+
def __init__(self, domain: Any, initial_instances: int) -> None:
|
|
419
|
+
super().__init__(domain, initial_instances)
|
|
420
|
+
self._ctx = domain._context
|
|
421
|
+
|
|
422
|
+
def _create_bucket_arrays(self) -> InstanceBucket:
|
|
423
|
+
istream = GLInstanceStream(self._ctx, self._initial, self._domain.per_instance, divisor=1)
|
|
424
|
+
vao = GLVertexArrayBinding(self._ctx, [self._domain.vertex_buffers, istream])
|
|
425
|
+
return InstanceBucket(istream, vao)
|
|
426
|
+
|
|
427
|
+
def _create_bucket_elements(self) -> InstanceBucket:
|
|
428
|
+
raise NotImplementedError("Use GLInstanceDomainElements for indexed draws")
|
|
429
|
+
|
|
430
|
+
def draw(self, mode: int) -> None:
|
|
431
|
+
for key, bucket in self._buckets.items():
|
|
432
|
+
if bucket.instance_count <= 0:
|
|
433
|
+
continue
|
|
434
|
+
first_vertex, vertex_count = self._geom[bucket]
|
|
435
|
+
bucket.vao.bind()
|
|
436
|
+
bucket.stream.commit()
|
|
437
|
+
self._ctx.glDrawArraysInstanced(mode, first_vertex, vertex_count, bucket.instance_count)
|
|
438
|
+
|
|
439
|
+
def draw_subset(self, mode: int, vertex_list: InstanceVertexList):
|
|
440
|
+
"""Draw a specific VertexList in the domain."""
|
|
441
|
+
bucket = vertex_list.bucket
|
|
442
|
+
bucket.vao.bind()
|
|
443
|
+
bucket.stream.commit()
|
|
444
|
+
self._ctx.glDrawArraysInstanced(mode, vertex_list.start, vertex_list.count, bucket.instance_count)
|
|
445
|
+
|
|
446
|
+
class GLInstanceDomainElements(BaseInstanceDomain):
|
|
447
|
+
_ctx: OpenGLSurfaceContext
|
|
448
|
+
|
|
449
|
+
def __init__(self, domain: Any, initial_instances: int, index_stream: GLIndexStream) -> None:
|
|
450
|
+
super().__init__(domain, initial_instances)
|
|
451
|
+
self._ctx = domain._context
|
|
452
|
+
self._index_stream = index_stream
|
|
453
|
+
self._index_gl_type = self._index_stream.gl_type
|
|
454
|
+
self._elem_size = index_stream.index_element_size
|
|
455
|
+
|
|
456
|
+
def _create_bucket_elements(self) -> InstanceBucket:
|
|
457
|
+
istream = GLInstanceStream(self._ctx, self._initial, self._domain.per_instance, divisor=1)
|
|
458
|
+
vao = GLVertexArrayBinding(self._ctx, [self._domain.vertex_buffers, istream, self._index_stream])
|
|
459
|
+
return InstanceBucket(istream, vao)
|
|
460
|
+
|
|
461
|
+
def _create_bucket_arrays(self) -> InstanceBucket:
|
|
462
|
+
raise NotImplementedError("Use GLInstanceDomainArrays for non-indexed draws")
|
|
463
|
+
|
|
464
|
+
def draw_subset(self, mode: GeometryMode, vertex_list: InstanceIndexedVertexList) -> None:
|
|
465
|
+
"""Draw a specific VertexList in the domain."""
|
|
466
|
+
byte_offset = vertex_list.index_start * self._elem_size
|
|
467
|
+
if vertex_list.start:
|
|
468
|
+
self._ctx.glDrawElementsInstancedBaseVertex(
|
|
469
|
+
mode,
|
|
470
|
+
vertex_list.index_count,
|
|
471
|
+
self._index_gl_type,
|
|
472
|
+
byte_offset,
|
|
473
|
+
vertex_list.bucket.instance_count,
|
|
474
|
+
vertex_list.start,
|
|
475
|
+
)
|
|
476
|
+
else:
|
|
477
|
+
self._ctx.glDrawElementsInstanced(
|
|
478
|
+
mode,
|
|
479
|
+
vertex_list.index_count,
|
|
480
|
+
self._index_gl_type,
|
|
481
|
+
byte_offset,
|
|
482
|
+
vertex_list.bucket.instance_count,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
def draw_bucket(self, mode: int, bucket: InstanceBucket) -> None:
|
|
486
|
+
if bucket.instance_count <= 0:
|
|
487
|
+
return
|
|
488
|
+
first_index, index_count, _, base_vertex = self._geom[bucket]
|
|
489
|
+
byte_offset = first_index * self._elem_size
|
|
490
|
+
bucket.vao.bind()
|
|
491
|
+
bucket.stream.commit()
|
|
492
|
+
if base_vertex:
|
|
493
|
+
self._ctx.glDrawElementsInstancedBaseVertex(
|
|
494
|
+
mode, index_count, self._index_gl_type, byte_offset,
|
|
495
|
+
bucket.instance_count, base_vertex,
|
|
496
|
+
)
|
|
497
|
+
else:
|
|
498
|
+
self._ctx.glDrawElementsInstanced(
|
|
499
|
+
mode, index_count, self._index_gl_type, byte_offset,
|
|
500
|
+
bucket.instance_count,
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
def draw(self, mode: int) -> None:
|
|
504
|
+
for key, bucket in self._buckets.items():
|
|
505
|
+
if bucket.instance_count <= 0:
|
|
506
|
+
continue
|
|
507
|
+
first_index, index_count, _, base_vertex = self._geom[bucket]
|
|
508
|
+
byte_offset = first_index * self._elem_size
|
|
509
|
+
bucket.vao.bind()
|
|
510
|
+
bucket.stream.commit()
|
|
511
|
+
if base_vertex:
|
|
512
|
+
self._ctx.glDrawElementsInstancedBaseVertex(
|
|
513
|
+
mode, index_count, self._index_gl_type, byte_offset,
|
|
514
|
+
bucket.instance_count, base_vertex,
|
|
515
|
+
)
|
|
516
|
+
else:
|
|
517
|
+
self._ctx.glDrawElementsInstanced(
|
|
518
|
+
mode, index_count, self._index_gl_type, byte_offset,
|
|
519
|
+
bucket.instance_count,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
class InstancedVertexDomain(InstancedVertexDomainBase, VertexDomain): # noqa: D101
|
|
523
|
+
_instances: int
|
|
524
|
+
_instance_properties: dict[str, property]
|
|
525
|
+
_vertexinstance_class: type
|
|
526
|
+
_vertex_class = InstanceVertexList
|
|
527
|
+
|
|
528
|
+
def __init__(self, context: OpenGLSurfaceContext, initial_count: int, # noqa: D107
|
|
529
|
+
attribute_meta: dict[str, Attribute]) -> None:
|
|
530
|
+
super().__init__(context, initial_count, attribute_meta)
|
|
531
|
+
|
|
532
|
+
def create_instance_domain(self, size: int) -> GLInstanceDomainArrays:
|
|
533
|
+
return GLInstanceDomainArrays(self, size)
|
|
534
|
+
|
|
535
|
+
def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
|
|
536
|
+
"""Draw a specific VertexGroupBucket in the domain."""
|
|
537
|
+
self.instance_domain.draw(mode)
|
|
538
|
+
|
|
539
|
+
def draw(self, mode: int) -> None:
|
|
540
|
+
"""Draw all vertices in the domain.
|
|
541
|
+
|
|
542
|
+
All vertices in the domain are drawn at once. This is the
|
|
543
|
+
most efficient way to render primitives.
|
|
544
|
+
|
|
545
|
+
Args:
|
|
546
|
+
mode:
|
|
547
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
548
|
+
|
|
549
|
+
"""
|
|
550
|
+
self.vertex_buffers.commit()
|
|
551
|
+
self.instance_domain.draw(mode)
|
|
552
|
+
|
|
553
|
+
def draw_subset(self, mode: GeometryMode, vertex_list: InstanceVertexList) -> None:
|
|
554
|
+
"""Draw a specific VertexList in the domain.
|
|
555
|
+
|
|
556
|
+
The `vertex_list` parameter specifies a :py:class:`VertexList`
|
|
557
|
+
to draw. Only primitives in that list will be drawn.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
mode:
|
|
561
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
562
|
+
vertex_list:
|
|
563
|
+
Vertex list to draw.
|
|
564
|
+
"""
|
|
565
|
+
self.vertex_buffers.commit()
|
|
566
|
+
self.instance_domain.draw_subset(geometry_map[mode], vertex_list)
|
|
567
|
+
|
|
568
|
+
class GLIndexStream(IndexStream): # noqa: D101
|
|
569
|
+
index_element_size: int
|
|
570
|
+
index_c_type: CType
|
|
571
|
+
gl_type: int
|
|
572
|
+
|
|
573
|
+
def __init__(self, ctx: OpenGLSurfaceContext, data_type: DataTypes, initial_elems: int) -> None: # noqa: D107
|
|
574
|
+
self.gl_type = _gl_types[data_type]
|
|
575
|
+
self.index_c_type = _c_types[self.gl_type]
|
|
576
|
+
self.index_element_size = ctypes.sizeof(self.index_c_type)
|
|
577
|
+
super().__init__(ctx, data_type, initial_elems)
|
|
578
|
+
|
|
579
|
+
def _create_buffer(self) -> IndexedBufferObject:
|
|
580
|
+
return IndexedBufferObject(
|
|
581
|
+
self.ctx, self.allocator.capacity * self.index_element_size, self.index_c_type, self.index_element_size, 1,
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
def bind_into(self, vao: VertexArrayBinding) -> None:
|
|
585
|
+
self.buffer.bind_to_index_buffer()
|
|
586
|
+
|
|
587
|
+
class IndexedVertexDomain(IndexedVertexDomainBase):
|
|
588
|
+
"""Management of a set of indexed vertex lists.
|
|
589
|
+
|
|
590
|
+
Construction of an indexed vertex domain is usually done with the
|
|
591
|
+
:py:func:`create_domain` function.
|
|
592
|
+
"""
|
|
593
|
+
vertex_buffers: GLVertexStream
|
|
594
|
+
index_stream: GLIndexStream
|
|
595
|
+
_vertex_class = IndexedVertexList
|
|
596
|
+
_supports_base_vertex: bool
|
|
597
|
+
|
|
598
|
+
def __init__(self, context: OpenGLSurfaceContext, initial_count: int, attribute_meta: dict[str, Attribute], # noqa: D107
|
|
599
|
+
index_type: DataTypes = "I") -> None:
|
|
600
|
+
self.index_type = index_type
|
|
601
|
+
#self._supports_base_vertex = False
|
|
602
|
+
self._supports_base_vertex = context.get_info().have_extension("GL_ARB_draw_elements_base_vertex")
|
|
603
|
+
super().__init__(context, initial_count, attribute_meta)
|
|
604
|
+
|
|
605
|
+
def _has_multi_draw_extension(self, ctx: OpenGLSurfaceContext) -> bool:
|
|
606
|
+
return ctx.get_info().have_extension("GL_EXT_multi_draw_arrays")
|
|
607
|
+
|
|
608
|
+
def _create_vertex_class(self) -> type:
|
|
609
|
+
# Make a custom VertexList class w/ properties for each attribute in the ShaderProgram:
|
|
610
|
+
return type(self._vertex_class.__name__, (_RunningIndexSupport, self._vertex_class),
|
|
611
|
+
self.vertex_buffers._property_dict) # noqa: SLF001
|
|
612
|
+
|
|
613
|
+
def _create_streams(self, size: int) -> list[VertexStream | IndexStream | InstanceStream]:
|
|
614
|
+
self.vertex_buffers = GLVertexStream(self._context, size, self.per_vertex)
|
|
615
|
+
self.index_stream = GLIndexStream(self._context, self.index_type, size)
|
|
616
|
+
return [self.vertex_buffers, self.index_stream]
|
|
617
|
+
|
|
618
|
+
def _create_vao(self) -> VertexArrayBinding:
|
|
619
|
+
return GLVertexArrayBinding(self._context, self._streams)
|
|
620
|
+
|
|
621
|
+
def draw_range(self, mode: int, start: int, count: int) -> None:
|
|
622
|
+
"""Draw a range of vertices."""
|
|
623
|
+
self._context.glDrawElements(
|
|
624
|
+
mode, count, self.index_stream.gl_type, start * self.index_stream.index_element_size,
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
|
|
628
|
+
regions = []
|
|
629
|
+
for bucket in buckets:
|
|
630
|
+
regions.extend(bucket.merged_ranges)
|
|
631
|
+
|
|
632
|
+
start_list = [region[0] for region in regions]
|
|
633
|
+
size_list = [region[1] for region in regions]
|
|
634
|
+
primcount = len(regions)
|
|
635
|
+
|
|
636
|
+
if self._supports_multi_draw:
|
|
637
|
+
starts = [s * self.index_stream.index_element_size for s in start_list]
|
|
638
|
+
starts = (ctypes.POINTER(GLvoid) * primcount)(*(GLintptr * primcount)(*starts))
|
|
639
|
+
sizes = (GLsizei * primcount)(*size_list)
|
|
640
|
+
self._context.glMultiDrawElements(mode, sizes, self.index_stream.gl_type, starts, primcount)
|
|
641
|
+
else:
|
|
642
|
+
for start, size in zip(start_list, size_list):
|
|
643
|
+
self._context.glDrawElements(mode, size, self.index_stream.gl_type,
|
|
644
|
+
start * self.index_stream.index_element_size)
|
|
645
|
+
|
|
646
|
+
def draw(self, mode: int) -> None:
|
|
647
|
+
"""Draw all vertices in the domain.
|
|
648
|
+
|
|
649
|
+
All vertices in the domain are drawn at once. This is the most efficient way to render primitives.
|
|
650
|
+
|
|
651
|
+
Args:
|
|
652
|
+
mode:
|
|
653
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
654
|
+
|
|
655
|
+
"""
|
|
656
|
+
self.vao.bind()
|
|
657
|
+
self.vertex_buffers.commit()
|
|
658
|
+
self.index_stream.buffer.commit()
|
|
659
|
+
|
|
660
|
+
starts, sizes = self.index_stream.allocator.get_allocated_regions()
|
|
661
|
+
primcount = len(starts)
|
|
662
|
+
if primcount == 0:
|
|
663
|
+
pass
|
|
664
|
+
elif primcount == 1:
|
|
665
|
+
# Common case
|
|
666
|
+
self._context.glDrawElements(mode, sizes[0], self.index_stream.gl_type,
|
|
667
|
+
starts[0] * self.index_stream.index_element_size)
|
|
668
|
+
else:
|
|
669
|
+
starts = [s * self.index_stream.index_element_size for s in starts]
|
|
670
|
+
starts = (ctypes.POINTER(GLvoid) * primcount)(*(GLintptr * primcount)(*starts))
|
|
671
|
+
sizes = (GLsizei * primcount)(*sizes)
|
|
672
|
+
self._context.glMultiDrawElements(mode, sizes, self.index_stream.gl_type, starts, primcount)
|
|
673
|
+
|
|
674
|
+
def draw_subset(self, mode: GeometryMode, vertex_list: IndexedVertexList) -> None:
|
|
675
|
+
"""Draw a specific IndexedVertexList in the domain.
|
|
676
|
+
|
|
677
|
+
The `vertex_list` parameter specifies a :py:class:`IndexedVertexList`
|
|
678
|
+
to draw. Only primitives in that list will be drawn.
|
|
679
|
+
|
|
680
|
+
Args:
|
|
681
|
+
mode:
|
|
682
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
683
|
+
vertex_list:
|
|
684
|
+
Vertex list to draw.
|
|
685
|
+
"""
|
|
686
|
+
self.vao.bind()
|
|
687
|
+
self.vertex_buffers.commit()
|
|
688
|
+
self.index_stream.buffer.commit()
|
|
689
|
+
|
|
690
|
+
self._context.glDrawElements(
|
|
691
|
+
geometry_map[mode],
|
|
692
|
+
vertex_list.index_count,
|
|
693
|
+
self.index_stream.gl_type,
|
|
694
|
+
vertex_list.index_start * self.index_stream.index_element_size,
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
class InstancedIndexedVertexDomain(InstancedIndexedVertexDomainBase, IndexedVertexDomain):
|
|
699
|
+
"""Management of a set of indexed vertex lists.
|
|
700
|
+
|
|
701
|
+
Construction of an indexed vertex domain is usually done with the
|
|
702
|
+
:py:func:`create_domain` function.
|
|
703
|
+
"""
|
|
704
|
+
_initial_index_count: int = 16
|
|
705
|
+
_vertex_class = InstanceIndexedVertexList
|
|
706
|
+
|
|
707
|
+
def __init__(self, context: OpenGLSurfaceContext, initial_count: int, attribute_meta: dict[str, dict[str, Any]],
|
|
708
|
+
index_type: DataTypes = "I") -> None:
|
|
709
|
+
super().__init__(context, initial_count, attribute_meta, index_type)
|
|
710
|
+
self._instance_map = {}
|
|
711
|
+
|
|
712
|
+
def create_instance_domain(self, size: int) -> GLInstanceDomainElements:
|
|
713
|
+
return GLInstanceDomainElements(self, size, index_stream=self.index_stream)
|
|
714
|
+
|
|
715
|
+
def draw_buckets(self, mode: int, buckets: list[VertexGroupBucket]) -> None:
|
|
716
|
+
"""Draw a specific VertexGroupBucket in the domain."""
|
|
717
|
+
for bucket in buckets:
|
|
718
|
+
for vl_range in bucket.ranges:
|
|
719
|
+
self.instance_domain.draw_bucket(mode, self._instance_map[vl_range])
|
|
720
|
+
|
|
721
|
+
def draw(self, mode: int) -> None:
|
|
722
|
+
"""Draw all vertices in the domain.
|
|
723
|
+
|
|
724
|
+
All vertices in the domain are drawn at once. This is the
|
|
725
|
+
most efficient way to render primitives.
|
|
726
|
+
|
|
727
|
+
Args:
|
|
728
|
+
mode:
|
|
729
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
730
|
+
|
|
731
|
+
"""
|
|
732
|
+
self.vertex_buffers.commit()
|
|
733
|
+
self.index_stream.commit()
|
|
734
|
+
self.instance_domain.draw(mode)
|
|
735
|
+
|
|
736
|
+
def draw_subset(self, mode: GeometryMode, vertex_list: InstanceIndexedVertexList) -> None:
|
|
737
|
+
"""Draw a specific IndexedVertexList in the domain.
|
|
738
|
+
|
|
739
|
+
The ``vertex_list`` parameter specifies a :py:class:`IndexedVertexList`
|
|
740
|
+
to draw. Only primitives in that list will be drawn.
|
|
741
|
+
|
|
742
|
+
Args:
|
|
743
|
+
mode:
|
|
744
|
+
OpenGL drawing mode, e.g. ``GL_POINTS``, ``GL_LINES``, etc.
|
|
745
|
+
vertex_list:
|
|
746
|
+
Vertex list to draw.
|
|
747
|
+
|
|
748
|
+
"""
|
|
749
|
+
self.vertex_buffers.commit()
|
|
750
|
+
self.index_stream.commit()
|
|
751
|
+
self.instance_domain.draw_subset(geometry_map[mode], vertex_list)
|