--- id: gl title: Gl order: 60 --- OpenGL for Ludic. Gl.* binds the whole OpenGL 4.1 core API: every gl* entry point of the platform gl3.h is a method named by its snake case (glBindBuffer → Gl.bind_buffer, glTexImage2D → Gl.tex_image2d, glDrawElementsInstanced → Gl.draw_elements_instanced), with every GL_* constant available as written. Parameters keep the header's names as labels (glVertexAttribPointer's pointer is called offset, program is prog); GLfloat/GLdouble parameters take fixed, pointer parameters take the raw bytes/words buffers Ludic already has, and 64-bit sizes take long (an int widens). The binding is generated by ludic-dev glgen from the header, with one ABI thunk per entry point. A context comes from Gl.open(width, height, title): windowed, an NSOpenGLContext on the game's window at the display's backing resolution (2× on Retina — Gl.width()/Gl.height() are the drawable's pixels); headless, an offscreen context with a framebuffer standing in for the screen (Gl.screen_fbo()), so the same program renders and screenshots under the test harness. Gl.swap() presents, Gl.screenshot(path) writes the screen as a PPM, Gl.check(tag) prints any pending error. The glue: Gl.program(vs, fs) / Gl.program5(vs, tcs, tes, gs, fs) compile and link (logs on failure), Gl.uniform(prog, name), Gl.vao(), Gl.buffer(), Gl.texture(), Gl.framebuffer() allocate, and float data is filled from Q16.16 with Gl.floats(n) / Gl.put(buf, i, v) / Gl.bytes_of(n) or from IEEE bits with Gl.put_bits; Gl.f32(v) and Gl.fixed(bits) convert single values. The bare f_add/f_mul/… helpers do IEEE single-precision arithmetic on those bit patterns for programs that want real floats on the CPU. Using Gl.* links gl.ll, the thunks and OpenGL.framework; a program that does not is byte-identical to before. The ludic.render3d package is a physically based 3D renderer written on this surface (see examples/rendering/smooth.ludic here, and Maroon Lake for a game built on it). ```ludic program Triangle { property Marker { on: int = 1 } model Anchor { Marker } state TriangleState { prog: int = 0 vao: int = 0 } handler Boot(triangle_st: mut TriangleState) phase Start { spawn Anchor {} if not Gl.open(width: 640, height: 360, title: "GL") { quit() } triangle_st.prog = Gl.program(vs: "#version 410 core\nvoid main(){ gl_Position = vec4(float(gl_VertexID == 1) * 2.0 - 0.5, float(gl_VertexID == 2) * 2.0 - 0.5, 0.0, 1.0); }\n", fs: "#version 410 core\nout vec4 o; void main(){ o = vec4(1.0, 0.5, 0.2, 1.0); }\n") triangle_st.vao = Gl.vao() } handler Draw(triangle_st: TriangleState) phase Render { Gl.clear_color(red: 0.1, green: 0.1, blue: 0.15, alpha: 1.0) Gl.clear(mask: GL_COLOR_BUFFER_BIT) Gl.use_program(prog: triangle_st.prog) Gl.bind_vertex_array(array: triangle_st.vao) Gl.draw_arrays(mode: GL_TRIANGLES, first: 0, count: 3) Gl.swap() } } ```