diff --git a/arcade/gl/uniform.py b/arcade/gl/uniform.py index a1802e09d..3fca202cd 100644 --- a/arcade/gl/uniform.py +++ b/arcade/gl/uniform.py @@ -1,5 +1,6 @@ from __future__ import annotations +import struct from ctypes import POINTER, cast from pyglet import gl @@ -274,12 +275,18 @@ def _create_setter_func( is_matrix, ): """Create setters for OpenGL data.""" + # Matrix uniforms 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 + try: + # FIXME: Configure the struct format on the uniform to support + # other types than float + c_array[:] = struct.unpack(f"{length}f", value) + except Exception: + c_array[:] = value gl_program_setter(program_id, location, array_length, gl.GL_FALSE, ptr) else: @@ -290,6 +297,7 @@ def setter_func(value): # type: ignore #conditional function variants must have gl.glUseProgram(program_id) gl_setter(location, array_length, gl.GL_FALSE, ptr) + # Single value uniforms elif length == 1 and count == 1: if ctx._ext_separate_shader_objects_enabled: @@ -306,12 +314,20 @@ def setter_func(value): # type: ignore #conditional function variants must have gl.glUseProgram(program_id) gl_setter(location, array_length, ptr) + # Uniforms types with multiple components 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 + # Support buffer protocol + try: + # FIXME: Configure the struct format on the uniform to support + # other types than float + c_array[:] = struct.unpack(f"{length}f", values) + except Exception: + c_array[:] = values + gl_program_setter(program_id, location, array_length, ptr) else: diff --git a/tests/unit/gl/test_gl_program.py b/tests/unit/gl/test_gl_program.py index 8f41d49d5..2873e2dae 100644 --- a/tests/unit/gl/test_gl_program.py +++ b/tests/unit/gl/test_gl_program.py @@ -2,7 +2,7 @@ import pytest import arcade from pyglet import gl -from pyglet.math import Mat4 +from pyglet.math import Mat4, Mat3 from arcade.gl import ShaderException from arcade.gl.uniform import UniformBlock from arcade.gl.glsl import ShaderSource @@ -130,6 +130,7 @@ def test_program_basic(ctx): vertex_shader=""" #version 330 + uniform mat4 matrix; uniform vec2 pos_offset; in vec2 in_vert; @@ -137,7 +138,7 @@ def test_program_basic(ctx): out vec2 v_uv; void main() { - gl_Position = vec4(in_vert + pos_offset, 0.0, 1.0); + gl_Position = matrix * vec4(in_vert + pos_offset, 0.0, 1.0); v_uv = in_uv; } """, @@ -166,6 +167,16 @@ def test_program_basic(ctx): with pytest.raises(KeyError): program['this_uniform_do_not_exist'] + # uniform values using byte data. struct.unpack in uniform setters will read from + # objects supporting buffer protocol like glm and numpy types + mat44_bytes = b'\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?' + program['matrix'] = mat44_bytes + assert program['matrix'] == Mat4() + + # vectors + program['pos_offset'] = b'\x00\x00\x80?\x00\x00\x00@' + assert program['pos_offset'] == (1.0, 2.0) + def test_vertex_shader(ctx): # Program with only vertex shader