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 }
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 }
112
113#[derive(Copy, Clone)]
114pub enum FramebufferAttachment {
115 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