shader
FreeBodyEngine.graphics.webgl.shader
#
WebGL2Shader: the WebGL2 implementation of Shader. Mirrors GL33Shader's
shape closely (compile via a Generator, introspect uniforms, cache their
last-set value) - the real difference throughout this file is mechanical,
not conceptual: PyOpenGL's glFoo(...) global-state calls become
self.gl.foo(...) calls against this specific canvas's WebGL2RenderingContext
object (JS has no implicit "current context" the way desktop GL does), and
raw ints/floats/bools that PyOpenGL happily takes straight from a numpy
array need to cross into JS as an explicit typed array first (see
graphics/webgl/interop.py).
WebGL2Shader(vertex_source, fragment_source, injector, geometry_source=None)
#
Bases: Shader
The WebGL2 implementation of Shader - see this module's own docstring.
Compiles vertex_source/fragment_source into a linked WebGL2
program (via WebGL2Generator) and introspects its active uniforms
into self.uniforms. geometry_source is accepted only for
interface parity with GLShader/the abstract Shader signature -
WebGL2 has no geometry shader stage at all, so a non-None value
here would already have failed inside WebGL2Generator's
(deliberately empty) CAPABILITIES before ever reaching this
constructor.
gl = get_service('renderer').gl
instance-attribute
#
uniform_cache = {name: None for name in (self.uniforms)}
instance-attribute
#
uniforms = {}
instance-attribute
#
check_val_type(val, gl_type, name)
#
Same validation GLShader.check_val_type() does - WebGL2's type enum values line up with desktop GL's for every type this engine actually uses, so the exact same dispatch works unchanged.
get_uniform(name)
#
Returns the introspected WebGLUniform record for uniform name.
rebuild(injector=..., vertex_source=None, fragment_source=None, geometry_source=...)
#
Recompiles this shader in place - see GLShader.rebuild()'s own docstring, same reasoning applies unchanged.
set_buffer(name, buffer)
#
Not supported - WebGL2Generator's empty CAPABILITIES already
rejects any FBUSL @buffer block before a shader referencing one
could compile, so this should never actually be reached; kept as
a clear error rather than silently doing nothing if it somehow
is.
set_uniform(name, val)
#
Sets uniform name to val - same skip-if-unchanged caching
as GLShader.set_uniform().
setup_uniforms()
#
Populates self.uniforms from the program's active uniforms
(getActiveUniform/getUniformLocation) - the WebGL2 equivalent
of GLShader.setup_uniforms(), just against JS's object-returning
introspection calls instead of PyOpenGL's.
use()
#
Activates this shader's program, updates the TIME builtin
uniform if declared, and binds every cached texture uniform.
Resets the texture manager's slot allocation here (not just from Renderer.draw_mesh()) so a caller that draws directly - shader.use() + mesh.draw(), bypassing draw_mesh() entirely, as phonon's VisualizerPipeline does for its ping-pong fullscreen quad - still gets a clean, fully-unbound set of texture units every draw. See WebGL2TextureManager.begin_draw()'s own docstring for why a stale binding left over from a path that skips this causes WebGL2's "Feedback loop formed between Framebuffer and active Texture" error.
WebGLUniform(location, size, type)
dataclass
#
One introspected active uniform: its WebGL location handle (an
opaque JS object, unlike GL33's plain int), array size, and WebGL
type enum (a plain int - WebGL2's GLenum values for e.g.
FLOAT/FLOAT_VEC3/SAMPLER_2D are numerically identical to desktop GL's,
both being derived from the same OpenGL ES lineage, so GL33Shader's
own type-name table/dispatch logic below carries over unchanged).
create_shader_program(gl, vertex_src, fragment_src)
#
Compiles and links vertex_src/fragment_src into a linked WebGL2
program, raising RuntimeError with the driver's log on a compile or
link failure - same contract as gl33/shader.py's own
create_shader_program().
set_gl_uniform(gl, loc, t, val)
#
The actual gl.uniform*/gl.uniformMatrix* type dispatch, shared
by WebGL2Shader._set_gl_uniform() (an already-introspected uniform on
an ordinary shader) and WebGL2ComputeShader (graphics/webgl/compute.py -
a compute/raytrace kernel's own uniforms, introspected the same way but
with no per-shader wrapper object of its own) - mirrors
gl33/shader.py's own module-level set_gl_uniform() being shared with
GLComputeShader for the same reason.