tiny_gl/gl/
mod.rs

1use core::{ffi::CStr, num::NonZeroU32};
2use bitflags::bitflags;
3
4#[cfg(feature = "alloc")]
5use alloc::string::String;
6
7pub mod ffi;
8
9#[derive(Copy, Clone)]
10pub struct Shader(pub NonZeroU32);
11
12#[derive(Copy, Clone)]
13pub struct Program(pub NonZeroU32);
14
15#[derive(Copy, Clone)]
16pub struct Buffer(pub NonZeroU32);
17
18#[derive(Copy, Clone)]
19pub struct VertexArray(pub NonZeroU32);
20
21#[derive(Copy, Clone)]
22pub struct Texture(pub NonZeroU32);
23
24#[derive(Copy, Clone)]
25pub struct Framebuffer(pub NonZeroU32);
26
27#[derive(Copy, Clone)]
28pub struct UniformLocation(pub i32);
29
30#[repr(u32)]
31pub enum ShaderType {
32    Vertex = ffi::GL_VERTEX_SHADER,
33    Fragment = ffi::GL_FRAGMENT_SHADER,
34    Geometry = ffi::GL_GEOMETRY_SHADER,
35    Compute = ffi::GL_COMPUTE_SHADER,
36}
37
38#[repr(u32)]
39pub enum DrawMode {
40    Points = ffi::GL_POINTS,
41    Lines = ffi::GL_LINES,
42    LineLoop = ffi::GL_LINE_LOOP,
43    LineStrip = ffi::GL_LINE_STRIP,
44    Triangles = ffi::GL_TRIANGLES,
45    TriangleStrip = ffi::GL_TRIANGLE_STRIP,
46    TriangleFan = ffi::GL_TRIANGLE_FAN,
47    LinesAdjacency = ffi::GL_LINES_ADJACENCY,
48    LineStripAdjacency = ffi::GL_LINE_STRIP_ADJACENCY,
49    TrianglesAdjacency = ffi::GL_TRIANGLES_ADJACENCY,
50    TriangleStripAdjacency = ffi::GL_TRIANGLE_STRIP_ADJACENCY,
51    Patches = ffi::GL_PATCHES,
52}
53
54#[repr(u32)]
55pub enum BufferUsage {
56    StreamDraw = ffi::GL_STREAM_DRAW,
57    StreamRead = ffi::GL_STREAM_READ,
58    StreamCopy = ffi::GL_STREAM_COPY,
59
60    StaticDraw = ffi::GL_STATIC_DRAW,
61    StaticRead = ffi::GL_STATIC_READ,
62    StaticCopy = ffi::GL_STATIC_COPY,
63
64    DynamicDraw = ffi::GL_DYNAMIC_DRAW,
65    DynamicRead = ffi::GL_DYNAMIC_READ,
66    DynamicCopy = ffi::GL_DYNAMIC_COPY,
67}
68
69#[derive(Copy, Clone)]
70#[repr(u32)]
71pub enum VertexAttribDataType {
72    Byte = ffi::GL_BYTE,
73    Short = ffi::GL_SHORT,
74    Int = ffi::GL_INT,
75    Fixed = ffi::GL_FIXED,
76    Float = ffi::GL_FLOAT,
77    HalfFloat = ffi::GL_HALF_FLOAT,
78    Double = ffi::GL_DOUBLE,
79    UnsignedByte = ffi::GL_UNSIGNED_BYTE,
80    UnsignedShort = ffi::GL_UNSIGNED_SHORT,
81    UnsignedInt = ffi::GL_UNSIGNED_INT,
82
83    // Currently unsupported:
84    // GL_INT_2_10_10_10_REV 
85    // GL_UNSIGNED_INT_2_10_10_10_REV 
86    // GL_UNSIGNED_INT_10F_11F_11F_REV 
87}
88
89#[repr(u32)]
90pub enum TextureTarget {
91    Texture1D = ffi::GL_TEXTURE_1D,
92    Texture2D = ffi::GL_TEXTURE_2D,
93    Texture3D = ffi::GL_TEXTURE_3D,
94    Texture1DArray = ffi::GL_TEXTURE_1D_ARRAY,
95    Texture2DArray = ffi::GL_TEXTURE_2D_ARRAY,
96    TextureRectangle = ffi::GL_TEXTURE_RECTANGLE,
97    TextureCubeMap = ffi::GL_TEXTURE_CUBE_MAP,
98    TextureCubeMapArray = ffi::GL_TEXTURE_CUBE_MAP_ARRAY,
99    TextureBuffer = ffi::GL_TEXTURE_BUFFER,
100    Texture2DMultisample = ffi::GL_TEXTURE_2D_MULTISAMPLE,
101    Texture2DMultisampleArray = ffi::GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
102}
103
104#[derive(Copy, Clone)]
105#[repr(u32)]
106pub enum TextureSizedInternalFormat {
107    Rgba8 = ffi::GL_RGBA8,
108    Depth24Stencil8 = ffi::GL_DEPTH24_STENCIL8,
109
110    //TODO Others are available...
111}
112
113#[derive(Copy, Clone)]
114pub enum FramebufferAttachment {
115    /// May range from zero to the value of GL_MAX_COLOR_ATTACHMENTS minus one.
116    ColorAttachment(u8),
117    DepthAttachment,
118    StencilAttachment,
119    DepthStencilAttachment,
120}
121
122impl FramebufferAttachment {
123    const fn to_u32(self) -> u32 {
124        match self {
125            FramebufferAttachment::ColorAttachment(i) => ffi::GL_COLOR_ATTACHMENT0 + i as u32,
126            FramebufferAttachment::DepthAttachment => ffi::GL_DEPTH_ATTACHMENT,
127            FramebufferAttachment::StencilAttachment => ffi::GL_STENCIL_ATTACHMENT,
128            FramebufferAttachment::DepthStencilAttachment => ffi::GL_DEPTH_STENCIL_ATTACHMENT,
129        }
130    }
131}
132
133bitflags! {
134    #[derive(Copy, Clone)]    
135    pub struct ClearMask: u32 {
136        const COLOR_BUFFER = ffi::GL_COLOR_BUFFER_BIT;
137        const DEPTH_BUFFER = ffi::GL_DEPTH_BUFFER_BIT;
138        const STENCIL_BUFFER = ffi::GL_STENCIL_BUFFER_BIT;
139    }
140}
141
142pub unsafe fn create_shader(ty: ShaderType) -> Option<Shader> {
143    NonZeroU32::new(ffi::glCreateShader(ty as _)).map(Shader)
144}
145
146pub unsafe fn delete_shader(shader: Shader) {
147    ffi::glDeleteShader(shader.0.get());
148}
149
150pub unsafe fn shader_source(shader: Shader, source: &str) {
151    let ptr = source.as_ptr() as *const ffi::GLchar;
152    let length = source.len() as i32;
153    ffi::glShaderSource(shader.0.get(), 1, &ptr, &length);
154}
155
156pub unsafe fn compile_shader(shader: Shader) {
157    ffi::glCompileShader(shader.0.get());
158}
159
160pub unsafe fn get_shader_compile_status(shader: Shader) -> bool {
161    let mut status = 0;
162    ffi::glGetShaderiv(shader.0.get(), ffi::GL_COMPILE_STATUS, &mut status);
163    status == 1
164}
165
166#[cfg(feature = "alloc")]
167pub unsafe fn get_shader_info_log(shader: Shader) -> String {
168    let mut length = 0;
169    ffi::glGetShaderiv(shader.0.get(), ffi::GL_INFO_LOG_LENGTH, &mut length);
170
171    if length > 0 {
172        let mut log = String::with_capacity(length as _);
173
174        ffi::glGetShaderInfoLog(shader.0.get(), length, &mut length, log.as_mut_ptr() as _);
175
176        log.truncate(length as _);
177        log
178    } else {
179        String::new()
180    }
181}
182
183pub unsafe fn create_program() -> Option<Program> {
184    NonZeroU32::new(ffi::glCreateProgram()).map(Program)
185}
186
187pub unsafe fn attach_shader(program: Program, shader: Shader) {
188    ffi::glAttachShader(program.0.get(), shader.0.get());
189}
190
191pub unsafe fn link_program(program: Program) {
192    ffi::glLinkProgram(program.0.get());
193}
194
195pub unsafe fn use_program(program: Option<Program>) {
196    let raw = program.map(|p| p.0.get()).unwrap_or(0);
197    
198    ffi::glUseProgram(raw);
199}
200
201pub unsafe fn get_program_link_status(program: Program) -> bool {
202    let mut status = 0;
203    ffi::glGetProgramiv(program.0.get(), ffi::GL_LINK_STATUS, &mut status);
204    status == 1
205}
206
207pub unsafe fn delete_program(program: Program) {
208    ffi::glDeleteProgram(program.0.get());
209}
210
211#[cfg(feature = "alloc")]
212pub unsafe fn get_program_info_log(program: Program) -> String {
213    let mut length = 0;
214    ffi::glGetProgramiv(program.0.get(), ffi::GL_INFO_LOG_LENGTH, &mut length);
215
216    if length > 0 {
217        let mut log = String::with_capacity(length as _);
218
219        ffi::glGetProgramInfoLog(program.0.get(), length, &mut length, log.as_mut_ptr() as _);
220
221        log.truncate(length as _);
222        log
223    } else {
224        String::new()
225    }
226}
227
228pub unsafe fn draw_arrays(mode: DrawMode, first: i32, count: i32) {
229    ffi::glDrawArrays(mode as _, first, count);
230}
231
232pub unsafe fn create_named_buffer() -> Option<Buffer> {
233    let mut buffer = 0;
234    ffi::glCreateBuffers(1, &mut buffer);
235    NonZeroU32::new(buffer).map(Buffer)
236}
237
238pub unsafe fn named_buffer_data_size(buffer: Buffer, size: i32, usage: BufferUsage) {
239    ffi::glNamedBufferData(buffer.0.get(), size as _, core::ptr::null(), usage as _);
240}
241
242pub unsafe fn named_buffer_data_u8_slice(buffer: Buffer, data: &[u8], usage: BufferUsage) {
243    ffi::glNamedBufferData(buffer.0.get(), data.len() as _, data.as_ptr() as _, usage as _);
244}
245
246pub unsafe fn delete_buffer(buffer: Buffer) {
247    ffi::glDeleteBuffers(1, &buffer.0.get());
248}
249
250pub unsafe fn create_named_vertex_array() -> Option<VertexArray> {
251    let mut vertex_array = 0;
252    ffi::glCreateVertexArrays(1, &mut vertex_array);
253    NonZeroU32::new(vertex_array).map(VertexArray)
254}
255
256pub unsafe fn delete_vertex_array(vertex_array: VertexArray) {
257    ffi::glDeleteVertexArrays(1, &vertex_array.0.get());
258}
259
260pub unsafe fn enable_vertex_array_attrib(vertex_array: VertexArray, index: u32) {
261    ffi::glEnableVertexArrayAttrib(vertex_array.0.get(), index);
262}
263
264pub unsafe fn vertex_array_element_buffer(vertex_array: VertexArray, buffer: Buffer) {
265    ffi::glVertexArrayElementBuffer(vertex_array.0.get(), buffer.0.get());
266}
267
268pub unsafe fn vertex_array_vertex_buffer(vertex_array: VertexArray, binding_index: u32, buffer: Option<Buffer>, offset: i32, stride: i32) {
269    let buffer = buffer.map_or(0, |b| b.0.get());
270    ffi::glVertexArrayVertexBuffer(vertex_array.0.get(), binding_index, buffer, offset as _, stride);
271}
272
273pub unsafe fn vertex_array_attrib_format(vertex_array: VertexArray, index: u32, size: i32, data_type: VertexAttribDataType, normalized: bool, relative_offset: u32) {
274    ffi::glVertexArrayAttribFormat(vertex_array.0.get(), index, size, data_type as _, normalized as _, relative_offset as _);
275}
276
277pub unsafe fn vertex_array_attrib_binding(vertex_array: VertexArray, attrib_index: u32, binding_index: u32) {
278    ffi::glVertexArrayAttribBinding(vertex_array.0.get(), attrib_index, binding_index);
279}
280
281pub unsafe fn create_texture(target: TextureTarget) -> Option<Texture> {
282    let mut texture = 0;
283    ffi::glCreateTextures(target as _, 1, &mut texture);
284    NonZeroU32::new(texture).map(Texture)
285}
286
287pub unsafe fn delete_texture(texture: Texture) {
288    ffi::glDeleteTextures(1, &texture.0.get());
289}
290
291pub unsafe fn texture_storage_2d(texture: Texture, levels: i32, internal_format: TextureSizedInternalFormat, width: i32, height: i32) {
292    ffi::glTextureStorage2D(texture.0.get(), levels as _, internal_format as _, width as _, height as _);
293}
294
295pub unsafe fn create_framebuffer() -> Option<Framebuffer> {
296    let mut framebuffer = 0;
297    ffi::glCreateFramebuffers(1, &mut framebuffer);
298    NonZeroU32::new(framebuffer).map(Framebuffer)
299}
300
301pub unsafe fn delete_framebuffer(framebuffer: Framebuffer) {
302    ffi::glDeleteFramebuffers(1, &framebuffer.0.get());
303}
304
305pub unsafe fn named_framebuffer_texture(framebuffer: Framebuffer, attachment: FramebufferAttachment, texture: Texture, level: i32) {
306    ffi::glNamedFramebufferTexture(framebuffer.0.get(), attachment.to_u32(), texture.0.get(), level as _);
307}
308
309pub unsafe fn bind_vertex_array(vertex_array: VertexArray) {
310    ffi::glBindVertexArray(vertex_array.0.get());
311}
312
313pub unsafe fn get_uniform_location(program: Program, name: &CStr) -> UniformLocation {
314    let raw = ffi::glGetUniformLocation(program.0.get(), name.as_ptr() as _);
315    UniformLocation(raw)
316}
317
318pub unsafe fn program_uniform_1_f32(program: Program, location: UniformLocation, value: f32) {
319    ffi::glProgramUniform1f(program.0.get(), location.0, value);
320}
321
322pub unsafe fn clear_color(red: f32, green: f32, blue: f32, alpha: f32) {
323    ffi::glClearColor(red, green, blue, alpha);
324}
325
326pub unsafe fn clear(mask: ClearMask) {
327    ffi::glClear(mask.bits());
328}
329
330pub unsafe fn viewport(x: i32, y: i32, width: i32, height: i32) {
331    ffi::glViewport(x, y, width, height);
332}
333
334//TODO Make functions for all of these:
335// glNamedBufferStorage