Skip to content

gl33

FreeBodyEngine.graphics.gl33 #

The OpenGL 3.3 implementation of the FB graphics system.

GLFramebuffer(width, height, attachments, transparent=False) #

Bases: Framebuffer

The GL 3.3 implementation of Framebuffer: a real glGenFramebuffers object with one GL_TEXTURE_2D per color attachment (so it can also be sampled from later, e.g. a G-buffer channel) and a single shared renderbuffer for whichever depth/stencil/depth-stencil attachment was requested. self.attachments[name] (inherited from the base class) is repurposed here to hold each color attachment's actual GL_COLOR_ATTACHMENT0 + n enum rather than the (AttachmentType, AttachmentFormat) pair the constructor received - that original pair is kept separately in self._attachments since resize() needs it again to recreate storage at the new size.

Creates the FBO and, for every requested attachment, the backing GL object: a mipmapless linear-filtered GL_TEXTURE_2D for each COLOR attachment (bound to consecutive GL_COLOR_ATTACHMENTn slots), or one shared renderbuffer for a DEPTH/STENCIL/DEPTH_STENCIL attachment. Color attachments are also collected into draw_buffers and wired up via glDrawBuffers so a shader with multiple @output fields actually renders to all of them; with no color attachments at all, glDrawBuffer(GL_NONE)/glReadBuffer(GL_NONE) are set instead (a depth-only FBO, e.g. a shadow map). Raises RuntimeError if the finished FBO fails glCheckFramebufferStatus. transparent enables standard alpha blending for subsequent draws into this FBO.

depth_renderbuffer = glGenRenderbuffers(1) instance-attribute #

depth_texture_name = name instance-attribute #

fbo = glGenFramebuffers(1) instance-attribute #

num_color_attachments = color_attachment_index instance-attribute #

textures = {} instance-attribute #

bind() #

Binds this FBO as the current GL_FRAMEBUFFER and sets the GL viewport to its full size, so subsequent draws render into it at the correct resolution instead of whatever viewport the previously-bound target left set.

clear_color_attachment(name, value=(0.0, 0.0, 0.0, 0.0)) #

Clears the named color attachment to value via glClearBufferfv(GL_COLOR, draw_buffer_index, ...), targeting only that attachment's own draw-buffer index rather than every bound draw buffer at once (the effect a plain glClear(GL_COLOR_BUFFER_BIT) would have) - see the abstract method's docstring for why that distinction matters for a multi-attachment G-buffer.

draw(attachment, size=None) #

Draw a named attachment to the screen.

get_attachment_texture(attachment_name) #

