v2026.9.4
All Bundles
Bundle OpenGL 3.3 core rendering on top of SDL2. Builds on sdl2.obl for the window and context; this bundle is the GL side. Compile with -lib sdl2. Targets the **3.3 core profile**, forward-compatible. That is the highest common denominator across the platforms Objeck ships: Windows, Linux and macOS desktop all reach it, and macOS caps at 4.1 core so nothing above 4.1 is portable there. GLES-only hardware (Raspberry Pi and similar) is out of scope by construction. Layers, from thinnest to friendliest -- all public, so nothing is capped: * GLWindow -- a window and a 3.3 core context, opened and paced for you. * GL -- static state operations. Thin, but never per-vertex. * Shader -- a linked program; Flat/Textured/TexturedFog/Normals built in, so the common cases need no GLSL at all. * Mesh -- geometry uploaded once into buffer objects, drawn many times, with Cube/Plane/Quad/Sphere built in, OBJ loading, and instancing. * Texture2D -- a texture, from a file or generated; Solid/Checker built in. * Light -- one directional light plus ambient, written into a shader. * RenderTarget -- draw into a texture instead of the window, then sample it. * Material -- a surface: its texture, tint and shininess. * Frustum -- the six planes of a view, for skipping what is off screen. * ShadowMap -- shadows from a directional or spot light, depth pass and all. * PointShadow -- shadows from a point light, in every direction, via a cube map. * Overlay -- text and rectangles over the scene, positioned in pixels. * Transform -- position, rotation and scale, with a cached matrix. * Box, Scene -- a world of boxes: draws itself, and answers collision. ## Why the API is shaped this way The native call boundary is expensive: the VM resolves each native symbol by string on EVERY call (GetProcAddress/dlsym) and boxes every argument into a fresh holder. A 1:1 mapping of OpenGL onto that would be thousands of lookups and allocations per frame. So each call here does real work -- 'compile a program from two sources' is one call, not the five GL calls it decomposes into -- and bulk data crosses as whole arrays, never element by element. This happens to be exactly what GL 3.3 core wants anyway: upload geometry once, then draw with few calls. ## Adding a call One `void fn(VMContext&)` in the OpenGL section of core/lib/sdl/sdl.cpp, and one method here that names it. See that file's header for the two rules that matter (positional slot indices, and keeping each call coarse).

Box

An axis-aligned box in the world: where it is, how big it is, what it looks like, and whether you can walk through it. One cube mesh is shared by every Box; the box only supplies a transform. That is what keeps a scene of hundreds of boxes down to one uploaded mesh. **That shared mesh must span -1..1 on every axis**, because the model matrix scales it by `half` directly and `half` is a half-extent. Hand Scene a mesh built to -0.5..0.5 instead -- the "unit quad" in Mesh's own example is built that way -- and every box renders at half the size it claims, while OverlapsXZ goes on using the full half-extents. Geometry and collision then disagree with no error anywhere: you walk into walls that are not where they are drawn. The model matrix is computed once and cached, because a static prop's transform does not change between frames. Moving the box invalidates it.

Operations

GetMaterial #

method : public : GetMaterial() ~ Material

Return

TypeDescription
Materialthe material, or Nil when this box only has a texture

GetModelMatrix #

The box's model matrix: translate then scale, cached after the first call.

method : public : GetModelMatrix() ~ Float[]

Return

TypeDescription
Floata 4x4 model matrix, column-major

IsOpaque #

method : public : IsOpaque() ~ Bool

Return

TypeDescription
Booltrue when nothing about this box needs sorting

IsSolid #

Whether this box blocks movement. Floors and ceilings are usually set non-solid: they are drawn but should not stop a walking character.

method : public : IsSolid() ~ Bool

Return

TypeDescription
Booltrue when the box blocks

New # constructor

New(center:Vector3, half:Vector3, texture:Texture2D)

Parameters

NameTypeDescription
centerVector3the box's centre
halfVector3half-extents on each axis, so a 2x2x2 cube has half 1,1,1 -- which is also why the shared mesh has to span -1..1; see the class note
textureTexture2Dthe texture to draw it with; may be Nil

OverlapsXZ #

Whether a circle in plan view overlaps this box. Deliberately 2D: a walking character should not be blocked by something overhead, and testing the full 3D box would do exactly that. Corners are treated conservatively -- a near-miss at a corner counts as a hit, which is the right way to be wrong about a wall.

method : public : OverlapsXZ(x:Float, z:Float, radius:Float) ~ Bool

Parameters

NameTypeDescription
xFloatcircle centre x
zFloatcircle centre z
radiusFloatcircle radius

Return

TypeDescription
Booltrue when they overlap

SetCenter #

Move the box, discarding the cached transform.

method : public : SetCenter(center:Vector3) ~ Nil

Parameters

NameTypeDescription
centerVector3the new centre

SetMaterial #

Give this box a full material rather than a bare texture. Takes precedence over the texture it was constructed with -- a box with a material uses the material's texture, its tint and its shininess. Passing Nil goes back to the plain texture, which is what every existing scene uses and still works.

method : public : SetMaterial(material:Material) ~ Nil

Parameters

NameTypeDescription
materialMaterialthe material, or Nil

SetOpacity #

How opaque this box is. A transparent box is drawn after every solid one, furthest first -- which is what Scene->SetEye is for. Without that ordering a pane in front of another writes depth and hides it, and the result looks worse than no transparency at all.

method : public : SetOpacity(opacity:Float) ~ Nil

Parameters

NameTypeDescription
opacityFloat0.0 invisible to 1.0 solid

SetSolid #

method : public : SetSolid(solid:Bool) ~ Nil

Parameters

NameTypeDescription
solidBoolfalse to make the box scenery that does not block