pyglet 2.1.dev6__py3-none-any.whl → 2.1.dev7__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 -4
- pyglet/app/__init__.py +1 -1
- pyglet/app/cocoa.py +61 -25
- pyglet/customtypes.py +1 -1
- pyglet/gl/cocoa.py +5 -0
- pyglet/graphics/shader.py +146 -74
- pyglet/gui/ninepatch.py +63 -17
- pyglet/image/__init__.py +26 -17
- pyglet/input/base.py +13 -36
- pyglet/input/controller_db.py +5 -1
- pyglet/input/linux/evdev.py +18 -26
- pyglet/input/macos/darwin_hid.py +3 -1
- pyglet/libs/darwin/cocoapy/cocoalibs.py +2 -0
- pyglet/libs/darwin/cocoapy/runtime.py +110 -72
- pyglet/libs/win32/com.py +9 -7
- pyglet/resource.py +24 -41
- pyglet/text/__init__.py +1 -1
- pyglet/text/document.py +53 -7
- pyglet/text/formats/attributed.py +1 -3
- pyglet/text/formats/plaintext.py +1 -1
- pyglet/text/formats/structured.py +1 -1
- pyglet/text/layout/base.py +18 -14
- pyglet/text/layout/incremental.py +2 -5
- pyglet/text/runlist.py +114 -0
- pyglet/window/cocoa/__init__.py +37 -15
- pyglet/window/cocoa/pyglet_delegate.py +1 -1
- pyglet/window/cocoa/pyglet_textview.py +8 -5
- pyglet/window/cocoa/pyglet_view.py +18 -27
- {pyglet-2.1.dev6.dist-info → pyglet-2.1.dev7.dist-info}/METADATA +1 -1
- {pyglet-2.1.dev6.dist-info → pyglet-2.1.dev7.dist-info}/RECORD +32 -32
- {pyglet-2.1.dev6.dist-info → pyglet-2.1.dev7.dist-info}/LICENSE +0 -0
- {pyglet-2.1.dev6.dist-info → pyglet-2.1.dev7.dist-info}/WHEEL +0 -0
pyglet/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
|
|
15
15
|
from typing import Any, Callable, ItemsView, Sized
|
|
16
16
|
|
|
17
17
|
#: The release version
|
|
18
|
-
version = '2.1.
|
|
18
|
+
version = '2.1.dev7'
|
|
19
19
|
__version__ = version
|
|
20
20
|
|
|
21
21
|
MIN_PYTHON_VERSION = 3, 8
|
|
@@ -25,9 +25,6 @@ if sys.version_info < MIN_PYTHON_VERSION:
|
|
|
25
25
|
msg = f"pyglet {version} requires Python {MIN_PYTHON_VERSION_STR} or newer."
|
|
26
26
|
raise Exception(msg)
|
|
27
27
|
|
|
28
|
-
if "sphinx" in sys.modules:
|
|
29
|
-
sys.is_pyglet_doc_run = True
|
|
30
|
-
|
|
31
28
|
# pyglet platform treats *BSD systems as Linux
|
|
32
29
|
compat_platform = sys.platform
|
|
33
30
|
if "bsd" in compat_platform:
|
pyglet/app/__init__.py
CHANGED
|
@@ -68,7 +68,7 @@ the set when they are no longer referenced or are closed explicitly.
|
|
|
68
68
|
"""
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def run(interval: float | None = 1/60) -> None:
|
|
71
|
+
def run(interval: float | None = 1 / 60) -> None:
|
|
72
72
|
"""Begin processing events, scheduled functions and window updates.
|
|
73
73
|
|
|
74
74
|
This is a convenience function, equivalent to::
|
pyglet/app/cocoa.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import signal
|
|
2
|
+
import time
|
|
3
|
+
|
|
2
4
|
from pyglet import app
|
|
3
5
|
from pyglet.app.base import PlatformEventLoop, EventLoop
|
|
4
6
|
from pyglet.libs.darwin import cocoapy, AutoReleasePool, ObjCSubclass, PyObjectEncoding, ObjCInstance, send_super, \
|
|
@@ -11,7 +13,7 @@ NSDate = cocoapy.ObjCClass('NSDate')
|
|
|
11
13
|
NSEvent = cocoapy.ObjCClass('NSEvent')
|
|
12
14
|
NSUserDefaults = cocoapy.ObjCClass('NSUserDefaults')
|
|
13
15
|
NSTimer = cocoapy.ObjCClass('NSTimer')
|
|
14
|
-
|
|
16
|
+
NSRunningApplication = cocoapy.ObjCClass('NSRunningApplication')
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def add_menu_item(menu, title, action, key):
|
|
@@ -71,6 +73,30 @@ class _AppDelegate_Implementation:
|
|
|
71
73
|
def applicationDidFinishLaunching_(self, notification):
|
|
72
74
|
self._pyglet_loop._finished_launching = True
|
|
73
75
|
|
|
76
|
+
# Force App to activate to the foreground due to being an unbundled CLI program.
|
|
77
|
+
# This prevents an issue where if you move the mouse when launching the program, it's focus can be stolen
|
|
78
|
+
# by an app under/behind it leading to a weird state of input and the menu bar being greyed out until
|
|
79
|
+
# reactivating it.
|
|
80
|
+
NSApp = NSApplication.sharedApplication()
|
|
81
|
+
|
|
82
|
+
# Activate dock to ensure all other apps are deactivated.
|
|
83
|
+
dock_str = cocoapy.get_NSString("com.apple.dock")
|
|
84
|
+
running_apps = NSRunningApplication.runningApplicationsWithBundleIdentifier_(dock_str)
|
|
85
|
+
app_count = running_apps.count()
|
|
86
|
+
for i in range(app_count):
|
|
87
|
+
running_app = running_apps.objectAtIndex_(i)
|
|
88
|
+
running_app.activateWithOptions_(cocoapy.NSApplicationActivateIgnoringOtherApps)
|
|
89
|
+
break
|
|
90
|
+
|
|
91
|
+
# Doesn't seem to work unless we add a small sleep for some reason...
|
|
92
|
+
time.sleep(0.01)
|
|
93
|
+
|
|
94
|
+
NSApp.activateIgnoringOtherApps_(True)
|
|
95
|
+
|
|
96
|
+
@_AppDelegate.method('v@')
|
|
97
|
+
def applicationWillFinishLaunching_(self, notification):
|
|
98
|
+
pass
|
|
99
|
+
|
|
74
100
|
@_AppDelegate.method('B')
|
|
75
101
|
def applicationSupportsSecureRestorableState_(self):
|
|
76
102
|
return True
|
|
@@ -129,7 +155,9 @@ class CocoaAlternateEventLoop(EventLoop):
|
|
|
129
155
|
class CocoaPlatformEventLoop(PlatformEventLoop):
|
|
130
156
|
|
|
131
157
|
def __init__(self):
|
|
132
|
-
super(
|
|
158
|
+
super().__init__()
|
|
159
|
+
self._timer = None
|
|
160
|
+
|
|
133
161
|
with AutoReleasePool():
|
|
134
162
|
# Prepare the default application.
|
|
135
163
|
self.NSApp = NSApplication.sharedApplication()
|
|
@@ -151,8 +179,23 @@ class CocoaPlatformEventLoop(PlatformEventLoop):
|
|
|
151
179
|
if not defaults.objectForKey_(holdEnabled):
|
|
152
180
|
defaults.setBool_forKey_(False, holdEnabled)
|
|
153
181
|
|
|
182
|
+
self.appdelegate = _AppDelegate.alloc().init(self)
|
|
183
|
+
self.NSApp.setDelegate_(self.appdelegate)
|
|
184
|
+
|
|
154
185
|
self._finished_launching = False
|
|
155
186
|
|
|
187
|
+
def term_received(*args):
|
|
188
|
+
if self._timer:
|
|
189
|
+
self._timer.invalidate()
|
|
190
|
+
self._timer = None
|
|
191
|
+
|
|
192
|
+
if self.NSApp:
|
|
193
|
+
self.NSApp.terminate_(None)
|
|
194
|
+
|
|
195
|
+
# Force NSApp to close if Python receives sig events.
|
|
196
|
+
signal.signal(signal.SIGINT, term_received)
|
|
197
|
+
signal.signal(signal.SIGTERM, term_received)
|
|
198
|
+
|
|
156
199
|
def start(self):
|
|
157
200
|
with AutoReleasePool():
|
|
158
201
|
if not self.NSApp.isRunning() and not self._finished_launching:
|
|
@@ -167,38 +210,31 @@ class CocoaPlatformEventLoop(PlatformEventLoop):
|
|
|
167
210
|
from pyglet.app import event_loop
|
|
168
211
|
self._event_loop = event_loop
|
|
169
212
|
|
|
170
|
-
|
|
171
|
-
if self.timer:
|
|
172
|
-
self.timer.invalidate()
|
|
173
|
-
self.timer = None
|
|
213
|
+
assert self._timer is None
|
|
174
214
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
self.NSApp.setDelegate_(self.appdelegate)
|
|
183
|
-
|
|
184
|
-
self.timer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
|
|
185
|
-
interval, # Clamped internally to 0.0001 (including 0)
|
|
186
|
-
self.appdelegate,
|
|
187
|
-
get_selector('updatePyglet:'),
|
|
188
|
-
False,
|
|
189
|
-
True
|
|
190
|
-
)
|
|
215
|
+
self._timer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
|
|
216
|
+
interval, # Clamped internally to 0.0001 (including 0)
|
|
217
|
+
self.appdelegate,
|
|
218
|
+
get_selector('updatePyglet:'),
|
|
219
|
+
False,
|
|
220
|
+
True
|
|
221
|
+
)
|
|
191
222
|
|
|
192
223
|
self.NSApp.run()
|
|
193
224
|
|
|
194
225
|
def nsapp_step(self):
|
|
195
226
|
"""Used only for CocoaAlternateEventLoop"""
|
|
196
227
|
self._event_loop.idle()
|
|
197
|
-
|
|
228
|
+
with AutoReleasePool():
|
|
229
|
+
self.dispatch_posted_events()
|
|
198
230
|
|
|
199
231
|
def nsapp_stop(self):
|
|
200
232
|
"""Used only for CocoaAlternateEventLoop"""
|
|
201
|
-
self.NSApp.
|
|
233
|
+
self.NSApp.stop_(None)
|
|
234
|
+
|
|
235
|
+
if self._timer:
|
|
236
|
+
self._timer.invalidate()
|
|
237
|
+
self._timer = None
|
|
202
238
|
|
|
203
239
|
def step(self, timeout=None):
|
|
204
240
|
with AutoReleasePool():
|
|
@@ -210,7 +246,7 @@ class CocoaPlatformEventLoop(PlatformEventLoop):
|
|
|
210
246
|
# will wait until the next event comes along.
|
|
211
247
|
timeout_date = NSDate.distantFuture()
|
|
212
248
|
elif timeout == 0.0:
|
|
213
|
-
timeout_date =
|
|
249
|
+
timeout_date = None
|
|
214
250
|
else:
|
|
215
251
|
timeout_date = NSDate.dateWithTimeIntervalSinceNow_(timeout)
|
|
216
252
|
|
pyglet/customtypes.py
CHANGED
|
@@ -14,7 +14,7 @@ else:
|
|
|
14
14
|
HorizontalAlign = Literal["left", "center", "right"]
|
|
15
15
|
AnchorX = Literal["left", "center", "right"]
|
|
16
16
|
AnchorY = Literal["top", "bottom", "center", "baseline"]
|
|
17
|
-
ContentVAlign = Literal["
|
|
17
|
+
ContentVAlign = Literal["bottom", "center", "top"]
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
pyglet/gl/cocoa.py
CHANGED
|
@@ -239,6 +239,11 @@ class CocoaDisplayConfig(DisplayConfig): # noqa: D101
|
|
|
239
239
|
self._pixel_format,
|
|
240
240
|
share_context)
|
|
241
241
|
|
|
242
|
+
# No longer needed after context creation.
|
|
243
|
+
if self._pixel_format:
|
|
244
|
+
self._pixel_format.release()
|
|
245
|
+
self._pixel_format = None
|
|
246
|
+
|
|
242
247
|
return CocoaContext(self, nscontext, share)
|
|
243
248
|
|
|
244
249
|
def compatible(self, canvas: CocoaCanvas) -> bool:
|
pyglet/graphics/shader.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
import warnings
|
|
4
5
|
import weakref
|
|
5
6
|
from collections import defaultdict
|
|
@@ -329,9 +330,10 @@ class _UniformArray:
|
|
|
329
330
|
_dsa: bool
|
|
330
331
|
_c_array: Array[GLDataType]
|
|
331
332
|
_ptr: CTypesPointer[GLDataType]
|
|
332
|
-
|
|
333
|
+
_idx_to_loc: dict[int, int]
|
|
333
334
|
|
|
334
|
-
__slots__ = ('_uniform', '_gl_type', '_gl_getter', '_gl_setter', '_is_matrix', '_dsa', '_c_array', '_ptr'
|
|
335
|
+
__slots__ = ('_uniform', '_gl_type', '_gl_getter', '_gl_setter', '_is_matrix', '_dsa', '_c_array', '_ptr',
|
|
336
|
+
'_idx_to_loc')
|
|
335
337
|
|
|
336
338
|
def __init__(self, uniform: _Uniform, gl_getter: GLFunc, gl_setter: GLFunc, gl_type: GLDataType, is_matrix: bool,
|
|
337
339
|
dsa: bool) -> None:
|
|
@@ -340,6 +342,7 @@ class _UniformArray:
|
|
|
340
342
|
self._gl_getter = gl_getter
|
|
341
343
|
self._gl_setter = gl_setter
|
|
342
344
|
self._is_matrix = is_matrix
|
|
345
|
+
self._idx_to_loc = {} # Array index to uniform location mapping.
|
|
343
346
|
self._dsa = dsa
|
|
344
347
|
|
|
345
348
|
if self._uniform.length > 1:
|
|
@@ -349,6 +352,31 @@ class _UniformArray:
|
|
|
349
352
|
|
|
350
353
|
self._ptr = cast(self._c_array, POINTER(gl_type))
|
|
351
354
|
|
|
355
|
+
def _get_location_for_index(self, index: int) -> int:
|
|
356
|
+
"""Get the location for the array name.
|
|
357
|
+
|
|
358
|
+
It is not guaranteed that the location ID's of the uniform in the shader program will be a contiguous offset.
|
|
359
|
+
|
|
360
|
+
On MacOS, the location ID of index 0 may be 1, and then index 2 might be 5. Whereas on Windows it may be a 1:1
|
|
361
|
+
offset from 0 to index. Here, we store the location ID's of each index to ensure we are setting data on the
|
|
362
|
+
right location.
|
|
363
|
+
"""
|
|
364
|
+
loc = gl.glGetUniformLocation(self._uniform.program,
|
|
365
|
+
create_string_buffer(f"{self._uniform.name}[{index}]".encode('utf-8')))
|
|
366
|
+
return loc
|
|
367
|
+
|
|
368
|
+
def _get_array_loc(self, index: int) -> int:
|
|
369
|
+
try:
|
|
370
|
+
return self._idx_to_loc[index]
|
|
371
|
+
except KeyError:
|
|
372
|
+
loc = self._idx_to_loc[index] = self._get_location_for_index(index)
|
|
373
|
+
|
|
374
|
+
if loc == -1:
|
|
375
|
+
msg = f"{self._uniform.name}[{index}] not found.\nThis may have been optimized out by the OpenGL driver if unused."
|
|
376
|
+
raise ShaderException(msg)
|
|
377
|
+
|
|
378
|
+
return loc
|
|
379
|
+
|
|
352
380
|
def __len__(self) -> int:
|
|
353
381
|
return self._uniform.size
|
|
354
382
|
|
|
@@ -365,8 +393,12 @@ class _UniformArray:
|
|
|
365
393
|
|
|
366
394
|
return tuple([data for data in sliced_data]) # noqa: C416
|
|
367
395
|
|
|
368
|
-
|
|
369
|
-
|
|
396
|
+
try:
|
|
397
|
+
value = self._c_array[key]
|
|
398
|
+
return tuple(value) if self._uniform.length > 1 else value
|
|
399
|
+
except IndexError:
|
|
400
|
+
msg = f"{self._uniform.name}[{key}] not found. This may have been optimized out by the OpenGL driver if unused."
|
|
401
|
+
raise ShaderException(msg)
|
|
370
402
|
|
|
371
403
|
def __setitem__(self, key: slice | int, value: Sequence) -> None:
|
|
372
404
|
if isinstance(key, slice):
|
|
@@ -403,11 +435,19 @@ class _UniformArray:
|
|
|
403
435
|
else:
|
|
404
436
|
size = self._uniform.size
|
|
405
437
|
|
|
438
|
+
location = self._get_location_for_index(offset)
|
|
439
|
+
|
|
406
440
|
if self._dsa:
|
|
407
|
-
|
|
441
|
+
if self._is_matrix:
|
|
442
|
+
self._gl_setter(self._uniform.program, location, size, GL_FALSE, data)
|
|
443
|
+
else:
|
|
444
|
+
self._gl_setter(self._uniform.program, location, size, data)
|
|
408
445
|
else:
|
|
409
446
|
glUseProgram(self._uniform.program)
|
|
410
|
-
self.
|
|
447
|
+
if self._is_matrix:
|
|
448
|
+
self._gl_setter(location, size, GL_FALSE, data)
|
|
449
|
+
else:
|
|
450
|
+
self._gl_setter(location, size, data)
|
|
411
451
|
|
|
412
452
|
def __repr__(self) -> str:
|
|
413
453
|
data = [tuple(data) if self._uniform.length > 1 else data for data in self._c_array]
|
|
@@ -426,13 +466,15 @@ class _Uniform:
|
|
|
426
466
|
size: int
|
|
427
467
|
location: int
|
|
428
468
|
program: int
|
|
469
|
+
name: str
|
|
429
470
|
length: int
|
|
430
471
|
get: Callable[[], Array[GLDataType] | GLDataType]
|
|
431
472
|
set: Callable[[float], None] | Callable[[Sequence], None]
|
|
432
473
|
|
|
433
|
-
__slots__ = 'type', 'size', 'location', 'length', 'count', 'get', 'set', 'program'
|
|
474
|
+
__slots__ = 'type', 'size', 'location', 'length', 'count', 'get', 'set', 'program', 'name'
|
|
434
475
|
|
|
435
|
-
def __init__(self, program: int, uniform_type: int, size: int, location: int, dsa: bool) -> None:
|
|
476
|
+
def __init__(self, program: int, name: str, uniform_type: int, size: int, location: int, dsa: bool) -> None:
|
|
477
|
+
self.name = name
|
|
436
478
|
self.type = uniform_type
|
|
437
479
|
self.size = size
|
|
438
480
|
self.location = location
|
|
@@ -609,6 +651,8 @@ class _UBOBindingManager:
|
|
|
609
651
|
msg = f"Uniform binding point: {index} is not in use."
|
|
610
652
|
raise ValueError(msg)
|
|
611
653
|
|
|
654
|
+
# Regular expression to detect array indices like [0], [1], etc.
|
|
655
|
+
array_regex = re.compile(r"(\w+)\[(\d+)\]")
|
|
612
656
|
|
|
613
657
|
class UniformBlock:
|
|
614
658
|
program: CallableProxyType[Callable[..., Any] | Any] | Any
|
|
@@ -616,12 +660,12 @@ class UniformBlock:
|
|
|
616
660
|
index: int
|
|
617
661
|
size: int
|
|
618
662
|
binding: int
|
|
619
|
-
uniforms: dict[int, tuple[str, GLDataType, int, int
|
|
663
|
+
uniforms: dict[int, tuple[str, GLDataType, int, int]]
|
|
620
664
|
view_cls: type[Structure] | None
|
|
621
|
-
__slots__ = 'program', 'name', 'index', 'size', 'binding', 'uniforms', 'view_cls'
|
|
665
|
+
__slots__ = 'program', 'name', 'index', 'size', 'binding', 'uniforms', 'view_cls', 'uniform_count'
|
|
622
666
|
|
|
623
667
|
def __init__(self, program: ShaderProgram, name: str, index: int, size: int, binding: int,
|
|
624
|
-
uniforms: dict[int, tuple[str, GLDataType, int, int,
|
|
668
|
+
uniforms: dict[int, tuple[str, GLDataType, int, int]], uniform_count: int) -> None:
|
|
625
669
|
"""Initialize a uniform block for a ShaderProgram."""
|
|
626
670
|
self.program = weakref.proxy(program)
|
|
627
671
|
self.name = name
|
|
@@ -629,6 +673,7 @@ class UniformBlock:
|
|
|
629
673
|
self.size = size
|
|
630
674
|
self.binding = binding
|
|
631
675
|
self.uniforms = uniforms
|
|
676
|
+
self.uniform_count = uniform_count
|
|
632
677
|
self.view_cls = None
|
|
633
678
|
|
|
634
679
|
def create_ubo(self) -> UniformBufferObject:
|
|
@@ -670,7 +715,7 @@ class UniformBlock:
|
|
|
670
715
|
p_id = self.program.id
|
|
671
716
|
index = self.index
|
|
672
717
|
|
|
673
|
-
active_count =
|
|
718
|
+
active_count = self.uniform_count
|
|
674
719
|
|
|
675
720
|
# Query the uniform index order and each uniform's offset:
|
|
676
721
|
indices = (gl.GLuint * active_count)()
|
|
@@ -693,50 +738,86 @@ class UniformBlock:
|
|
|
693
738
|
# gl.glGetActiveUniformsiv(p_id, active_count, indices, gl.GL_UNIFORM_TYPE, gl_types_ptr)
|
|
694
739
|
# gl.glGetActiveUniformsiv(p_id, active_count, indices, gl.GL_UNIFORM_MATRIX_STRIDE, stride_ptr)
|
|
695
740
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
final_gl_type = gl_type * u_size
|
|
741
|
+
array_sizes = {}
|
|
742
|
+
dynamic_structs = {}
|
|
743
|
+
p_count = 0
|
|
744
|
+
|
|
745
|
+
rep_func = lambda s: str(dict(s._fields_))
|
|
746
|
+
|
|
747
|
+
def build_ctypes_struct(name: str, struct_dict: dict) -> type:
|
|
748
|
+
fields = []
|
|
749
|
+
for field_name, field_type in struct_dict.items():
|
|
750
|
+
if isinstance(field_type, dict):
|
|
751
|
+
# Recursive call for nested structures
|
|
752
|
+
element_struct = build_ctypes_struct(field_name, field_type)
|
|
753
|
+
field_type = element_struct # noqa: PLW2901
|
|
754
|
+
if field_name in array_sizes and array_sizes[field_name] > 1:
|
|
755
|
+
field_type = element_struct * array_sizes[field_name] # noqa: PLW2901
|
|
712
756
|
else:
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
padding = offset_size - c_type_size
|
|
757
|
+
# This handles base types like c_float_Array_2, which isn't a dict.
|
|
758
|
+
fields.append((field_name, field_type))
|
|
759
|
+
continue
|
|
760
|
+
fields.append((field_name, field_type))
|
|
718
761
|
|
|
719
|
-
|
|
720
|
-
view_fields.append(arg)
|
|
762
|
+
return type(name.title(), (Structure,), {"_fields_": fields, "__repr__": rep_func})
|
|
721
763
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
764
|
+
# Build a ctypes Structure of the uniforms including arrays and nested structures.
|
|
765
|
+
for i in range(active_count):
|
|
766
|
+
u_name, gl_type, length, u_size = self.uniforms[indices[i]]
|
|
767
|
+
|
|
768
|
+
parts = u_name.split(".")
|
|
769
|
+
|
|
770
|
+
current_structure = dynamic_structs
|
|
771
|
+
for part_idx, part in enumerate(parts):
|
|
772
|
+
part_name = part
|
|
773
|
+
match = array_regex.match(part_name)
|
|
774
|
+
if match: # It's an array
|
|
775
|
+
arr_name, index = match.groups()
|
|
776
|
+
part_name = arr_name
|
|
777
|
+
|
|
778
|
+
if part_idx != len(parts) - 1:
|
|
779
|
+
index = int(index) # Convert the index to an integer
|
|
780
|
+
|
|
781
|
+
# Track array sizes for the current array name
|
|
782
|
+
array_sizes[arr_name] = max(array_sizes.get(arr_name, 0), index + 1)
|
|
783
|
+
if array_sizes[arr_name] > 1:
|
|
784
|
+
break
|
|
785
|
+
|
|
786
|
+
if arr_name not in current_structure:
|
|
787
|
+
current_structure[arr_name] = {}
|
|
788
|
+
|
|
789
|
+
current_structure = current_structure[arr_name] # Move to the correct index of the array
|
|
790
|
+
continue
|
|
791
|
+
|
|
792
|
+
# The end should be a regular attribute
|
|
793
|
+
if part_idx == len(parts) - 1: # The last part is the actual type
|
|
794
|
+
if u_size > 1:
|
|
795
|
+
# If size > 1, treat as an array of type
|
|
796
|
+
current_structure[part_name] = gl_type * length * u_size
|
|
797
|
+
else:
|
|
798
|
+
current_structure[part_name] = gl_type * length
|
|
799
|
+
|
|
800
|
+
offset_size = offsets[i + 1] - offsets[i]
|
|
801
|
+
c_type_size = sizeof(current_structure[part_name])
|
|
802
|
+
padding = offset_size - c_type_size
|
|
803
|
+
|
|
804
|
+
# TODO: Cannot get a different stride on my hardware. Needs testing.
|
|
805
|
+
# is_matrix = gl_types[i] in _gl_matrices
|
|
806
|
+
# if is_matrix:
|
|
807
|
+
# stride_padding = (mat_stride[i] // 4) * 4 - offset_size
|
|
808
|
+
# if stride_padding > 0:
|
|
809
|
+
# view_fields.append((f'_matrix_stride{i}', c_byte * stride_padding))
|
|
810
|
+
|
|
811
|
+
if padding > 0:
|
|
812
|
+
current_structure[f'_padding{p_count}'] = c_byte * padding
|
|
813
|
+
p_count += 1
|
|
814
|
+
else:
|
|
815
|
+
if part_name not in current_structure:
|
|
816
|
+
current_structure[part_name] = {}
|
|
817
|
+
current_structure = current_structure[part_name] # Drill down into nested structures
|
|
731
818
|
|
|
732
819
|
# Custom ctypes Structure for Uniform access:
|
|
733
|
-
|
|
734
|
-
_fields_ = view_fields
|
|
735
|
-
|
|
736
|
-
def __repr__(self) -> str:
|
|
737
|
-
return str(dict(self._fields_))
|
|
738
|
-
|
|
739
|
-
return View
|
|
820
|
+
return build_ctypes_struct('View', dynamic_structs)
|
|
740
821
|
|
|
741
822
|
def _actual_binding_point(self) -> int:
|
|
742
823
|
"""Queries OpenGL to find what the bind point currently is."""
|
|
@@ -900,9 +981,9 @@ def _introspect_uniforms(program_id: int, have_dsa: bool) -> dict[str, _Uniform]
|
|
|
900
981
|
for index in range(_get_number(program_id, gl.GL_ACTIVE_UNIFORMS)):
|
|
901
982
|
u_name, u_type, u_size = _query_uniform(program_id, index)
|
|
902
983
|
|
|
903
|
-
# Multidimensional arrays cannot be fully inspected via OpenGL calls.
|
|
984
|
+
# Multidimensional arrays cannot be fully inspected via OpenGL calls and compile errors with 3.3.
|
|
904
985
|
array_count = u_name.count("[0]")
|
|
905
|
-
if array_count > 1:
|
|
986
|
+
if array_count > 1 and u_name.count("[0][0]") != 0:
|
|
906
987
|
msg = "Multidimensional arrays are not currently supported."
|
|
907
988
|
raise ShaderException(msg)
|
|
908
989
|
|
|
@@ -911,11 +992,11 @@ def _introspect_uniforms(program_id: int, have_dsa: bool) -> dict[str, _Uniform]
|
|
|
911
992
|
continue
|
|
912
993
|
|
|
913
994
|
# Strip [0] from array name for a more user-friendly name.
|
|
914
|
-
if array_count
|
|
995
|
+
if array_count != 0:
|
|
915
996
|
u_name = u_name.strip('[0]')
|
|
916
997
|
|
|
917
998
|
assert u_name not in uniforms, f"{u_name} exists twice in the shader. Possible name clash with an array."
|
|
918
|
-
uniforms[u_name] = _Uniform(program_id, u_type, u_size, loc, have_dsa)
|
|
999
|
+
uniforms[u_name] = _Uniform(program_id, u_name, u_type, u_size, loc, have_dsa)
|
|
919
1000
|
|
|
920
1001
|
if _debug_gl_shaders:
|
|
921
1002
|
for uniform in uniforms.values():
|
|
@@ -956,7 +1037,7 @@ def _introspect_uniform_blocks(program: ShaderProgram | ComputeShaderProgram) ->
|
|
|
956
1037
|
indices_ptr = cast(addressof(indices), POINTER(gl.GLint))
|
|
957
1038
|
gl.glGetActiveUniformBlockiv(program_id, index, gl.GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices_ptr)
|
|
958
1039
|
|
|
959
|
-
uniforms: dict[int, tuple[str, GLDataType, int, int
|
|
1040
|
+
uniforms: dict[int, tuple[str, GLDataType, int, int]] = {}
|
|
960
1041
|
|
|
961
1042
|
if not hasattr(pyglet.gl.current_context, "ubo_manager"):
|
|
962
1043
|
pyglet.gl.current_context.ubo_manager = _UBOBindingManager()
|
|
@@ -966,26 +1047,16 @@ def _introspect_uniform_blocks(program: ShaderProgram | ComputeShaderProgram) ->
|
|
|
966
1047
|
for block_uniform_index in indices:
|
|
967
1048
|
uniform_name, u_type, u_size = _query_uniform(program_id, block_uniform_index)
|
|
968
1049
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
is_array = True
|
|
973
|
-
|
|
974
|
-
# Strip [0] from array name for a more user-friendly name.
|
|
975
|
-
if array_count == 1:
|
|
976
|
-
uniform_name = uniform_name.strip('[0]')
|
|
977
|
-
else:
|
|
978
|
-
msg = "Multidimensional arrays are not currently supported."
|
|
979
|
-
raise ShaderException(msg)
|
|
1050
|
+
# Remove block name.
|
|
1051
|
+
if uniform_name.startswith(f"{name}."):
|
|
1052
|
+
uniform_name = uniform_name[len(name) + 1:] # Strip 'block_name.' part
|
|
980
1053
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
except ValueError:
|
|
985
|
-
pass
|
|
1054
|
+
if uniform_name.count("[0][0]") > 0:
|
|
1055
|
+
msg = "Multidimensional arrays are not currently supported."
|
|
1056
|
+
raise ShaderException(msg)
|
|
986
1057
|
|
|
987
1058
|
gl_type, _, _, length = _uniform_setters[u_type]
|
|
988
|
-
uniforms[block_uniform_index] = (uniform_name, gl_type, length, u_size
|
|
1059
|
+
uniforms[block_uniform_index] = (uniform_name, gl_type, length, u_size)
|
|
989
1060
|
|
|
990
1061
|
binding_index = binding.value
|
|
991
1062
|
if pyglet.options.shader_bind_management:
|
|
@@ -1005,7 +1076,8 @@ def _introspect_uniform_blocks(program: ShaderProgram | ComputeShaderProgram) ->
|
|
|
1005
1076
|
warnings.warn(msg)
|
|
1006
1077
|
manager.add_explicit_binding(program, name, binding.value)
|
|
1007
1078
|
|
|
1008
|
-
uniform_blocks[name] = UniformBlock(program, name, index, block_data_size.value, binding_index, uniforms
|
|
1079
|
+
uniform_blocks[name] = UniformBlock(program, name, index, block_data_size.value, binding_index, uniforms,
|
|
1080
|
+
len(indices))
|
|
1009
1081
|
|
|
1010
1082
|
if _debug_gl_shaders:
|
|
1011
1083
|
for block in uniform_blocks.values():
|