Returns the raw GL texture id backing the named color attachment (there's nothing to return for a depth/stencil attachment - those are renderbuffers, not textures - so only entries in self.textures apply).

read(attachment_name) #

Reads back the named color attachment's pixels via glReadPixels, always as GL_FLOAT regardless of the attachment's own storage type, and reshapes the raw buffer into a (height, width, channels) float32 array (channels derived from the attachment's GL format via GL_CHANNEL_COUNT). This is a synchronous GPU->CPU stall - see the abstract method's docstring for when that's acceptable.

resize(size) #

Recreates every attachment's storage at the new size, mirroring init's attachment loop: each color texture is deleted and regenerated at the new dimensions (a GL texture's storage can't be resized in place), and the shared depth/stencil renderbuffer is likewise deleted and regenerated if one exists. Also re-runs the draw-buffers wiring and completeness check init does, and updates the GL viewport to match. Raises RuntimeError if the resized FBO is incomplete.

set_draw_buffers(names) #

See Framebuffer.set_draw_buffers. Assumes this FBO is already bound.

Builds the same full-width, position-equals-attachment-index array WebGL2Framebuffer.set_draw_buffers() is forced to use (GL_NONE at every color attachment not in names) rather than the more compact [self.attachments[n] for n in names] this used to be - desktop GL doesn't require that shape (it can remap an arbitrary subset onto sequential fragment-output locations starting at 0), but PBRPipeline's shaders (see graphics/pbr/shaders.py's LIGHTING_COMPOSITE_FRAG/default_forward.fbfrag) declare their real @output field at whatever location its physical attachment index is - padded with unused leading fields to get there - specifically so the same FBUSL source compiles correctly on WebGL2, which has no remapping at all (see WebGL2Framebuffer.set_draw_buffers()'s own docstring). Matching that convention here means one shared assumption ("output location N always means physical attachment N") holds on both backends instead of desktop silently tolerating a mismatch WebGL2 can't.

unbind() #

Rebinds the default framebuffer (0), i.e. the window's own backbuffer.

GLImage(data) #

Bases: Image

The GL 3.3 implementation of Image: a thin wrapper that reads its pixel data and rect straight off the underlying GLTextureManager-owned Texture rather than holding any separate GPU state of its own.

Forwards data (the Texture this image wraps) to Image.init, which stores it as self.texture.

get_data() #

Returns the wrapped texture's raw pixel data (see Texture.get_image_data).

get_size() #

Returns the wrapped texture's UV rect (x, y, w, h).

GLMesh(attributes, indices=None, primitive=None, index_type=None, usage=None) #

Bases: Mesh

The GL 3.3 implementation of Mesh: owns a real VAO, one VBO per vertex attribute, and an optional EBO for indexed drawing. Maps the abstract PrimitiveType onto the actual GL draw-mode enum once at construction (_render_mode) rather than re-resolving it on every draw().

Generates the VAO and, if indices is given, the EBO (VBOs themselves are created lazily per-attribute in upload()), resolves primitive to its GL draw-mode enum, and immediately calls upload() to push the mesh's initial data to the GPU.

ebo = glGenBuffers(1) if indices is not None else None instance-attribute #

vao = glGenVertexArrays(1) instance-attribute #

vbos = {} instance-attribute #

destroy() #

Deletes every attribute VBO, the EBO if this mesh has one, and the VAO itself, releasing all of this mesh's GPU resources.

draw() #

Issues the draw call: glDrawElements against the EBO if this mesh has indices, else glDrawArrays over a vertex count derived from the first attribute's raw array length divided by 3 (i.e. this non-indexed path assumes that first attribute is 3 components wide, such as a "verticies" vec3 channel).

upload() #

(Re)creates one VBO per entry in self.attributes and uploads its data, wiring each up as a sequential vertex attribute starting at location 0 in self.attributes' iteration order - so the order attributes are inserted into that dict is exactly the order the matching shader's in locations must line up with. Also uploads self.indices into the EBO if this mesh has one, recording its GL index-element type (gl_index_type) for draw() to use.

GLShader(vertex_source, fragment_source, injector, geometry_source=None) #

Bases: Shader

The GL 3.3 implementation of Shader: compiles FBUSL source via GL33Generator into a real GL program, introspects its uniforms, and caches each uniform's last-set value so set_uniform() can skip a redundant glUniform* call when the value hasn't actually changed.

generator_cls is a class attribute (not hardcoded inline in init) specifically so graphics/gles/shader.py's GLESShader can reuse every method here unchanged and only override which generator produces the GLSL text - the real GL program creation/introspection/ uniform dispatch below is all plain PyOpenGL calls, valid against a GLES 3.0 context exactly the same as a desktop 3.3 one.

Compiles vertex_source/fragment_source(/geometry_source) into a linked GL program (via self.generator_cls) and introspects its active uniforms into self.uniforms, seeding uniform_cache with None for each so the first set_uniform() call for any uniform always goes through.

generator_cls = GL33Generator class-attribute instance-attribute #

uniform_cache = {} instance-attribute #

uniforms = {} instance-attribute #

check_val_type(val, gl_type, name) #

Validates that val is an acceptable Python value for a uniform of GL type gl_type - logging an engine error and returning False if not. Color/Vector/Vector3 are accepted directly for the vector GL types they map onto, alongside a plain tuple/list/ndarray of the right length.

get_uniform(name) #

Returns the introspected GLUniform record (location/size/type) for uniform name.

rebuild(injector=..., vertex_source=None, fragment_source=None, geometry_source=...) #

Recompiles this shader in place (same object, new GL program) - used by dev-mode hot reload (see Material.reload_shader()). Passing vertex_source/fragment_source re-fetches from those (a fresh FileResource, not whatever's cached on self already) rather than this shader's existing ones, since a stale FileResource can be holding a file handle to a since-replaced inode (editors that save via write-to-temp-then-rename) and silently never see new content. geometry_source defaults to self.geometry_source unchanged (... rather than None, since None is itself a valid "no geometry shader" value some callers legitimately want to keep).

set_buffer(name, buffer) #

Binds buffer to the uniform block declared as name in this shader's source (self.data['buffers'], populated by generator-produced metadata) - warns instead of raising if name isn't a known buffer block.

set_uniform(name, val) #

Sets uniform name to val, after check_val_type() validates it. Skips the actual glUniform* call (and the cache update) if val equals the value already cached for this uniform, avoiding redundant driver calls when the same value is set every frame - as material properties typically are.

setup_uniforms() #

Populates self.uniforms from the program's active uniforms (glGetActiveUniform), normalizing the name PyOpenGL hands back (which can come as str, bytes, or a numpy array depending on driver/binding) to a plain, null-terminated string.

use() #

Activates this shader's program, updates the TIME builtin uniform if the shader declares one, and binds every currently-cached texture/texture-stack uniform (see _bind_textures).