Source code for picogl.backend.modern.core.shader.program

from pathlib import Path

from OpenGL import GL as gl

from picogl.backend.modern.core.shader.compile import compile_shader
from picogl.backend.modern.core.shader.helpers import log_gl_error, read_shader_source
from picogl.backend.modern.core.uniform.location_value import set_uniform_location_value
from picogl.logger import Logger as log
from picogl.shaders.uniform import get_uniform_location


[docs] class ShaderProgram: """OpenGL Shader program manager for vertex and fragment shaders."""
[docs] def __init__( self, shader_name: str = None, vertex_source_file: str = None, fragment_source_file: str = None, glsl_dir: str | Path | None = None, ): """constructor"""
[docs] self.shader_name = shader_name
[docs] self.vertex_source_file = vertex_source_file
[docs] self.fragment_source_file = fragment_source_file
[docs] self.base_dir = glsl_dir
[docs] self.vertex_shader = None
[docs] self.fragment_shader = None
[docs] self.program = None
[docs] self.uniforms = {}
if vertex_source_file is not None and vertex_source_file is not None: self.init_shader_from_glsl_files( vertex_source_file=vertex_source_file, fragment_source_file=fragment_source_file, glsl_dir=glsl_dir, )
[docs] def __str__(self): return f"PicoGLShader(name={self.shader_name}, program={self.program})"
[docs] def __enter__(self): self.bind()
[docs] def __exit__(self, exc_type, exc_val, exc_tb): self.unbind()
[docs] def program_id(self): return self.program
[docs] def init_shader_from_glsl_files( self, vertex_source_file: str, fragment_source_file: str, glsl_dir: str | Path | None = None, ) -> None: """ init_shader_from_glsl_files :param glsl_dir: directory containing vertex shaders :param vertex_source_file: list of paths to vertex shaders :param fragment_source_file: list of paths to fragment shaders :return: None """ vertex_sources = read_shader_source(vertex_source_file, glsl_dir=glsl_dir) fragment_sources = read_shader_source(fragment_source_file, glsl_dir=glsl_dir) self.init_shader_from_glsl(vertex_sources, fragment_sources)
[docs] def init_shader_from_glsl(self, vertex_source: str, fragment_source: str) -> None: """ init_shader_from_glsl :param vertex_source: list of paths to vertex shaders :param fragment_source: list of paths to fragment shaders :return: None """ self.init_shader(vertex_source, fragment_source)
[docs] def init_shader(self, vertex_source: str, fragment_source: str): """ init_shader :param vertex_source: list of paths to vertex shaders :param fragment_source: list of paths to fragment shaders :return: None Create, compile, and link shaders into a program. """ self.create_shader_program() log.parameter("self.program", self.program, silent=True) log.parameter("vertex_source", vertex_source, silent=True) log.parameter("fragment_source", fragment_source, silent=True) self.vertex_shader = compile_shader( self.program, gl.GL_VERTEX_SHADER, vertex_source ) self.fragment_shader = compile_shader( self.program, gl.GL_FRAGMENT_SHADER, fragment_source ) self.link_shader_program()
[docs] def uniform(self, name: str, value): """ uniform :param name: str - uniform name :param value: value to set (float, int, vec2, vec3, vec4, mat4, or np.ndarray) :return: self - for chaining Set uniform value (auto-detect type) """ loc = self.uniforms.get(name) or self.get_uniform_location(name) self.uniforms[name] = loc set_uniform_location_value(loc, value) return self # allow chaining
[docs] def create_shader_program(self): """ create_shader_program """ self.program = gl.glCreateProgram() log.message(f"Created shader program {self.program}", silent=True) log_gl_error()
[docs] def get_uniform_location(self, uniform_name): """get_uniform_location""" mvp_id = get_uniform_location( shader_program=self.program, uniform_name=uniform_name ) return mvp_id
[docs] def begin(self): """begin""" gl.glUseProgram(self.program) log_gl_error()
[docs] def end(self): """end""" gl.glUseProgram(0)
[docs] def bind(self): """begin""" gl.glUseProgram(self.program) log_gl_error()
[docs] def unbind(self): gl.glUseProgram(0)
[docs] def release(self): gl.glUseProgram(0)
[docs] def delete(self): self.release()