pyglet 3.0.dev5__py3-none-any.whl → 3.0.dev6__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 +1 -1
- pyglet/event.py +3 -23
- pyglet/graphics/__init__.py +2 -0
- pyglet/graphics/api/gl/state.py +22 -5
- pyglet/graphics/api/gl2/state.py +2 -2
- pyglet/graphics/api/webgl/state.py +24 -5
- pyglet/graphics/buffer.py +83 -0
- pyglet/graphics/draw.py +19 -5
- pyglet/graphics/shader.py +29 -8
- pyglet/graphics/state.py +3 -1
- pyglet/libs/win32/__init__.py +10 -0
- pyglet/libs/win32/constants.py +13 -0
- pyglet/libs/win32/context_managers.py +66 -1
- pyglet/libs/win32/types.py +71 -0
- pyglet/window/__init__.py +47 -0
- pyglet/window/camera/base.py +15 -31
- pyglet/window/cocoa/pyglet_view.py +69 -20
- pyglet/window/win32/__init__.py +172 -12
- pyglet/window/xlib/__init__.py +58 -0
- {pyglet-3.0.dev5.dist-info → pyglet-3.0.dev6.dist-info}/METADATA +1 -1
- {pyglet-3.0.dev5.dist-info → pyglet-3.0.dev6.dist-info}/RECORD +23 -23
- {pyglet-3.0.dev5.dist-info → pyglet-3.0.dev6.dist-info}/WHEEL +0 -0
- {pyglet-3.0.dev5.dist-info → pyglet-3.0.dev6.dist-info}/licenses/LICENSE +0 -0
pyglet/__init__.py
CHANGED
pyglet/event.py
CHANGED
|
@@ -121,7 +121,6 @@ from __future__ import annotations
|
|
|
121
121
|
import inspect
|
|
122
122
|
import os.path
|
|
123
123
|
|
|
124
|
-
from functools import partial
|
|
125
124
|
from typing import TYPE_CHECKING, Literal, Union
|
|
126
125
|
from weakref import WeakMethod
|
|
127
126
|
|
|
@@ -193,7 +192,7 @@ class EventDispatcher:
|
|
|
193
192
|
msg = f'Unknown event "{name}"'
|
|
194
193
|
raise EventException(msg)
|
|
195
194
|
if inspect.ismethod(obj):
|
|
196
|
-
yield name, WeakMethod(obj
|
|
195
|
+
yield name, WeakMethod(obj)
|
|
197
196
|
else:
|
|
198
197
|
yield name, obj
|
|
199
198
|
else:
|
|
@@ -201,7 +200,7 @@ class EventDispatcher:
|
|
|
201
200
|
for name in dir(obj):
|
|
202
201
|
if name in self.event_types:
|
|
203
202
|
meth = getattr(obj, name)
|
|
204
|
-
yield name, WeakMethod(meth
|
|
203
|
+
yield name, WeakMethod(meth)
|
|
205
204
|
|
|
206
205
|
for name, handler in kwargs.items():
|
|
207
206
|
# Function for handling given event (no magic)
|
|
@@ -209,7 +208,7 @@ class EventDispatcher:
|
|
|
209
208
|
msg = f'Unknown event "{name}"'
|
|
210
209
|
raise EventException(msg)
|
|
211
210
|
if inspect.ismethod(handler):
|
|
212
|
-
yield name, WeakMethod(handler
|
|
211
|
+
yield name, WeakMethod(handler)
|
|
213
212
|
else:
|
|
214
213
|
yield name, handler
|
|
215
214
|
|
|
@@ -303,25 +302,6 @@ class EventDispatcher:
|
|
|
303
302
|
except KeyError:
|
|
304
303
|
pass
|
|
305
304
|
|
|
306
|
-
def _remove_handler(self, name: str, handler: Callable) -> None:
|
|
307
|
-
"""Used internally to remove all handler instances for the given event name.
|
|
308
|
-
|
|
309
|
-
This is normally called from a dead ``WeakMethod`` to remove itself from the
|
|
310
|
-
event stack.
|
|
311
|
-
"""
|
|
312
|
-
# Iterate over a copy as we might mutate the list
|
|
313
|
-
for frame in list(self._event_stack):
|
|
314
|
-
|
|
315
|
-
if name in frame:
|
|
316
|
-
try:
|
|
317
|
-
if frame[name] == handler:
|
|
318
|
-
del frame[name]
|
|
319
|
-
if not frame:
|
|
320
|
-
self._event_stack.remove(frame)
|
|
321
|
-
except TypeError:
|
|
322
|
-
# weakref is already dead
|
|
323
|
-
pass
|
|
324
|
-
|
|
325
305
|
def dispatch_event(self, event_type: str, *args: Any) -> bool | None:
|
|
326
306
|
"""Dispatch an event to the attached event handlers.
|
|
327
307
|
|
pyglet/graphics/__init__.py
CHANGED
|
@@ -37,6 +37,7 @@ if TYPE_CHECKING:
|
|
|
37
37
|
from pyglet.graphics.shader import Shader, ShaderProgram, ComputeShaderProgram, TransformFeedbackShaderProgram # noqa: F401
|
|
38
38
|
from pyglet.graphics.state import State # noqa: F401
|
|
39
39
|
from pyglet.graphics.shader import get_default_shader # noqa: F401
|
|
40
|
+
from pyglet.graphics.buffer import UniformBufferRegion # noqa: F401
|
|
40
41
|
from pyglet.graphics.draw import get_default_batch # noqa: F401
|
|
41
42
|
from pyglet.graphics.texture import Texture, TextureGrid, Texture3D, TextureArray # noqa: F401
|
|
42
43
|
from pyglet.graphics.atlas import TextureBin, TextureArrayBin, TextureAtlas # noqa: F401
|
|
@@ -53,6 +54,7 @@ else:
|
|
|
53
54
|
)
|
|
54
55
|
from pyglet.graphics.state import State # noqa: F401
|
|
55
56
|
from pyglet.graphics.api import core # noqa: F401
|
|
57
|
+
from pyglet.graphics.buffer import UniformBufferRegion # noqa: F401
|
|
56
58
|
from pyglet.graphics.texture import Texture, TextureGrid, Texture3D, TextureArray # noqa: F401
|
|
57
59
|
from pyglet.graphics.atlas import TextureBin, TextureArrayBin, TextureAtlas # noqa: F401
|
|
58
60
|
from pyglet.graphics.framebuffer import Framebuffer, Renderbuffer # noqa: F401
|
pyglet/graphics/api/gl/state.py
CHANGED
|
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
from pyglet.customtypes import ScissorProtocol
|
|
17
17
|
from pyglet.graphics.draw import DrawContext
|
|
18
18
|
from pyglet.graphics.api.gl.shader import ShaderProgram
|
|
19
|
+
from pyglet.graphics.buffer import UniformBufferRegion
|
|
19
20
|
from pyglet.graphics.texture import Texture
|
|
20
21
|
|
|
21
22
|
|
|
@@ -50,8 +51,9 @@ class TextureState(State): # noqa: D101
|
|
|
50
51
|
|
|
51
52
|
@dataclass(frozen=True)
|
|
52
53
|
class MultiTextureSamplerState(State):
|
|
53
|
-
"""
|
|
54
|
+
"""Texture bindings and sampler uniforms for multi-texture draws."""
|
|
54
55
|
program: ShaderProgram
|
|
56
|
+
textures: tuple[tuple[tuple[int, int], int, int], ...]
|
|
55
57
|
uniforms: tuple[tuple[str, int], ...]
|
|
56
58
|
|
|
57
59
|
sets_state: bool = True
|
|
@@ -61,10 +63,20 @@ class MultiTextureSamplerState(State):
|
|
|
61
63
|
cls,
|
|
62
64
|
program: ShaderProgram,
|
|
63
65
|
textures: dict[str, Texture],
|
|
64
|
-
first_texture_unit: int = 0
|
|
65
|
-
|
|
66
|
+
first_texture_unit: int = 0,
|
|
67
|
+
set_id: int = 0) -> MultiTextureSamplerState:
|
|
68
|
+
texture_states = tuple(
|
|
69
|
+
((texture.target, texture.id), texture_unit, set_id)
|
|
70
|
+
for texture_unit, texture in enumerate(textures.values(), first_texture_unit)
|
|
71
|
+
)
|
|
72
|
+
uniforms = tuple((name, idx) for idx, name in enumerate(textures, first_texture_unit))
|
|
73
|
+
return cls(program, texture_states, uniforms)
|
|
66
74
|
|
|
67
75
|
def set_state(self, ctx: DrawContext) -> None:
|
|
76
|
+
for texture, texture_unit, _set_id in self.textures:
|
|
77
|
+
ctx.surface_ctx.glActiveTexture(GL_TEXTURE0 + texture_unit)
|
|
78
|
+
ctx.surface_ctx.glBindTexture(*texture)
|
|
79
|
+
|
|
68
80
|
for uniform_name, texture_unit in self.uniforms:
|
|
69
81
|
self.program[uniform_name] = texture_unit
|
|
70
82
|
|
|
@@ -216,8 +228,13 @@ class ViewportState(_BaseViewportState):
|
|
|
216
228
|
|
|
217
229
|
@dataclass(frozen=True)
|
|
218
230
|
class UniformBufferState(State):
|
|
219
|
-
|
|
220
|
-
|
|
231
|
+
region: UniformBufferRegion
|
|
232
|
+
binding_index: int | None = None
|
|
233
|
+
|
|
234
|
+
sets_state: bool = True
|
|
235
|
+
|
|
236
|
+
def set_state(self, ctx: DrawContext) -> None:
|
|
237
|
+
self.region.bind(binding_index=self.binding_index)
|
|
221
238
|
|
|
222
239
|
|
|
223
240
|
@dataclass(frozen=True)
|
pyglet/graphics/api/gl2/state.py
CHANGED
|
@@ -5,7 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from pyglet.graphics.state import State
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
from pyglet.graphics.api.gl.state import (TextureState, MultiTextureSamplerState, BlendState, ShaderUniformState, # noqa: F401
|
|
8
|
-
DepthBufferComparison, ScissorState, ViewportState)
|
|
8
|
+
DepthBufferComparison, ScissorState, UniformBufferState, ViewportState)
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
@@ -24,6 +24,6 @@ class ShaderProgramState(State):
|
|
|
24
24
|
ctx.active_shader_program = self.program
|
|
25
25
|
|
|
26
26
|
if ctx.active_camera and ctx.active_camera.view.storage:
|
|
27
|
-
ctx.active_camera.view.storage.
|
|
27
|
+
ctx.active_camera.view.storage.bind_camera(ctx)
|
|
28
28
|
|
|
29
29
|
|
|
@@ -10,6 +10,7 @@ from pyglet.graphics.state import State, _BaseScissorState, _BaseViewportState
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from pyglet.customtypes import ScissorProtocol
|
|
13
|
+
from pyglet.graphics.buffer import UniformBufferRegion
|
|
13
14
|
from pyglet.graphics.api.webgl.shader import ShaderProgram
|
|
14
15
|
from pyglet.graphics.draw import DrawContext
|
|
15
16
|
from pyglet.graphics.texture import Texture
|
|
@@ -53,9 +54,11 @@ class TextureState(State): # noqa: D101
|
|
|
53
54
|
|
|
54
55
|
@dataclass(frozen=True)
|
|
55
56
|
class MultiTextureSamplerState(State):
|
|
56
|
-
"""
|
|
57
|
+
"""Texture bindings and sampler uniforms for multi-texture draws."""
|
|
57
58
|
program: ShaderProgram
|
|
59
|
+
textures: tuple[tuple[tuple[int, int], int, int], ...]
|
|
58
60
|
uniforms: tuple[tuple[str, int], ...]
|
|
61
|
+
webgl_textures: tuple[Any, ...] = field(hash=False, compare=False)
|
|
59
62
|
|
|
60
63
|
sets_state: bool = True
|
|
61
64
|
|
|
@@ -64,10 +67,21 @@ class MultiTextureSamplerState(State):
|
|
|
64
67
|
cls,
|
|
65
68
|
program: ShaderProgram,
|
|
66
69
|
textures: dict[str, Texture],
|
|
67
|
-
first_texture_unit: int = 0
|
|
68
|
-
|
|
70
|
+
first_texture_unit: int = 0,
|
|
71
|
+
set_id: int = 0) -> MultiTextureSamplerState:
|
|
72
|
+
texture_states = tuple(
|
|
73
|
+
((texture.target, id(texture.id)), texture_unit, set_id)
|
|
74
|
+
for texture_unit, texture in enumerate(textures.values(), first_texture_unit)
|
|
75
|
+
)
|
|
76
|
+
uniforms = tuple((name, idx) for idx, name in enumerate(textures, first_texture_unit))
|
|
77
|
+
webgl_textures = tuple(texture.id for texture in textures.values())
|
|
78
|
+
return cls(program, texture_states, uniforms, webgl_textures)
|
|
69
79
|
|
|
70
80
|
def set_state(self, ctx: DrawContext) -> None:
|
|
81
|
+
for (texture, texture_unit, _set_id), webgl_texture in zip(self.textures, self.webgl_textures):
|
|
82
|
+
ctx.surface_ctx.gl.activeTexture(GL_TEXTURE0 + texture_unit)
|
|
83
|
+
ctx.surface_ctx.gl.bindTexture(texture[0], webgl_texture)
|
|
84
|
+
|
|
71
85
|
for uniform_name, texture_unit in self.uniforms:
|
|
72
86
|
self.program[uniform_name] = texture_unit
|
|
73
87
|
|
|
@@ -203,8 +217,13 @@ class ViewportState(_BaseViewportState):
|
|
|
203
217
|
|
|
204
218
|
@dataclass(frozen=True)
|
|
205
219
|
class UniformBufferState(State):
|
|
206
|
-
|
|
207
|
-
|
|
220
|
+
region: UniformBufferRegion
|
|
221
|
+
binding_index: int | None = None
|
|
222
|
+
|
|
223
|
+
sets_state: bool = True
|
|
224
|
+
|
|
225
|
+
def set_state(self, ctx: DrawContext) -> None:
|
|
226
|
+
self.region.bind(binding_index=self.binding_index)
|
|
208
227
|
|
|
209
228
|
|
|
210
229
|
@dataclass(frozen=True)
|
pyglet/graphics/buffer.py
CHANGED
|
@@ -464,6 +464,89 @@ class UniformBufferObject(RingBuffer):
|
|
|
464
464
|
)
|
|
465
465
|
|
|
466
466
|
|
|
467
|
+
class UniformBufferRegion:
|
|
468
|
+
"""UBO region that uploads through a ring-buffered ``UniformBufferObject``.
|
|
469
|
+
|
|
470
|
+
The region owns one CPU-side data structure and a set of GPU ranges.
|
|
471
|
+
|
|
472
|
+
General practice is to update the data structure, mark it dirty, and then commit when you are done updating
|
|
473
|
+
for that frame.
|
|
474
|
+
|
|
475
|
+
.. warning:: Do not make the CPU-side data dirty after binding/committing during the same frame (for example,
|
|
476
|
+
during the ``on_draw`` call), or GPU stalls may occur.
|
|
477
|
+
|
|
478
|
+
.. versionadded:: 3.0
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
__slots__ = (
|
|
482
|
+
"_current_binding",
|
|
483
|
+
"_current_range",
|
|
484
|
+
"_dirty",
|
|
485
|
+
"_next_range_index",
|
|
486
|
+
"_ranges",
|
|
487
|
+
"_ubo",
|
|
488
|
+
"data",
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
def __init__(
|
|
492
|
+
self,
|
|
493
|
+
ubo: UniformBufferObject,
|
|
494
|
+
*,
|
|
495
|
+
copies_per_resource: int | None = None,
|
|
496
|
+
) -> None:
|
|
497
|
+
self._ubo = ubo
|
|
498
|
+
self.data = ubo.get_data_structure()
|
|
499
|
+
self._current_binding: BufferBindingSlice | None = None
|
|
500
|
+
self._current_range: BufferRange | None = None
|
|
501
|
+
self._ranges = ubo.reserve_resource_range(copies_per_resource=copies_per_resource)
|
|
502
|
+
self._next_range_index = 0
|
|
503
|
+
self._dirty = True
|
|
504
|
+
|
|
505
|
+
@property
|
|
506
|
+
def ubo(self) -> UniformBufferObject:
|
|
507
|
+
"""The underlying ``UniformBufferObject``."""
|
|
508
|
+
return self._ubo
|
|
509
|
+
|
|
510
|
+
@property
|
|
511
|
+
def dirty(self) -> bool:
|
|
512
|
+
"""Whether the CPU-side data needs to be uploaded before drawing."""
|
|
513
|
+
return self._dirty
|
|
514
|
+
|
|
515
|
+
def __enter__(self) -> ctypes.Structure:
|
|
516
|
+
return self.data
|
|
517
|
+
|
|
518
|
+
def __exit__(self, _exc_type: Any, _exc_val: Any, _exc_tb: Any) -> None:
|
|
519
|
+
self.mark_dirty()
|
|
520
|
+
|
|
521
|
+
def mark_dirty(self) -> None:
|
|
522
|
+
"""Mark the CPU-side data for upload on the next ``bind`` call."""
|
|
523
|
+
self._dirty = True
|
|
524
|
+
|
|
525
|
+
def commit(self) -> None:
|
|
526
|
+
"""Upload dirty CPU-side data to the next writable GPU range."""
|
|
527
|
+
if not self._dirty:
|
|
528
|
+
return
|
|
529
|
+
|
|
530
|
+
self._current_binding, self._current_range, self._next_range_index = (
|
|
531
|
+
self._ubo.upload_to_available_binding_from_ranges(
|
|
532
|
+
self.data,
|
|
533
|
+
self._ranges,
|
|
534
|
+
self._next_range_index,
|
|
535
|
+
)
|
|
536
|
+
)
|
|
537
|
+
self._dirty = False
|
|
538
|
+
|
|
539
|
+
def bind(self, *, binding_index: int | None = None) -> None:
|
|
540
|
+
"""Upload dirty data if needed, then bind the current GPU range."""
|
|
541
|
+
self.commit()
|
|
542
|
+
|
|
543
|
+
if self._current_binding is None or self._current_range is None:
|
|
544
|
+
return
|
|
545
|
+
|
|
546
|
+
self._ubo.use_range(self._current_range)
|
|
547
|
+
self._ubo.bind_slice(self._current_binding, binding_index=binding_index)
|
|
548
|
+
|
|
549
|
+
|
|
467
550
|
class MappedBufferObject(AbstractBuffer):
|
|
468
551
|
"""A GPU buffer that supports map/unmap and range mapping."""
|
|
469
552
|
|
pyglet/graphics/draw.py
CHANGED
|
@@ -23,10 +23,12 @@ from pyglet.graphics.state import (
|
|
|
23
23
|
ShaderUniformState,
|
|
24
24
|
State,
|
|
25
25
|
TextureState,
|
|
26
|
+
UniformBufferState,
|
|
26
27
|
ViewportState,
|
|
27
28
|
_expand_states_in_order,
|
|
28
29
|
)
|
|
29
30
|
if TYPE_CHECKING:
|
|
31
|
+
from pyglet.graphics.buffer import UniformBufferRegion
|
|
30
32
|
from pyglet.window.camera.base import BaseCamera, CameraScissor
|
|
31
33
|
from pyglet.customtypes import ScissorProtocol
|
|
32
34
|
from pyglet.graphics.shader import ShaderProgram
|
|
@@ -99,6 +101,7 @@ class Group:
|
|
|
99
101
|
|
|
100
102
|
If the state is an enforced state, setting a new state will not update any children.
|
|
101
103
|
"""
|
|
104
|
+
assert not self.batches, "New states cannot be set once a group is in a batch."
|
|
102
105
|
state_type = type(state)
|
|
103
106
|
self._state_names[state_type.__name__] = state
|
|
104
107
|
group_states = self._state_names.values()
|
|
@@ -145,9 +148,21 @@ class Group:
|
|
|
145
148
|
def set_shader_program(self, program: ShaderProgram):
|
|
146
149
|
self.set_state(ShaderProgramState(program))
|
|
147
150
|
|
|
148
|
-
def set_shader_uniforms(self, program: ShaderProgram, uniforms: dict[str, Any]):
|
|
151
|
+
def set_shader_uniforms(self, program: ShaderProgram, uniforms: dict[str, Any]) -> None:
|
|
149
152
|
self.set_state(ShaderUniformState(program, uniforms))
|
|
150
153
|
|
|
154
|
+
def set_uniform_buffer(self, region: UniformBufferRegion, binding_index: int | None = None) -> None:
|
|
155
|
+
"""Set a Uniform Buffer Object region state.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
region:
|
|
159
|
+
A region created by ``UniformBlock.create_ubo_region``.
|
|
160
|
+
binding_index:
|
|
161
|
+
Optional binding point override. By default, the region uses
|
|
162
|
+
the binding point assigned to its source uniform block.
|
|
163
|
+
"""
|
|
164
|
+
self.set_state(UniformBufferState(region, binding_index))
|
|
165
|
+
|
|
151
166
|
def set_texture(self, texture: Texture, texture_unit: int=0, set_id: int=0) -> None:
|
|
152
167
|
"""Set the texture state.
|
|
153
168
|
|
|
@@ -161,6 +176,7 @@ class Group:
|
|
|
161
176
|
set_id:
|
|
162
177
|
The set that the sampler belongs to. Only applicable in Vulkan.
|
|
163
178
|
"""
|
|
179
|
+
self._state_names.pop(MultiTextureSamplerState.__name__, None)
|
|
164
180
|
self.set_state(TextureState.from_texture(texture, texture_unit, set_id))
|
|
165
181
|
|
|
166
182
|
def set_textures(
|
|
@@ -181,10 +197,8 @@ class Group:
|
|
|
181
197
|
set_id:
|
|
182
198
|
The set that the sampler belongs to. Only applicable in Vulkan.
|
|
183
199
|
"""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
self.set_state(MultiTextureSamplerState.from_textures(program, textures, first_texture_unit))
|
|
200
|
+
self._state_names.pop(TextureState.__name__, None)
|
|
201
|
+
self.set_state(MultiTextureSamplerState.from_textures(program, textures, first_texture_unit, set_id))
|
|
188
202
|
|
|
189
203
|
@property
|
|
190
204
|
def order(self) -> int:
|
pyglet/graphics/shader.py
CHANGED
|
@@ -9,21 +9,26 @@ import weakref
|
|
|
9
9
|
from abc import ABC, abstractmethod
|
|
10
10
|
from collections import defaultdict
|
|
11
11
|
from dataclasses import dataclass
|
|
12
|
-
from typing import
|
|
12
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal, Protocol, Sequence, overload
|
|
13
13
|
|
|
14
14
|
import pyglet
|
|
15
15
|
from pyglet.enums import GraphicsAPI
|
|
16
|
+
from pyglet.graphics.buffer import UniformBufferRegion
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
18
|
-
from pyglet.graphics.buffer import (
|
|
19
|
-
UniformBufferObject,
|
|
20
|
-
)
|
|
21
|
-
from pyglet.customtypes import DataTypes, CType
|
|
22
|
-
from pyglet.graphics.vertexdomain import IndexedVertexList, VertexList, InstanceIndexedVertexList, InstanceVertexList
|
|
23
|
-
from pyglet.graphics import Batch, Group
|
|
24
|
-
from pyglet.enums import GeometryMode
|
|
25
19
|
from _weakref import CallableProxyType
|
|
26
20
|
|
|
21
|
+
from pyglet.customtypes import CType, DataTypes
|
|
22
|
+
from pyglet.enums import GeometryMode
|
|
23
|
+
from pyglet.graphics import Batch, Group
|
|
24
|
+
from pyglet.graphics.buffer import UniformBufferObject
|
|
25
|
+
from pyglet.graphics.vertexdomain import (
|
|
26
|
+
IndexedVertexList,
|
|
27
|
+
InstanceIndexedVertexList,
|
|
28
|
+
InstanceVertexList,
|
|
29
|
+
VertexList,
|
|
30
|
+
)
|
|
31
|
+
|
|
27
32
|
|
|
28
33
|
class ShaderException(BaseException):
|
|
29
34
|
pass
|
|
@@ -967,6 +972,22 @@ class UniformBlock:
|
|
|
967
972
|
strict,
|
|
968
973
|
)
|
|
969
974
|
|
|
975
|
+
def create_ubo_region(
|
|
976
|
+
self,
|
|
977
|
+
*,
|
|
978
|
+
copies_per_resource: int = 3,
|
|
979
|
+
alignment: int | None = None,
|
|
980
|
+
strict: bool = False,
|
|
981
|
+
) -> UniformBufferRegion:
|
|
982
|
+
"""Create a ring-buffered region for updating and binding this uniform block."""
|
|
983
|
+
|
|
984
|
+
ubo = self.create_ubo(
|
|
985
|
+
copies_per_resource=copies_per_resource,
|
|
986
|
+
alignment=alignment,
|
|
987
|
+
strict=strict,
|
|
988
|
+
)
|
|
989
|
+
return UniformBufferRegion(ubo, copies_per_resource=copies_per_resource)
|
|
990
|
+
|
|
970
991
|
def set_binding(self, binding: int) -> None:
|
|
971
992
|
"""Rebind the Uniform Block to a new binding index number.
|
|
972
993
|
|
pyglet/graphics/state.py
CHANGED
|
@@ -8,8 +8,8 @@ import pyglet
|
|
|
8
8
|
|
|
9
9
|
from pyglet.enums import GraphicsAPI
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
if TYPE_CHECKING:
|
|
12
|
+
from pyglet.window.camera.base import _CameraViewBase
|
|
13
13
|
from pyglet.customtypes import ScissorProtocol
|
|
14
14
|
from pyglet.graphics.draw import DrawContext
|
|
15
15
|
from pyglet.window.camera import ViewportType
|
|
@@ -62,6 +62,7 @@ class State:
|
|
|
62
62
|
@runtime_checkable
|
|
63
63
|
class CameraScopeProtocol(Protocol):
|
|
64
64
|
"""Protocol for camera objects used by camera scope states."""
|
|
65
|
+
view: _CameraViewBase
|
|
65
66
|
|
|
66
67
|
@property
|
|
67
68
|
def viewport(self) -> ViewportType:
|
|
@@ -180,6 +181,7 @@ MultiTextureSamplerState: type[State] = _backend_state.MultiTextureSamplerState
|
|
|
180
181
|
ShaderProgramState: type[State] = _backend_state.ShaderProgramState
|
|
181
182
|
BlendState: type[State] = _backend_state.BlendState
|
|
182
183
|
ShaderUniformState: type[State] = _backend_state.ShaderUniformState
|
|
184
|
+
UniformBufferState: type[State] = _backend_state.UniformBufferState
|
|
183
185
|
DepthBufferComparison: type[State] = _backend_state.DepthBufferComparison
|
|
184
186
|
ScissorState: type[State] = _backend_state.ScissorState
|
|
185
187
|
ViewportState: type[State] = _backend_state.ViewportState
|
pyglet/libs/win32/__init__.py
CHANGED
|
@@ -288,6 +288,10 @@ _ole32.CoInitialize.restype = HRESULT
|
|
|
288
288
|
_ole32.CoInitialize.argtypes = [LPVOID]
|
|
289
289
|
_ole32.CoInitializeEx.restype = HRESULT
|
|
290
290
|
_ole32.CoInitializeEx.argtypes = [LPVOID, DWORD]
|
|
291
|
+
_ole32.OleInitialize.restype = HRESULT
|
|
292
|
+
_ole32.OleInitialize.argtypes = [LPVOID]
|
|
293
|
+
_ole32.OleUninitialize.restype = c_void
|
|
294
|
+
_ole32.OleUninitialize.argtypes = []
|
|
291
295
|
_ole32.CoUninitialize.restype = HRESULT
|
|
292
296
|
_ole32.CoUninitialize.argtypes = []
|
|
293
297
|
_ole32.PropVariantClear.restype = HRESULT
|
|
@@ -296,6 +300,12 @@ _ole32.CoCreateInstance.restype = HRESULT
|
|
|
296
300
|
_ole32.CoCreateInstance.argtypes = [com.REFIID, c_void_p, DWORD, com.REFIID, c_void_p]
|
|
297
301
|
_ole32.CoSetProxyBlanket.restype = HRESULT
|
|
298
302
|
_ole32.CoSetProxyBlanket.argtypes = (c_void_p, DWORD, DWORD, c_void_p, DWORD, DWORD, c_void_p, DWORD)
|
|
303
|
+
_ole32.RegisterDragDrop.restype = HRESULT
|
|
304
|
+
_ole32.RegisterDragDrop.argtypes = [HWND, c_void_p]
|
|
305
|
+
_ole32.RevokeDragDrop.restype = HRESULT
|
|
306
|
+
_ole32.RevokeDragDrop.argtypes = [HWND]
|
|
307
|
+
_ole32.ReleaseStgMedium.restype = c_void
|
|
308
|
+
_ole32.ReleaseStgMedium.argtypes = [POINTER(STGMEDIUM)]
|
|
299
309
|
|
|
300
310
|
# oleaut32
|
|
301
311
|
_oleaut32.VariantInit.restype = c_void_p
|
pyglet/libs/win32/constants.py
CHANGED
|
@@ -4159,6 +4159,19 @@ CF_PRIVATEFIRST = 512
|
|
|
4159
4159
|
CF_PRIVATELAST = 767
|
|
4160
4160
|
CF_GDIOBJFIRST = 768
|
|
4161
4161
|
CF_GDIOBJLAST = 1023
|
|
4162
|
+
DVASPECT_CONTENT = 1
|
|
4163
|
+
TYMED_HGLOBAL = 1
|
|
4164
|
+
TYMED_FILE = 2
|
|
4165
|
+
TYMED_ISTREAM = 4
|
|
4166
|
+
TYMED_ISTORAGE = 8
|
|
4167
|
+
TYMED_GDI = 16
|
|
4168
|
+
TYMED_MFPICT = 32
|
|
4169
|
+
TYMED_ENHMF = 64
|
|
4170
|
+
TYMED_NULL = 0
|
|
4171
|
+
DROPEFFECT_NONE = 0
|
|
4172
|
+
DROPEFFECT_COPY = 1
|
|
4173
|
+
DROPEFFECT_MOVE = 2
|
|
4174
|
+
DROPEFFECT_LINK = 4
|
|
4162
4175
|
FVIRTKEY =1
|
|
4163
4176
|
FNOINVERT = 2
|
|
4164
4177
|
FSHIFT = 4
|
|
@@ -30,7 +30,7 @@ After::
|
|
|
30
30
|
from __future__ import annotations
|
|
31
31
|
|
|
32
32
|
from contextlib import contextmanager
|
|
33
|
-
from typing import Generator, TYPE_CHECKING
|
|
33
|
+
from typing import Any, Callable, Generator, TYPE_CHECKING
|
|
34
34
|
from ctypes import WinError
|
|
35
35
|
from pyglet.libs.win32 import _user32 as user32
|
|
36
36
|
|
|
@@ -72,3 +72,68 @@ def com_context(com_object: COMObject) -> Generator[COMObject, None, None]:
|
|
|
72
72
|
yield com_object
|
|
73
73
|
finally:
|
|
74
74
|
com_object.Release()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _HResultManager:
|
|
78
|
+
"""Helper for managing multiple HRESULT ctypes calls.
|
|
79
|
+
|
|
80
|
+
Typically, ctypes will output an ``OSError`` when the result < 0.
|
|
81
|
+
"""
|
|
82
|
+
error: OSError | None
|
|
83
|
+
last_result: int | None
|
|
84
|
+
|
|
85
|
+
def __init__(self) -> None:
|
|
86
|
+
self.last_result = None
|
|
87
|
+
self.error = None
|
|
88
|
+
|
|
89
|
+
def call(self, callback: Callable[..., int], *args: Any) -> int | None:
|
|
90
|
+
"""Invoke a ctypes callback and capture `OSError` as manager state."""
|
|
91
|
+
self.error = None
|
|
92
|
+
try:
|
|
93
|
+
self.last_result = callback(*args)
|
|
94
|
+
return self.last_result
|
|
95
|
+
except OSError as err:
|
|
96
|
+
self.error = err
|
|
97
|
+
self.last_result = None
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def succeeded(result: int | None, acceptable: tuple[int, ...] = ()) -> bool:
|
|
102
|
+
"""Return success for a HRESULT value.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
result:
|
|
106
|
+
The value returned from a HRESULT-style API call.
|
|
107
|
+
acceptable:
|
|
108
|
+
Extra HRESULT values treated as acceptable for this call.
|
|
109
|
+
"""
|
|
110
|
+
return result is not None and (result >= 0 or result in acceptable)
|
|
111
|
+
|
|
112
|
+
def call_succeeded(self, callback: Callable[..., int], *args: Any, acceptable: tuple[int, ...] = ()) -> bool:
|
|
113
|
+
"""Call and check success in one step.
|
|
114
|
+
|
|
115
|
+
Use `self.error` to inspect the captured `OSError` when this returns `False`.
|
|
116
|
+
"""
|
|
117
|
+
return self.succeeded(self.call(callback, *args), acceptable=acceptable)
|
|
118
|
+
|
|
119
|
+
def raise_if_failed(self, result: int | None, acceptable: tuple[int, ...] = ()) -> int:
|
|
120
|
+
"""Raise exception if the result is not successful.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
OSError:
|
|
124
|
+
Re-raises captured ctypes `OSError`.
|
|
125
|
+
"""
|
|
126
|
+
if self.succeeded(result, acceptable=acceptable):
|
|
127
|
+
return int(result)
|
|
128
|
+
|
|
129
|
+
if self.error is not None:
|
|
130
|
+
raise self.error
|
|
131
|
+
|
|
132
|
+
msg = f"HRESULT call failed with result {result}"
|
|
133
|
+
raise OSError(msg)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@contextmanager
|
|
137
|
+
def hresult_context() -> Generator[_HResultManager, None, None]:
|
|
138
|
+
"""Context manager for grouped HRESULT checks."""
|
|
139
|
+
yield _HResultManager()
|
pyglet/libs/win32/types.py
CHANGED
|
@@ -606,6 +606,38 @@ class VARIANT(Structure):
|
|
|
606
606
|
]
|
|
607
607
|
|
|
608
608
|
|
|
609
|
+
class FORMATETC(Structure):
|
|
610
|
+
_fields_ = [
|
|
611
|
+
('cfFormat', WORD),
|
|
612
|
+
('ptd', c_void_p),
|
|
613
|
+
('dwAspect', DWORD),
|
|
614
|
+
('lindex', LONG),
|
|
615
|
+
('tymed', DWORD),
|
|
616
|
+
]
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
class _STGMEDIUM_UNION(Union):
|
|
620
|
+
_fields_ = [
|
|
621
|
+
('hBitmap', HANDLE),
|
|
622
|
+
('hMetaFilePict', HANDLE),
|
|
623
|
+
('hEnhMetaFile', HANDLE),
|
|
624
|
+
('hGlobal', HANDLE),
|
|
625
|
+
('lpszFileName', LPOLESTR),
|
|
626
|
+
('pstm', LPSTREAM),
|
|
627
|
+
('pstg', c_void_p),
|
|
628
|
+
]
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
class STGMEDIUM(Structure):
|
|
632
|
+
_anonymous_ = ['union']
|
|
633
|
+
|
|
634
|
+
_fields_ = [
|
|
635
|
+
('tymed', DWORD),
|
|
636
|
+
('union', _STGMEDIUM_UNION),
|
|
637
|
+
('pUnkForRelease', com.pIUnknown),
|
|
638
|
+
]
|
|
639
|
+
|
|
640
|
+
|
|
609
641
|
class DWM_BLURBEHIND(Structure):
|
|
610
642
|
_fields_ = [
|
|
611
643
|
("dwFlags", DWORD),
|
|
@@ -663,6 +695,45 @@ class IStream(com.pIUnknown):
|
|
|
663
695
|
]
|
|
664
696
|
|
|
665
697
|
|
|
698
|
+
class IDataObject(com.pIUnknown):
|
|
699
|
+
_methods_ = [
|
|
700
|
+
('GetData',
|
|
701
|
+
com.STDMETHOD(POINTER(FORMATETC), POINTER(STGMEDIUM))),
|
|
702
|
+
('GetDataHere',
|
|
703
|
+
com.STDMETHOD(POINTER(FORMATETC), POINTER(STGMEDIUM))),
|
|
704
|
+
('QueryGetData',
|
|
705
|
+
com.STDMETHOD(POINTER(FORMATETC))),
|
|
706
|
+
('GetCanonicalFormatEtc',
|
|
707
|
+
com.STDMETHOD(POINTER(FORMATETC), POINTER(FORMATETC))),
|
|
708
|
+
('SetData',
|
|
709
|
+
com.STDMETHOD(POINTER(FORMATETC), POINTER(STGMEDIUM), BOOL)),
|
|
710
|
+
('EnumFormatEtc',
|
|
711
|
+
com.STDMETHOD(DWORD, c_void_p)),
|
|
712
|
+
('DAdvise',
|
|
713
|
+
com.STDMETHOD(POINTER(FORMATETC), DWORD, c_void_p, POINTER(DWORD))),
|
|
714
|
+
('DUnadvise',
|
|
715
|
+
com.STDMETHOD(DWORD)),
|
|
716
|
+
('EnumDAdvise',
|
|
717
|
+
com.STDMETHOD(c_void_p)),
|
|
718
|
+
]
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
IID_IUNKNOWN = com.GUID(0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
|
|
722
|
+
IID_IDROPTARGET = com.GUID(0x00000122, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
|
|
723
|
+
|
|
724
|
+
class IDropTarget(com.IUnknown):
|
|
725
|
+
_methods_ = [
|
|
726
|
+
('DragEnter',
|
|
727
|
+
com.STDMETHOD(IDataObject, DWORD, POINT, POINTER(DWORD))),
|
|
728
|
+
('DragOver',
|
|
729
|
+
com.STDMETHOD(DWORD, POINT, POINTER(DWORD))),
|
|
730
|
+
('DragLeave',
|
|
731
|
+
com.STDMETHOD()),
|
|
732
|
+
('Drop',
|
|
733
|
+
com.STDMETHOD(IDataObject, DWORD, POINT, POINTER(DWORD))),
|
|
734
|
+
]
|
|
735
|
+
|
|
736
|
+
|
|
666
737
|
class DEV_BROADCAST_HDR(Structure):
|
|
667
738
|
_fields_ = (
|
|
668
739
|
('dbch_size', DWORD),
|