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 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.dev6'
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(CocoaPlatformEventLoop, self).__init__()
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
- def term_received(*args):
171
- if self.timer:
172
- self.timer.invalidate()
173
- self.timer = None
213
+ assert self._timer is None
174
214
 
175
- self.nsapp_stop()
176
-
177
- # Force NSApp to close if Python receives sig events.
178
- signal.signal(signal.SIGINT, term_received)
179
- signal.signal(signal.SIGTERM, term_received)
180
-
181
- self.appdelegate = _AppDelegate.alloc().init(self)
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
- self.dispatch_posted_events()
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.terminate_(None)
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 = NSDate.distantPast()
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["left", "center", "top"]
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
- _uniform: _Uniform
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
- value = self._c_array[key]
369
- return tuple(value) if self._uniform.length > 1 else value
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
- self._gl_setter(self._uniform.program, self._uniform.location + offset, size, data)
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._gl_setter(self._uniform.location + offset, size, data)
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, bool]]
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, bool]]) -> None:
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 = len(self.uniforms)
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
- view_fields = []
697
-
698
- for i in range(active_count):
699
- u_name, gl_type, length, u_size, is_array = self.uniforms[indices[i]]
700
-
701
- # Is something like a vec2,3,4.
702
- if length > 1:
703
- # If it's an array, further divide it.
704
- if is_array:
705
- final_gl_type = gl_type * length * u_size
706
- else:
707
- final_gl_type = gl_type * length
708
- else:
709
- # A single length, but may be an array.
710
- if is_array:
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
- final_gl_type = gl_type
714
-
715
- offset_size = offsets[i + 1] - offsets[i]
716
- c_type_size = sizeof(final_gl_type)
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
- arg = (u_name, final_gl_type)
720
- view_fields.append(arg)
762
+ return type(name.title(), (Structure,), {"_fields_": fields, "__repr__": rep_func})
721
763
 
722
- if padding > 0:
723
- view_fields.append((f'_padding{i}', c_byte * padding))
724
-
725
- # TODO: Cannot get a different stride on my hardware. Needs testing.
726
- # is_matrix = gl_types[i] in _gl_matrices
727
- # if is_matrix:
728
- # stride_padding = (mat_stride[i] // 4) * 4 - offset_size
729
- # if stride_padding > 0:
730
- # view_fields.append((f'_matrix_stride{i}', c_byte * stride_padding))
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
- class View(Structure):
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 == 1:
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, bool]] = {}
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
- is_array = False
970
- array_count = uniform_name.count("[0]")
971
- if array_count > 0:
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
- # Separate uniform name from block name (Only if instance name is provided on the Uniform Block)
982
- try:
983
- _, uniform_name = uniform_name.split(".")
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, is_array)
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():