Skip to main content

raylib/rlgl/
mod.rs

1//! Safe wrappers for rlgl, raylib's immediate-mode OpenGL abstraction layer
2//! (`rlgl.h`). rlgl sits directly beneath raylib's higher-level drawing
3//! functions and supports OpenGL 3.3, OpenGL 2.1, OpenGL ES 2.0, and the
4//! software-renderer backend — the same source compiles for all back-ends.
5//!
6//! This module exposes the surface most useful for custom rendering:
7//!
8//! - **Matrix stack** — [`rl_push_matrix`](RaylibRlgl::rl_push_matrix) returns
9//!   an [`RlMatrix`] RAII guard; `Drop` pops the matrix, so the stack is always
10//!   balanced even on early return.
11//! - **Immediate-mode vertex streams** —
12//!   [`rl_begin`](RaylibRlgl::rl_begin) / [`rl_draw`](RaylibRlgl::rl_draw) with
13//!   an [`RlImmediate`] RAII guard that calls `rlEnd` on drop.
14//! - **Render-state toggles** — depth test, back-face culling, etc.
15//! - **Safe bind helpers** — [`rl_set_texture`](RaylibRlgl::rl_set_texture) and
16//!   [`rl_enable_shader`](RaylibRlgl::rl_enable_shader) accept the crate's
17//!   [`Texture2D`](crate::core::texture::Texture2D) /
18//!   [`Shader`](crate::core::shaders::Shader) RAII handles instead of raw ids.
19//!
20//! GL-object *lifecycle* (create/destroy) stays with those safe types and raw
21//! [`ffi`]; the full rlgl surface is still available there as a power-user
22//! escape hatch.
23//!
24//! ## Coverage policy
25//!
26//! The safe surface deliberately covers the immediate-mode, matrix-stack, and
27//! render-state slice of rlgl. The per-function disposition of the entire
28//! rlgl FFI surface (wrapped / escape-hatch / future-work) is recorded in
29//! `docs/superpowers/notes/databuf-mesh-testing-complete.md`, along with the
30//! census script to regenerate it after a raylib bump.
31//!
32//! All entry points are on [`RaylibRlgl`], blanket-implemented for every draw
33//! handle, so they are only callable inside a `begin_drawing` frame.
34
35mod immediate;
36mod matrix;
37
38pub use immediate::{DrawMode, RlImmediate};
39pub use matrix::{MatrixMode, RlMatrix};
40
41use crate::core::drawing::RaylibDraw;
42use crate::ffi;
43use crate::math::Matrix;
44
45/// Immediate-mode rlgl drawing, available on every draw handle. See the module docs.
46pub trait RaylibRlgl: RaylibDraw + Sized {
47    // ── Matrix stack ────────────────────────────────────────────────────────
48
49    /// Push the current matrix onto the stack; the returned guard pops it on drop.
50    /// Apply transforms (`rl_translatef`/`rl_rotatef`/`rl_scalef`) through the guard.
51    #[inline]
52    fn rl_push_matrix(&mut self) -> RlMatrix<'_, Self> {
53        // SAFETY: the returned RlMatrix's Drop calls the matching rlPopMatrix.
54        unsafe { ffi::rlPushMatrix() };
55        RlMatrix::new(self)
56    }
57
58    /// Reset the current matrix to identity.
59    #[inline]
60    fn rl_load_identity(&mut self) {
61        // SAFETY: rlLoadIdentity is an unconditional state mutation; no preconditions.
62        unsafe { ffi::rlLoadIdentity() }
63    }
64
65    /// Multiply the current matrix by a translation.
66    #[inline]
67    fn rl_translatef(&mut self, x: f32, y: f32, z: f32) {
68        // SAFETY: pure rlgl state call; no preconditions.
69        unsafe { ffi::rlTranslatef(x, y, z) }
70    }
71
72    /// Multiply the current matrix by a rotation of `angle` degrees about (x,y,z).
73    #[inline]
74    fn rl_rotatef(&mut self, angle: f32, x: f32, y: f32, z: f32) {
75        // SAFETY: pure rlgl state call; no preconditions.
76        unsafe { ffi::rlRotatef(angle, x, y, z) }
77    }
78
79    /// Multiply the current matrix by a scale.
80    #[inline]
81    fn rl_scalef(&mut self, x: f32, y: f32, z: f32) {
82        // SAFETY: pure rlgl state call; no preconditions.
83        unsafe { ffi::rlScalef(x, y, z) }
84    }
85
86    /// Multiply the current matrix by `mat`.
87    #[inline]
88    fn rl_mult_matrixf(&mut self, mat: Matrix) {
89        // SAFETY: ffi::Matrix is repr(C) with 16 contiguous f32 fields in the
90        // column-major order rlMultMatrixf expects. Casting the Matrix address to
91        // *const f32 is sound: the struct starts with m0 at offset 0 and is
92        // exactly 16×f32 = 64 bytes (confirmed by bindgen size assertion).
93        unsafe { ffi::rlMultMatrixf(&mat as *const Matrix as *const f32) }
94    }
95
96    /// Choose which matrix subsequent operations affect.
97    #[inline]
98    fn rl_matrix_mode(&mut self, mode: MatrixMode) {
99        // SAFETY: pure rlgl state call; mode is guaranteed valid by the MatrixMode enum.
100        unsafe { ffi::rlMatrixMode(mode as i32) }
101    }
102
103    /// Multiply the current matrix by an orthographic projection.
104    #[inline]
105    fn rl_ortho(&mut self, left: f64, right: f64, bottom: f64, top: f64, near: f64, far: f64) {
106        // SAFETY: pure rlgl state call; no preconditions.
107        unsafe { ffi::rlOrtho(left, right, bottom, top, near, far) }
108    }
109
110    /// Set the projection matrix directly.
111    #[inline]
112    fn rl_set_matrix_projection(&mut self, proj: Matrix) {
113        // SAFETY: crate::math::Matrix is re-exported from ffi::Matrix (same type);
114        // passed by value to rlSetMatrixProjection which expects ffi::Matrix.
115        unsafe { ffi::rlSetMatrixProjection(proj) }
116    }
117
118    /// Set the model-view matrix directly.
119    #[inline]
120    fn rl_set_matrix_modelview(&mut self, view: Matrix) {
121        // SAFETY: same identity as rl_set_matrix_projection.
122        unsafe { ffi::rlSetMatrixModelview(view) }
123    }
124
125    // ── Immediate-mode vertex stream ─────────────────────────────────────────
126
127    /// Begin an immediate-mode vertex stream; the returned guard ends it on drop.
128    /// Emit vertices/colors through the guard. Prefer [`rl_draw`](RaylibRlgl::rl_draw).
129    #[inline]
130    fn rl_begin(&mut self, mode: DrawMode) -> RlImmediate<'_, Self> {
131        // SAFETY: the returned RlImmediate's Drop calls the matching rlEnd.
132        unsafe { ffi::rlBegin(mode as i32) };
133        RlImmediate::new(self)
134    }
135
136    /// Run `body` inside an immediate-mode block, ending it afterwards (closure form).
137    ///
138    /// # Example
139    /// ```no_run
140    /// use raylib::prelude::*;
141    /// fn frame(d: &mut RaylibDrawHandle) {
142    ///     d.rl_draw(DrawMode::Triangles, |v| {
143    ///         v.color4ub(Color::RED);
144    ///         v.vertex2f(0.0, 0.0);
145    ///         v.vertex2f(100.0, 0.0);
146    ///         v.vertex2f(50.0, 100.0);
147    ///     });
148    /// }
149    /// ```
150    #[inline]
151    fn rl_draw(&mut self, mode: DrawMode, body: impl FnOnce(&mut RlImmediate<'_, Self>)) {
152        let mut v = self.rl_begin(mode);
153        body(&mut v);
154    }
155
156    // ── Render-state toggles ─────────────────────────────────────────────────
157
158    /// Enable depth testing.
159    #[inline]
160    fn rl_enable_depth_test(&mut self) {
161        // SAFETY: unconditional rlgl state toggle; no preconditions.
162        unsafe { ffi::rlEnableDepthTest() }
163    }
164
165    /// Disable depth testing.
166    #[inline]
167    fn rl_disable_depth_test(&mut self) {
168        // SAFETY: unconditional rlgl state toggle; no preconditions.
169        unsafe { ffi::rlDisableDepthTest() }
170    }
171
172    /// Enable back-face culling.
173    #[inline]
174    fn rl_enable_backface_culling(&mut self) {
175        // SAFETY: unconditional rlgl state toggle; no preconditions.
176        unsafe { ffi::rlEnableBackfaceCulling() }
177    }
178
179    /// Disable back-face culling.
180    #[inline]
181    fn rl_disable_backface_culling(&mut self) {
182        // SAFETY: unconditional rlgl state toggle; no preconditions.
183        unsafe { ffi::rlDisableBackfaceCulling() }
184    }
185
186    // ── Bind-safe-handle methods ─────────────────────────────────────────────
187
188    /// Set the active texture for subsequent immediate-mode drawing.
189    ///
190    /// # Example
191    /// ```no_run
192    /// use raylib::prelude::*;
193    /// fn frame(d: &mut RaylibDrawHandle, tex: &Texture2D) {
194    ///     d.rl_set_texture(tex);
195    ///     d.rl_draw(DrawMode::Quads, |v| {
196    ///         v.color4ub(Color::WHITE);
197    ///         v.texcoord2f(0.0, 0.0); v.vertex2f(0.0, 0.0);
198    ///         v.texcoord2f(1.0, 0.0); v.vertex2f(64.0, 0.0);
199    ///         v.texcoord2f(1.0, 1.0); v.vertex2f(64.0, 64.0);
200    ///         v.texcoord2f(0.0, 1.0); v.vertex2f(0.0, 64.0);
201    ///     });
202    ///     d.rl_disable_texture();
203    /// }
204    /// ```
205    #[inline]
206    fn rl_set_texture(&mut self, texture: &crate::core::texture::Texture2D) {
207        // SAFETY: texture.id is a valid GPU texture id owned by the Texture2D RAII.
208        unsafe { ffi::rlSetTexture(texture.id) }
209    }
210
211    /// Enable a texture (by binding the safe handle's GL id).
212    #[inline]
213    fn rl_enable_texture(&mut self, texture: &crate::core::texture::Texture2D) {
214        // SAFETY: texture.id is a valid GPU texture id owned by the Texture2D RAII.
215        unsafe { ffi::rlEnableTexture(texture.id) }
216    }
217
218    /// Disable the active texture.
219    #[inline]
220    fn rl_disable_texture(&mut self) {
221        // SAFETY: unconditional rlgl state call; no preconditions.
222        unsafe { ffi::rlDisableTexture() }
223    }
224
225    /// Select the active multitexture slot.
226    #[inline]
227    fn rl_active_texture_slot(&mut self, slot: i32) {
228        // SAFETY: rlgl clamps out-of-range slots; no UB from an invalid slot value.
229        unsafe { ffi::rlActiveTextureSlot(slot) }
230    }
231
232    /// Enable a shader program (by binding the safe handle's GL id).
233    #[inline]
234    fn rl_enable_shader(&mut self, shader: &crate::core::shaders::Shader) {
235        // SAFETY: shader.id is a valid GPU shader id owned by the Shader RAII.
236        unsafe { ffi::rlEnableShader(shader.id) }
237    }
238
239    /// Set the active shader and its uniform locations (from the safe handle).
240    #[inline]
241    fn rl_set_shader(&mut self, shader: &crate::core::shaders::Shader) {
242        // SAFETY: shader.id is a valid GPU shader id; shader.locs is a non-null
243        // pointer owned and initialized by the Shader RAII's load path.
244        unsafe { ffi::rlSetShader(shader.id, shader.locs) }
245    }
246}
247
248impl<D: RaylibDraw> RaylibRlgl for D {}