ncca-ngl 0.1.0__py3-none-any.whl → 0.1.1__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.
@@ -1,816 +0,0 @@
1
- import ctypes
2
- from typing import Any, Dict, List, Optional, Union
3
-
4
- import numpy as np
5
- import OpenGL.GL as gl
6
-
7
- from .log import logger
8
- from .mat2 import Mat2
9
- from .mat3 import Mat3
10
- from .mat4 import Mat4
11
- from .shader import Shader
12
- from .vec2 import Vec2
13
- from .vec3 import Vec3
14
- from .vec4 import Vec4
15
-
16
-
17
- class ShaderProgram:
18
- """
19
- A wrapper class for OpenGL shader programs.
20
-
21
- This class provides functionality to create, link, and manage OpenGL shader programs,
22
- including automatic uniform and uniform block registration, and convenience methods
23
- for setting uniform values.
24
-
25
- Attributes:
26
- _name: The name of the shader program
27
- _exit_on_error: Whether to exit the application on errors
28
- _id: The OpenGL shader program ID
29
- _shaders: List of attached shaders
30
- _uniforms: Dictionary of registered uniforms
31
- _registered_uniform_blocks: Dictionary of registered uniform blocks
32
- """
33
-
34
- def __init__(self, name: str, exit_on_error: bool = True) -> None:
35
- """
36
- Initialize a new shader program.
37
-
38
- Args:
39
- name: Name of the shader program for identification
40
- exit_on_error: Whether to exit the application when errors occur
41
- """
42
- self._name: str = name
43
- self._exit_on_error: bool = exit_on_error
44
- self._id: int = gl.glCreateProgram()
45
- self._shaders: list[Shader] = []
46
- self._uniforms: dict[str, tuple[int, int, int, bool]] = {}
47
- self._registered_uniform_blocks: dict[str, dict] = {}
48
-
49
- def attach_shader(self, shader: Shader) -> None:
50
- """
51
- Attach a shader to this program.
52
-
53
- Args:
54
- shader: The Shader object to attach
55
- """
56
- gl.glAttachShader(self._id, shader._id)
57
- self._shaders.append(shader)
58
-
59
- def link(self) -> bool:
60
- """
61
- Link the attached shaders to create the final shader program.
62
-
63
- Returns:
64
- bool: True if linking succeeded, False otherwise.
65
- """
66
- gl.glLinkProgram(self._id)
67
- if gl.glGetProgramiv(self._id, gl.GL_LINK_STATUS) != gl.GL_TRUE:
68
- info = gl.glGetProgramInfoLog(self._id)
69
- logger.error(f"Error linking program {self._name}: {info}")
70
- if self._exit_on_error:
71
- exit()
72
- return False
73
- # Automatically register uniforms and uniform blocks after linking
74
- self.auto_register_uniforms()
75
- self.auto_register_uniform_blocks()
76
- return True
77
-
78
- def auto_register_uniforms(self) -> None:
79
- """
80
- Automatically register all active uniforms in the shader program.
81
-
82
- This method queries OpenGL for all active uniforms and stores their
83
- information including location, type, size, and array status.
84
- For array uniforms, it also registers individual array elements.
85
- """
86
- uniform_count = gl.glGetProgramiv(self._id, gl.GL_ACTIVE_UNIFORMS)
87
- for i in range(uniform_count):
88
- name, size, shader_type = gl.glGetActiveUniform(self._id, i, 256)
89
-
90
- # Convert name to string
91
- name_str = name.decode("utf-8") if isinstance(name, bytes) else name
92
-
93
- # Handle array uniforms - OpenGL returns name with [0] for arrays
94
- is_array = size > 1
95
- base_name = name_str
96
- if name_str.endswith("[0]"):
97
- base_name = name_str[:-3]
98
-
99
- location = gl.glGetUniformLocation(self._id, name)
100
-
101
- # Store uniform info: (location, shader_type, size, is_array)
102
- self._uniforms[base_name] = (location, shader_type, size, is_array)
103
-
104
- # For arrays, also register individual elements
105
- if is_array:
106
- for element_idx in range(size):
107
- element_name = f"{base_name}[{element_idx}]"
108
- element_location = gl.glGetUniformLocation(
109
- self._id, element_name.encode("utf-8")
110
- )
111
- if element_location != -1:
112
- # Store individual array element: (location, shader_type, 1, False)
113
- self._uniforms[element_name] = (
114
- element_location,
115
- shader_type,
116
- 1,
117
- False,
118
- )
119
-
120
- # Log array uniforms differently
121
- if is_array:
122
- logger.info(
123
- f"Registered array uniform: {base_name}[{size}] (type: {self.get_gl_type_string(shader_type)}, location: {location})"
124
- )
125
- logger.info(
126
- f" Also registered individual elements: {base_name}[0] to {base_name}[{size - 1}]"
127
- )
128
- else:
129
- logger.info(
130
- f"Registered uniform: {base_name} (type: {self.get_gl_type_string(shader_type)}, location: {location})"
131
- )
132
-
133
- def auto_register_uniform_blocks(self) -> None:
134
- """
135
- Automatically register uniform blocks for this shader program.
136
- This is the Python equivalent of the C++ ShaderProgram::autoRegisterUniformBlocks method.
137
- """
138
- # Clear existing uniform blocks
139
- self._registered_uniform_blocks.clear()
140
-
141
- # Get number of active uniform blocks
142
- n_uniforms = gl.glGetProgramiv(self._id, gl.GL_ACTIVE_UNIFORM_BLOCKS)
143
- logger.info(f"FOUND UNIFORM BLOCKS {n_uniforms}")
144
-
145
- for i in range(n_uniforms):
146
- # Get uniform block name using ctypes buffer
147
- name_buffer = (ctypes.c_char * 256)()
148
- length = ctypes.c_int()
149
-
150
- gl.glGetActiveUniformBlockName(
151
- self._id, i, 256, ctypes.byref(length), name_buffer
152
- )
153
- name_str = (
154
- name_buffer.value.decode("utf-8")
155
- if name_buffer.value
156
- else f"UniformBlock_{i}"
157
- )
158
-
159
- # Create uniform block data structure
160
- data = {
161
- "name": name_str,
162
- "loc": gl.glGetUniformBlockIndex(self._id, name_str.encode("utf-8")),
163
- "buffer": gl.glGenBuffers(1),
164
- }
165
-
166
- # Store the uniform block data
167
- self._registered_uniform_blocks[name_str] = data
168
- logger.info(f"Uniform Block {name_str} {data['loc']} {data['buffer']}")
169
-
170
- def use(self) -> None:
171
- """
172
- Set this shader program as the current active program.
173
- """
174
- gl.glUseProgram(self._id)
175
-
176
- def get_id(self) -> int:
177
- """
178
- Get the OpenGL shader program ID.
179
-
180
- Returns:
181
- int: The OpenGL program ID
182
- """
183
- return self._id
184
-
185
- def get_uniform_location(self, name: str) -> int:
186
- """
187
- Get the location of a uniform variable.
188
-
189
- Args:
190
- name: The name of the uniform variable
191
-
192
- Returns:
193
- int: The uniform location, or -1 if not found
194
- """
195
- if name in self._uniforms:
196
- return self._uniforms[name][0]
197
- else:
198
- logger.warning(f"Uniform '{name}' not found in shader '{self._name}'")
199
- return -1
200
-
201
- def get_uniform_info(self, name: str) -> tuple[int, int, int, bool]:
202
- """
203
- Get complete uniform info: (location, shader_type, size, is_array).
204
-
205
- Args:
206
- name: The name of the uniform variable
207
-
208
- Returns:
209
- tuple: (location, shader_type, size, is_array)
210
- """
211
- return self._uniforms.get(name, (-1, 0, 0, False))
212
-
213
- def is_uniform_array(self, name: str) -> bool:
214
- """
215
- Check if a uniform is an array.
216
-
217
- Args:
218
- name: The name of the uniform variable
219
-
220
- Returns:
221
- bool: True if the uniform is an array, False otherwise
222
- """
223
- if name in self._uniforms:
224
- return self._uniforms[name][3]
225
- return False
226
-
227
- def get_uniform_array_size(self, name: str) -> int:
228
- """
229
- Get the size of a uniform array, returns 1 for non-arrays.
230
-
231
- Args:
232
- name: The name of the uniform variable
233
-
234
- Returns:
235
- int: The array size, or 0 if uniform not found
236
- """
237
- if name in self._uniforms:
238
- return self._uniforms[name][2]
239
- return 0
240
-
241
- def set_uniform_buffer(self, uniform_block_name: str, size: int, data) -> bool:
242
- """
243
- Set uniform buffer data for the specified uniform block.
244
- This is the Python equivalent of the C++ ShaderProgram::setUniformBuffer method.
245
-
246
- Args:
247
- uniform_block_name: Name of the uniform block
248
- size: Size of the data in bytes
249
- data: Data to upload (can be ctypes array, bytes, or buffer-like object)
250
-
251
- Returns:
252
- bool: True if successful, False otherwise
253
- """
254
- if uniform_block_name not in self._registered_uniform_blocks:
255
- logger.error(
256
- f"Uniform block '{uniform_block_name}' not found in shader '{self._name}'"
257
- )
258
- return False
259
-
260
- block = self._registered_uniform_blocks[uniform_block_name]
261
-
262
- try:
263
- # Bind the uniform buffer
264
- gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, block["buffer"])
265
-
266
- # Upload the data
267
- data = np.frombuffer(data, dtype=np.float32)
268
- gl.glBufferData(gl.GL_UNIFORM_BUFFER, size, data, gl.GL_DYNAMIC_DRAW)
269
-
270
- # Bind the buffer to the uniform block binding point
271
- gl.glBindBufferBase(gl.GL_UNIFORM_BUFFER, block["loc"], block["buffer"])
272
-
273
- # Unbind the buffer
274
- gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, 0)
275
-
276
- return True
277
-
278
- except Exception as e:
279
- logger.error(f"Failed to set uniform buffer '{uniform_block_name}': {e}")
280
- return False
281
-
282
- def set_uniform(self, name: str, *value: Any) -> None:
283
- """
284
- Set a uniform variable value.
285
-
286
- This method automatically detects the type of the value and calls the
287
- appropriate OpenGL uniform function. Supports scalars, vectors, matrices,
288
- and custom vector/matrix types.
289
-
290
- Args:
291
- name: The name of the uniform variable
292
- *value: The value(s) to set
293
- """
294
- loc = self.get_uniform_location(name)
295
- if loc == -1:
296
- logger.warning(f"Uniform location not found for '{name}'")
297
- return
298
-
299
- # Get uniform info for better type handling
300
- uniform_info = self.get_uniform_info(name)
301
- _, uniform_type, array_size, is_array = uniform_info
302
-
303
- if len(value) == 1:
304
- val = value[0]
305
- if isinstance(val, int):
306
- gl.glUniform1i(loc, val)
307
- elif isinstance(val, float):
308
- gl.glUniform1f(loc, val)
309
- elif isinstance(val, Mat2):
310
- gl.glUniformMatrix2fv(
311
- loc, 1, gl.GL_FALSE, (ctypes.c_float * 4)(*val.get_matrix())
312
- )
313
- elif isinstance(val, Mat3):
314
- gl.glUniformMatrix3fv(
315
- loc, 1, gl.GL_FALSE, (ctypes.c_float * 9)(*val.get_matrix())
316
- )
317
- elif isinstance(val, Mat4):
318
- gl.glUniformMatrix4fv(
319
- loc, 1, gl.GL_FALSE, (ctypes.c_float * 16)(*val.get_matrix())
320
- )
321
- elif isinstance(val, Vec2):
322
- gl.glUniform2f(loc, *val)
323
- elif isinstance(val, Vec3):
324
- gl.glUniform3f(loc, *val)
325
- elif isinstance(val, Vec4):
326
- gl.glUniform4f(loc, *val)
327
- else:
328
- try:
329
- val = list(value[0])
330
- if len(val) == 4:
331
- gl.glUniformMatrix2fv(
332
- loc, 1, gl.GL_FALSE, (ctypes.c_float * 4)(*val)
333
- )
334
- elif len(val) == 9:
335
- gl.glUniformMatrix3fv(
336
- loc, 1, gl.GL_FALSE, (ctypes.c_float * 9)(*val)
337
- )
338
- elif len(val) == 16:
339
- gl.glUniformMatrix4fv(
340
- loc, 1, gl.GL_FALSE, (ctypes.c_float * 16)(*val)
341
- )
342
- except TypeError:
343
- logger.warning(
344
- f"Warning: uniform '{name}' has unknown type: {type(val)}"
345
- )
346
-
347
- elif len(value) == 2:
348
- gl.glUniform2f(loc, *value)
349
- elif len(value) == 3:
350
- gl.glUniform3f(loc, *value)
351
- elif len(value) == 4:
352
- gl.glUniform4f(loc, *value)
353
-
354
- def set_uniform_1fv(self, name: str, values: List[float]) -> None:
355
- """
356
- Set a float array uniform.
357
-
358
- Args:
359
- name: The name of the uniform variable
360
- values: List of float values
361
- """
362
- """Set a float array uniform"""
363
- loc = self.get_uniform_location(name)
364
- if loc != -1:
365
- gl.glUniform1fv(loc, len(values), (ctypes.c_float * len(values))(*values))
366
-
367
- def set_uniform_2fv(self, name: str, values: List[List[float]]) -> None:
368
- """
369
- Set a vec2 array uniform.
370
-
371
- Args:
372
- name: The name of the uniform variable
373
- values: List of vec2 values (each as a list of 2 floats)
374
- """
375
- """Set a vec2 array uniform"""
376
- loc = self.get_uniform_location(name)
377
- if loc != -1:
378
- flat_values = [item for vec in values for item in vec]
379
- gl.glUniform2fv(
380
- loc, len(values), (ctypes.c_float * len(flat_values))(*flat_values)
381
- )
382
-
383
- def set_uniform_3fv(self, name: str, values: List[List[float]]) -> None:
384
- """
385
- Set a vec3 array uniform.
386
-
387
- Args:
388
- name: The name of the uniform variable
389
- values: List of vec3 values (each as a list of 3 floats)
390
- """
391
- """Set a vec3 array uniform"""
392
- loc = self.get_uniform_location(name)
393
- if loc != -1:
394
- flat_values = [item for vec in values for item in vec]
395
- gl.glUniform3fv(
396
- loc, len(values), (ctypes.c_float * len(flat_values))(*flat_values)
397
- )
398
-
399
- def set_uniform_4fv(self, name: str, values: List[List[float]]) -> None:
400
- """
401
- Set a vec4 array uniform.
402
-
403
- Args:
404
- name: The name of the uniform variable
405
- values: List of vec4 values (each as a list of 4 floats)
406
- """
407
- """Set a vec4 array uniform"""
408
- loc = self.get_uniform_location(name)
409
- if loc != -1:
410
- flat_values = [item for vec in values for item in vec]
411
- gl.glUniform4fv(
412
- loc, len(values), (ctypes.c_float * len(flat_values))(*flat_values)
413
- )
414
-
415
- def set_uniform_1iv(self, name: str, values: List[int]) -> None:
416
- """
417
- Set an int array uniform.
418
-
419
- Args:
420
- name: The name of the uniform variable
421
- values: List of integer values
422
- """
423
- """Set an int array uniform"""
424
- loc = self.get_uniform_location(name)
425
- if loc != -1:
426
- gl.glUniform1iv(loc, len(values), (ctypes.c_int * len(values))(*values))
427
-
428
- def set_uniform_matrix2fv(
429
- self,
430
- name: str,
431
- matrices: List[Union[Mat2, List[float]]],
432
- transpose: bool = False,
433
- ) -> None:
434
- """
435
- Set a mat2 array uniform.
436
-
437
- Args:
438
- name: The name of the uniform variable
439
- matrices: List of 2x2 matrices (Mat2 objects or lists of 4 floats)
440
- transpose: Whether to transpose the matrices
441
- """
442
- """Set a mat2 array uniform"""
443
- loc = self.get_uniform_location(name)
444
- if loc != -1:
445
- flat_values = []
446
- for matrix in matrices:
447
- if hasattr(matrix, "get_matrix"):
448
- flat_values.extend(matrix.get_matrix())
449
- else:
450
- flat_values.extend(matrix)
451
- gl.glUniformMatrix2fv(
452
- loc,
453
- len(matrices),
454
- gl.GL_TRUE if transpose else gl.GL_FALSE,
455
- (ctypes.c_float * len(flat_values))(*flat_values),
456
- )
457
-
458
- def set_uniform_matrix3fv(
459
- self,
460
- name: str,
461
- matrices: List[Union[Mat3, List[float]]],
462
- transpose: bool = False,
463
- ) -> None:
464
- """
465
- Set a mat3 array uniform.
466
-
467
- Args:
468
- name: The name of the uniform variable
469
- matrices: List of 3x3 matrices (Mat3 objects or lists of 9 floats)
470
- transpose: Whether to transpose the matrices
471
- """
472
- """Set a mat3 array uniform"""
473
- loc = self.get_uniform_location(name)
474
- if loc != -1:
475
- flat_values = []
476
- for matrix in matrices:
477
- if hasattr(matrix, "get_matrix"):
478
- flat_values.extend(matrix.get_matrix())
479
- else:
480
- flat_values.extend(matrix)
481
- gl.glUniformMatrix3fv(
482
- loc,
483
- len(matrices),
484
- gl.GL_TRUE if transpose else gl.GL_FALSE,
485
- (ctypes.c_float * len(flat_values))(*flat_values),
486
- )
487
-
488
- def set_uniform_matrix4fv(
489
- self,
490
- name: str,
491
- matrices: List[Union[Mat4, List[float]]],
492
- transpose: bool = False,
493
- ) -> None:
494
- """
495
- Set a mat4 array uniform.
496
-
497
- Args:
498
- name: The name of the uniform variable
499
- matrices: List of 4x4 matrices (Mat4 objects or lists of 16 floats)
500
- transpose: Whether to transpose the matrices
501
- """
502
- """Set a mat4 array uniform"""
503
- loc = self.get_uniform_location(name)
504
- if loc != -1:
505
- flat_values = []
506
- for matrix in matrices:
507
- if hasattr(matrix, "get_matrix"):
508
- flat_values.extend(matrix.get_matrix())
509
- else:
510
- flat_values.extend(matrix)
511
- gl.glUniformMatrix4fv(
512
- loc,
513
- len(matrices),
514
- gl.GL_TRUE if transpose else gl.GL_FALSE,
515
- (ctypes.c_float * len(flat_values))(*flat_values),
516
- )
517
-
518
- def get_uniform_1f(self, name: str) -> float:
519
- """
520
- Get a single float uniform value.
521
-
522
- Args:
523
- name: The name of the uniform variable
524
-
525
- Returns:
526
- The float value, or 0.0 if not found
527
- """
528
- loc = self.get_uniform_location(name)
529
- if loc != -1:
530
- result = (ctypes.c_float * 1)()
531
- gl.glGetUniformfv(self._id, loc, result)
532
- return result[0]
533
- return 0.0
534
-
535
- def get_uniform_2f(self, name: str) -> List[float]:
536
- """
537
- Get a vec2 uniform value.
538
-
539
- Args:
540
- name: The name of the uniform variable
541
-
542
- Returns:
543
- A list of 2 floats, or [0.0, 0.0] if not found
544
- """
545
- loc = self.get_uniform_location(name)
546
- if loc != -1:
547
- result = (ctypes.c_float * 2)()
548
- gl.glGetUniformfv(self._id, loc, result)
549
- return list(result)
550
- return [0.0, 0.0]
551
-
552
- def get_uniform_3f(self, name: str) -> List[float]:
553
- """
554
- Get a vec3 uniform value.
555
-
556
- Args:
557
- name: The name of the uniform variable
558
-
559
- Returns:
560
- A list of 3 floats, or [0.0, 0.0, 0.0] if not found
561
- """
562
- loc = self.get_uniform_location(name)
563
- if loc != -1:
564
- result = (ctypes.c_float * 3)()
565
- gl.glGetUniformfv(self._id, loc, result)
566
- return list(result)
567
- return [0.0, 0.0, 0.0]
568
-
569
- def get_uniform_4f(self, name: str) -> List[float]:
570
- """
571
- Get a vec4 uniform value.
572
-
573
- Args:
574
- name: The name of the uniform variable
575
-
576
- Returns:
577
- A list of 4 floats, or [0.0, 0.0, 0.0, 0.0] if not found
578
- """
579
- loc = self.get_uniform_location(name)
580
- if loc != -1:
581
- result = (ctypes.c_float * 4)()
582
- gl.glGetUniformfv(self._id, loc, result)
583
- return list(result)
584
- return [0.0, 0.0, 0.0, 0.0]
585
-
586
- def get_uniform_mat2(self, name: str) -> List[float]:
587
- """
588
- Get a mat2 uniform value.
589
-
590
- Args:
591
- name: The name of the uniform variable
592
-
593
- Returns:
594
- A list of 4 floats representing the 2x2 matrix, or zeros if not found
595
- """
596
- loc = self.get_uniform_location(name)
597
- if loc != -1:
598
- result = (ctypes.c_float * 4)()
599
- gl.glGetUniformfv(self._id, loc, result)
600
- return list(result)
601
- return [0.0] * 4
602
-
603
- def get_uniform_mat3(self, name: str) -> List[float]:
604
- """
605
- Get a mat3 uniform value.
606
-
607
- Args:
608
- name: The name of the uniform variable
609
-
610
- Returns:
611
- A list of 9 floats representing the 3x3 matrix, or zeros if not found
612
- """
613
- loc = self.get_uniform_location(name)
614
- if loc != -1:
615
- result = (ctypes.c_float * 9)()
616
- gl.glGetUniformfv(self._id, loc, result)
617
- return list(result)
618
- return [0.0] * 9
619
-
620
- def get_uniform_mat4(self, name: str) -> List[float]:
621
- """
622
- Get a mat4 uniform value.
623
-
624
- Args:
625
- name: The name of the uniform variable
626
-
627
- Returns:
628
- A list of 16 floats representing the 4x4 matrix, or zeros if not found
629
- """
630
- loc = self.get_uniform_location(name)
631
- if loc != -1:
632
- result = (ctypes.c_float * 16)()
633
- gl.glGetUniformfv(self._id, loc, result)
634
- return list(result)
635
- return [0.0] * 16
636
-
637
- def get_uniform_mat4x3(self, name: str) -> List[float]:
638
- """
639
- Get a mat4x3 uniform value.
640
-
641
- Args:
642
- name: The name of the uniform variable
643
-
644
- Returns:
645
- A list of 12 floats representing the 4x3 matrix, or zeros if not found
646
- """
647
- loc = self.get_uniform_location(name)
648
- if loc != -1:
649
- result = (ctypes.c_float * 12)()
650
- gl.glGetUniformfv(self._id, loc, result)
651
- return list(result)
652
- return [0.0] * 12
653
-
654
- def get_uniform_block_data(self, name: str) -> Optional[Dict[str, Any]]:
655
- """
656
- Get uniform block data by name.
657
-
658
- Args:
659
- name: The name of the uniform block
660
-
661
- Returns:
662
- Dictionary containing uniform block data, or None if not found
663
- """
664
- """Get uniform block data by name"""
665
- return self._registered_uniform_blocks.get(name, None)
666
-
667
- def get_registered_uniform_blocks(self) -> Dict[str, Dict[str, Any]]:
668
- """
669
- Get all registered uniform blocks.
670
-
671
- Returns:
672
- A copy of the registered uniform blocks dictionary
673
- """
674
- """Get all registered uniform blocks"""
675
- return self._registered_uniform_blocks.copy()
676
-
677
- def get_uniform_block_location(self, name: str) -> int:
678
- """
679
- Get uniform block location by name.
680
-
681
- Args:
682
- name: The name of the uniform block
683
-
684
- Returns:
685
- The uniform block index/location, or -1 if not found
686
- """
687
- """Get uniform block location by name"""
688
- if name in self._registered_uniform_blocks:
689
- return self._registered_uniform_blocks[name]["loc"]
690
- else:
691
- logger.warning(f"Uniform block '{name}' not found in shader '{self._name}'")
692
- return -1
693
-
694
- def get_uniform_block_buffer(self, name: str) -> int:
695
- """
696
- Get uniform block buffer by name.
697
-
698
- Args:
699
- name: The name of the uniform block
700
-
701
- Returns:
702
- The OpenGL buffer ID, or 0 if not found
703
- """
704
- """Get uniform block buffer by name"""
705
- if name in self._registered_uniform_blocks:
706
- return self._registered_uniform_blocks[name]["buffer"]
707
- else:
708
- logger.warning(f"Uniform block '{name}' not found in shader '{self._name}'")
709
- return 0
710
-
711
- def get_gl_type_string(self, gl_type: int) -> str:
712
- """
713
- Convert OpenGL type constant to human-readable string.
714
-
715
- Args:
716
- gl_type: OpenGL type constant (e.g., GL_FLOAT, GL_FLOAT_VEC3)
717
-
718
- Returns:
719
- str: Human-readable type string
720
- """
721
- type_map = {
722
- gl.GL_FLOAT: "float",
723
- gl.GL_FLOAT_VEC2: "vec2",
724
- gl.GL_FLOAT_VEC3: "vec3",
725
- gl.GL_FLOAT_VEC4: "vec4",
726
- gl.GL_DOUBLE: "double",
727
- gl.GL_INT: "int",
728
- gl.GL_UNSIGNED_INT: "unsigned int",
729
- gl.GL_BOOL: "bool",
730
- gl.GL_FLOAT_MAT2: "mat2",
731
- gl.GL_FLOAT_MAT3: "mat3",
732
- gl.GL_FLOAT_MAT4: "mat4",
733
- gl.GL_SAMPLER_2D: "sampler2D",
734
- gl.GL_SAMPLER_CUBE: "samplerCube",
735
- }
736
- return type_map.get(gl_type, f"Unknown type {gl_type}")
737
-
738
- def print_registered_uniforms(self) -> None:
739
- """
740
- Print information about all registered uniforms to the log.
741
- """
742
- logger.info(f"Registered uniforms for {self._name}:")
743
- base_uniforms = {}
744
- array_elements = {}
745
-
746
- # Separate base uniforms from array elements
747
- for name, (location, uniform_type, size, is_array) in self._uniforms.items():
748
- if "[" in name and "]" in name:
749
- # This is an array element
750
- base_name = name.split("[")[0]
751
- if base_name not in array_elements:
752
- array_elements[base_name] = []
753
- array_elements[base_name].append(
754
- (name, location, uniform_type, size, is_array)
755
- )
756
- else:
757
- base_uniforms[name] = (location, uniform_type, size, is_array)
758
-
759
- # Print base uniforms
760
- for name, (location, uniform_type, size, is_array) in base_uniforms.items():
761
- type_str = self.get_gl_type_string(uniform_type)
762
- if is_array:
763
- logger.info(
764
- f" {name}[{size}] (type: {type_str}, location: {location})"
765
- )
766
- else:
767
- logger.info(f" {name} (type: {type_str}, location: {location})")
768
-
769
- # Print array elements grouped by base name
770
- for base_name, elements in array_elements.items():
771
- logger.info(f" Array elements for {base_name}:")
772
- for element_name, location, uniform_type, size, is_array in elements:
773
- type_str = self.get_gl_type_string(uniform_type)
774
- logger.info(
775
- f" {element_name} (type: {type_str}, location: {location})"
776
- )
777
-
778
- def print_registered_uniform_blocks(self) -> None:
779
- """
780
- Print information about all registered uniform blocks to the log.
781
- """
782
- logger.info(f"Registered uniform blocks for {self._name}:")
783
- for name, data in self._registered_uniform_blocks.items():
784
- logger.info(f" {name} (index: {data['loc']}, buffer: {data['buffer']})")
785
-
786
- def print_properties(self) -> None:
787
- """
788
- Print detailed properties and status information about this shader program.
789
- """
790
- logger.info(f"Properties for shader program {self._name}:")
791
- logger.info(f" ID: {self._id}")
792
-
793
- link_status = gl.glGetProgramiv(self._id, gl.GL_LINK_STATUS)
794
- logger.info(f" Link status: {link_status}")
795
-
796
- validate_status = gl.glGetProgramiv(self._id, gl.GL_VALIDATE_STATUS)
797
- logger.info(f" Validate status: {validate_status}")
798
-
799
- attached_shaders = gl.glGetProgramiv(self._id, gl.GL_ATTACHED_SHADERS)
800
- logger.info(f" Attached shaders: {attached_shaders}")
801
-
802
- active_attributes = gl.glGetProgramiv(self._id, gl.GL_ACTIVE_ATTRIBUTES)
803
- logger.info(f" Active attributes: {active_attributes}")
804
-
805
- active_uniforms = gl.glGetProgramiv(self._id, gl.GL_ACTIVE_UNIFORMS)
806
- logger.info(f" Active uniforms: {active_uniforms}")
807
-
808
- active_uniform_blocks = gl.glGetProgramiv(self._id, gl.GL_ACTIVE_UNIFORM_BLOCKS)
809
- logger.info(f" Active uniform blocks: {active_uniform_blocks}")
810
-
811
- if self._registered_uniform_blocks:
812
- logger.info(" Registered uniform blocks:")
813
- for name, data in self._registered_uniform_blocks.items():
814
- logger.info(
815
- f" {name} (index: {data['loc']}, buffer: {data['buffer']})"
816
- )