arcade.gl.uniform 源代码
from __future__ import annotations
from ctypes import cast, POINTER
from pyglet import gl
from .exceptions import ShaderException
[文档]
class Uniform:
"""
A Program uniform
:param ctx: The context
:param program_id: The program id to which this uniform belongs
:param location: The uniform location
:param name: The uniform name
:param data_type: The data type of the uniform
:param array_length: The array length of the uniform
"""
_uniform_getters = {
gl.GLint: gl.glGetUniformiv,
gl.GLuint: gl.glGetUniformuiv,
gl.GLfloat: gl.glGetUniformfv,
}
_uniform_setters = {
# uniform type: (gl_type, setter, length, count)
# Integers 32 bit
gl.GL_INT: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_INT_VEC2: (gl.GLint, gl.glProgramUniform2iv, gl.glUniform2iv, 2, 1),
gl.GL_INT_VEC3: (gl.GLint, gl.glProgramUniform3iv, gl.glUniform3iv, 3, 1),
gl.GL_INT_VEC4: (gl.GLint, gl.glProgramUniform4iv, gl.glUniform4iv, 4, 1),
# Unsigned integers 32 bit
gl.GL_UNSIGNED_INT: (gl.GLuint, gl.glProgramUniform1uiv, gl.glUniform1uiv, 1, 1),
gl.GL_UNSIGNED_INT_VEC2: (gl.GLuint, gl.glProgramUniform2uiv, gl.glUniform2uiv, 2, 1),
gl.GL_UNSIGNED_INT_VEC3: (gl.GLuint, gl.glProgramUniform3uiv, gl.glUniform3uiv, 3, 1),
gl.GL_UNSIGNED_INT_VEC4: (gl.GLuint, gl.glProgramUniform4uiv, gl.glUniform4uiv, 4, 1),
# Integers 64 bit unsigned
gl.GL_INT64_ARB: (gl.GLint64, gl.glProgramUniform1i64vARB, gl.glUniform1i64vARB, 1, 1),
gl.GL_INT64_VEC2_ARB: (gl.GLint64, gl.glProgramUniform2i64vARB, gl.glUniform2i64vARB, 2, 1),
gl.GL_INT64_VEC3_ARB: (gl.GLint64, gl.glProgramUniform3i64vARB, gl.glUniform3i64vARB, 3, 1),
gl.GL_INT64_VEC4_ARB: (gl.GLint64, gl.glProgramUniform4i64vARB, gl.glUniform4i64vARB, 4, 1),
# Unsigned integers 64 bit
gl.GL_UNSIGNED_INT64_ARB: (gl.GLuint64, gl.glProgramUniform1ui64vARB, gl.glUniform1ui64vARB, 1, 1),
gl.GL_UNSIGNED_INT64_VEC2_ARB: (gl.GLuint64, gl.glProgramUniform2ui64vARB, gl.glUniform2ui64vARB, 2, 1),
gl.GL_UNSIGNED_INT64_VEC3_ARB: (gl.GLuint64, gl.glProgramUniform3ui64vARB, gl.glUniform3ui64vARB, 3, 1),
gl.GL_UNSIGNED_INT64_VEC4_ARB: (gl.GLuint64, gl.glProgramUniform4ui64vARB, gl.glUniform4ui64vARB, 4, 1),
# Bools
gl.GL_BOOL: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_BOOL_VEC2: (gl.GLint, gl.glProgramUniform2iv, gl.glUniform2iv, 2, 1),
gl.GL_BOOL_VEC3: (gl.GLint, gl.glProgramUniform3iv, gl.glUniform3iv, 3, 1),
gl.GL_BOOL_VEC4: (gl.GLint, gl.glProgramUniform4iv, gl.glUniform4iv, 4, 1),
# Floats 32 bit
gl.GL_FLOAT: (gl.GLfloat, gl.glProgramUniform1fv, gl.glUniform1fv, 1, 1),
gl.GL_FLOAT_VEC2: (gl.GLfloat, gl.glProgramUniform2fv, gl.glUniform2fv, 2, 1),
gl.GL_FLOAT_VEC3: (gl.GLfloat, gl.glProgramUniform3fv, gl.glUniform3fv, 3, 1),
gl.GL_FLOAT_VEC4: (gl.GLfloat, gl.glProgramUniform4fv, gl.glUniform4fv, 4, 1),
# Floats 64 bit
gl.GL_DOUBLE: (gl.GLdouble, gl.glProgramUniform1dv, gl.glUniform1dv, 1, 1),
gl.GL_DOUBLE_VEC2: (gl.GLdouble, gl.glProgramUniform2dv, gl.glUniform2dv, 2, 1),
gl.GL_DOUBLE_VEC3: (gl.GLdouble, gl.glProgramUniform3dv, gl.glUniform3dv, 3, 1),
gl.GL_DOUBLE_VEC4: (gl.GLdouble, gl.glProgramUniform4dv, gl.glUniform4dv, 4, 1),
# 1D Samplers
gl.GL_SAMPLER_1D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_INT_SAMPLER_1D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_UNSIGNED_INT_SAMPLER_1D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_TEXTURE_1D_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
# 2D samplers
gl.GL_SAMPLER_2D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_SAMPLER_2D_MULTISAMPLE: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_INT_SAMPLER_2D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_UNSIGNED_INT_SAMPLER_2D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_TEXTURE_2D_MULTISAMPLE: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
# Array
gl.GL_SAMPLER_2D_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_TEXTURE_2D_MULTISAMPLE_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
# 3D
gl.GL_SAMPLER_3D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
# Cube
gl.GL_SAMPLER_CUBE: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_TEXTURE_CUBE_MAP_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
# Matrices
gl.GL_FLOAT_MAT2: (gl.GLfloat, gl.glProgramUniformMatrix2fv, gl.glUniformMatrix2fv, 4, 1),
gl.GL_FLOAT_MAT3: (gl.GLfloat, gl.glProgramUniformMatrix3fv, gl.glUniformMatrix3fv, 9, 1),
gl.GL_FLOAT_MAT4: (gl.GLfloat, gl.glProgramUniformMatrix4fv, gl.glUniformMatrix4fv, 16, 1),
# Image (compute shader)
gl.GL_IMAGE_1D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_2D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_2D_RECT: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_3D: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_CUBE: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_1D_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_2D_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_CUBE_MAP_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_2D_MULTISAMPLE: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_2D_MULTISAMPLE_ARRAY: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
gl.GL_IMAGE_BUFFER: (gl.GLint, gl.glProgramUniform1iv, gl.glUniform1iv, 1, 1),
# TODO: test/implement these:
# gl.GL_FLOAT_MAT2x3: glUniformMatrix2x3fv,
# gl.GL_FLOAT_MAT2x4: glUniformMatrix2x4fv,
#
# gl.GL_FLOAT_MAT3x2: glUniformMatrix3x2fv,
# gl.GL_FLOAT_MAT3x4: glUniformMatrix3x4fv,
#
# gl.GL_FLOAT_MAT4x2: glUniformMatrix4x2fv,
# gl.GL_FLOAT_MAT4x3: glUniformMatrix4x3fv,
}
__slots__ = (
"_program_id",
"_location",
"_name",
"_data_type",
"_array_length",
"_components",
"getter",
"setter",
"_ctx",
)
def __init__(self, ctx, program_id, location, name, data_type, array_length):
self._ctx = ctx
self._program_id = program_id
self._location = location
self._name = name
self._data_type = data_type
# Array length of the uniform (1 if no array)
self._array_length = array_length
# Number of components (including per array entry)
self._components = 0
#: The getter function configured for this uniform
#: The setter function configured for this uniform
self._setup_getters_and_setters()
@property
def location(self) -> int:
"""The location of the uniform in the program"""
return self._location
@property
def name(self) -> str:
"""Name of the uniform"""
return self._name
@property
def array_length(self) -> int:
"""Length of the uniform array. If not an array 1 will be returned"""
return self._array_length
@property
def components(self) -> int:
"""
How many components for the uniform.
A vec4 will for example have 4 components.
"""
return self._components
def _setup_getters_and_setters(self):
"""Maps the right getter and setter functions for this uniform"""
try:
gl_type, gl_program_setter, gl_setter, length, count = self._uniform_setters[self._data_type]
self._components = length
except KeyError:
raise ShaderException(f"Unsupported Uniform type: {self._data_type}")
gl_getter = self._uniform_getters[gl_type]
is_matrix = self._data_type in (
gl.GL_FLOAT_MAT2,
gl.GL_FLOAT_MAT3,
gl.GL_FLOAT_MAT4,
)
# Create persistent mini c_array for getters and setters:
length = length * self._array_length # Increase buffer size to include arrays
c_array = (gl_type * length)()
ptr = cast(c_array, POINTER(gl_type))
# Create custom dedicated getters and setters for each uniform:
self.getter = Uniform._create_getter_func(
self._program_id, self._location, gl_getter, c_array, length,
)
self.setter = Uniform._create_setter_func(
self._ctx, self._program_id, self._location, gl_program_setter, gl_setter,
c_array, length, self._array_length, count, ptr, is_matrix,
)
@staticmethod
def _create_getter_func(program_id, location, gl_getter, c_array, length):
""" Create a function for getting/setting OpenGL data. """
def getter_func1():
""" Get single-element OpenGL uniform data. """
gl_getter(program_id, location, c_array)
return c_array[0]
def getter_func2():
""" Get list of OpenGL uniform data. """
gl_getter(program_id, location, c_array)
return tuple(c_array)
if length == 1:
return getter_func1
else:
return getter_func2
@staticmethod
def _create_setter_func(
ctx, program_id, location, gl_program_setter, gl_setter, c_array, length, array_length, count, ptr, is_matrix
):
""" Create setters for OpenGL data. """
if is_matrix:
if ctx._ext_separate_shader_objects_enabled:
def setter_func(value): # type: ignore #conditional function variants must have identical signature
""" Set OpenGL matrix uniform data. """
c_array[:] = value
gl_program_setter(program_id, location, array_length, gl.GL_FALSE, ptr)
else:
def setter_func(value): # type: ignore #conditional function variants must have identical signature
""" Set OpenGL matrix uniform data. """
c_array[:] = value
gl.glUseProgram(program_id)
gl_setter(location, array_length, gl.GL_FALSE, ptr)
elif length == 1 and count == 1:
if ctx._ext_separate_shader_objects_enabled:
def setter_func(value): # type: ignore #conditional function variants must have identical signature
""" Set OpenGL uniform data value. """
c_array[0] = value
gl_program_setter(program_id, location, array_length, ptr)
else:
def setter_func(value): # type: ignore #conditional function variants must have identical signature
""" Set OpenGL uniform data value. """
c_array[0] = value
gl.glUseProgram(program_id)
gl_setter(location, array_length, ptr)
elif length > 1 and count == 1:
if ctx._ext_separate_shader_objects_enabled:
def setter_func(values): # type: ignore #conditional function variants must have identical signature
""" Set list of OpenGL uniform data. """
c_array[:] = values
gl_program_setter(program_id, location, array_length, ptr)
else:
def setter_func(values): # type: ignore #conditional function variants must have identical signature
""" Set list of OpenGL uniform data. """
c_array[:] = values
gl.glUseProgram(program_id)
gl_setter(location, array_length, ptr)
else:
raise NotImplementedError("Uniform type not yet supported.")
return setter_func
def __repr__(self) -> str:
return f"<Uniform '{self._name}' loc={self._location} array_length={self._array_length}>"
[文档]
class UniformBlock:
"""
Wrapper for a uniform block in shaders.
"""
__slots__ = ("glo", "index", "size", "name")
def __init__(self, glo: int, index: int, size: int, name: str):
#: The OpenGL object handle
self.glo = glo
#: The index of the uniform block
self.index = index
#: The size of the uniform block
self.size = size
#: The name of the uniform block
self.name = name
@property
def binding(self) -> int:
"""Get or set the binding index for this uniform block"""
binding = gl.GLint()
gl.glGetActiveUniformBlockiv(
self.glo, self.index, gl.GL_UNIFORM_BLOCK_BINDING, binding
)
return binding.value
@binding.setter
def binding(self, binding: int):
gl.glUniformBlockBinding(self.glo, self.index, binding)
[文档]
def getter(self):
"""
The getter function for this uniform block.
Returns self.
"""
return self
[文档]
def setter(self, value: int):
"""
The setter function for this uniform block.
:param value: The binding index to set.
"""
self.binding = value
def __str__(self):
return f"<UniformBlock {self.name} index={self.index} size={self.size}>"