1use bitflags::bitflags;
2use core::{ffi::CStr, num::NonZeroU32};
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#[derive(Copy, Clone)]
39#[repr(u32)]
40pub enum DrawMode {
41 Points = ffi::GL_POINTS,
42 Lines = ffi::GL_LINES,
43 LineLoop = ffi::GL_LINE_LOOP,
44 LineStrip = ffi::GL_LINE_STRIP,
45 Triangles = ffi::GL_TRIANGLES,
46 TriangleStrip = ffi::GL_TRIANGLE_STRIP,
47 TriangleFan = ffi::GL_TRIANGLE_FAN,
48 LinesAdjacency = ffi::GL_LINES_ADJACENCY,
49 LineStripAdjacency = ffi::GL_LINE_STRIP_ADJACENCY,
50 TrianglesAdjacency = ffi::GL_TRIANGLES_ADJACENCY,
51 TriangleStripAdjacency = ffi::GL_TRIANGLE_STRIP_ADJACENCY,
52 Patches = ffi::GL_PATCHES,
53}
54
55#[repr(u32)]
56pub enum BufferUsage {
57 StreamDraw = ffi::GL_STREAM_DRAW,
60
61 StreamRead = ffi::GL_STREAM_READ,
64
65 StreamCopy = ffi::GL_STREAM_COPY,
68
69 StaticDraw = ffi::GL_STATIC_DRAW,
72
73 StaticRead = ffi::GL_STATIC_READ,
76
77 StaticCopy = ffi::GL_STATIC_COPY,
80
81 DynamicDraw = ffi::GL_DYNAMIC_DRAW,
84
85 DynamicRead = ffi::GL_DYNAMIC_READ,
88
89 DynamicCopy = ffi::GL_DYNAMIC_COPY,
92}
93
94#[derive(Copy, Clone)]
95#[repr(u32)]
96pub enum VertexAttribDataType {
97 Byte = ffi::GL_BYTE,
98 Short = ffi::GL_SHORT,
99 Int = ffi::GL_INT,
100 Fixed = ffi::GL_FIXED,
101 Float = ffi::GL_FLOAT,
102 HalfFloat = ffi::GL_HALF_FLOAT,
103 Double = ffi::GL_DOUBLE,
104 UnsignedByte = ffi::GL_UNSIGNED_BYTE,
105 UnsignedShort = ffi::GL_UNSIGNED_SHORT,
106 UnsignedInt = ffi::GL_UNSIGNED_INT,
107 }
112
113#[repr(u32)]
114pub enum TextureTarget {
115 Texture1D = ffi::GL_TEXTURE_1D,
116 Texture2D = ffi::GL_TEXTURE_2D,
117 Texture3D = ffi::GL_TEXTURE_3D,
118 Texture1DArray = ffi::GL_TEXTURE_1D_ARRAY,
119 Texture2DArray = ffi::GL_TEXTURE_2D_ARRAY,
120 TextureRectangle = ffi::GL_TEXTURE_RECTANGLE,
121 TextureCubeMap = ffi::GL_TEXTURE_CUBE_MAP,
122 TextureCubeMapArray = ffi::GL_TEXTURE_CUBE_MAP_ARRAY,
123 TextureBuffer = ffi::GL_TEXTURE_BUFFER,
124 Texture2DMultisample = ffi::GL_TEXTURE_2D_MULTISAMPLE,
125 Texture2DMultisampleArray = ffi::GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
126}
127
128#[derive(Copy, Clone)]
129#[repr(u32)]
130pub enum TextureSizedInternalFormat {
131 Rgba8 = ffi::GL_RGBA8,
132 Depth24Stencil8 = ffi::GL_DEPTH24_STENCIL8,
133 }
135
136#[derive(Copy, Clone)]
137pub enum FramebufferAttachment {
138 ColorAttachment(u8),
140 DepthAttachment,
141 StencilAttachment,
142 DepthStencilAttachment,
143}
144
145impl FramebufferAttachment {
146 const fn to_u32(self) -> u32 {
147 match self {
148 FramebufferAttachment::ColorAttachment(i) => ffi::GL_COLOR_ATTACHMENT0 + i as u32,
149 FramebufferAttachment::DepthAttachment => ffi::GL_DEPTH_ATTACHMENT,
150 FramebufferAttachment::StencilAttachment => ffi::GL_STENCIL_ATTACHMENT,
151 FramebufferAttachment::DepthStencilAttachment => ffi::GL_DEPTH_STENCIL_ATTACHMENT,
152 }
153 }
154}
155
156bitflags! {
157 #[derive(Copy, Clone)]
158 pub struct ClearMask: u32 {
159 const COLOR_BUFFER = ffi::GL_COLOR_BUFFER_BIT;
160 const DEPTH_BUFFER = ffi::GL_DEPTH_BUFFER_BIT;
161 const STENCIL_BUFFER = ffi::GL_STENCIL_BUFFER_BIT;
162 }
163}
164
165#[derive(Copy, Clone)]
166#[repr(u32)]
167pub enum Capability {
168 DepthTest = ffi::GL_DEPTH_TEST,
169 DebugOutput = ffi::GL_DEBUG_OUTPUT,
170}
171
172#[derive(Copy, Clone)]
173#[repr(u32)]
174pub enum DepthFunction {
175 Never = ffi::GL_NEVER,
176 Less = ffi::GL_LESS,
177 Equal = ffi::GL_EQUAL,
178 Lequal = ffi::GL_LEQUAL,
179 Greater = ffi::GL_GREATER,
180 Notequal = ffi::GL_NOTEQUAL,
181 Gequal = ffi::GL_GEQUAL,
182 Always = ffi::GL_ALWAYS,
183}
184
185pub unsafe fn depth_function(func: DepthFunction) {
193 ffi::glDepthFunc(func as _);
194}
195
196pub unsafe fn depth_mask(flag: bool) {
203 ffi::glDepthMask(flag as _);
204}
205
206pub unsafe fn depth_test(value: bool) {
213 if value {
214 enable(Capability::DepthTest);
215 } else {
216 disable(Capability::DepthTest);
217 }
218}
219
220pub unsafe fn enable(capability: Capability) {
227 ffi::glEnable(capability as _);
228}
229
230pub unsafe fn disable(capability: Capability) {
237 ffi::glDisable(capability as _);
238}
239
240pub unsafe fn create_shader(ty: ShaderType) -> Option<Shader> {
241 NonZeroU32::new(ffi::glCreateShader(ty as _)).map(Shader)
242}
243
244pub unsafe fn delete_shader(shader: Shader) {
245 ffi::glDeleteShader(shader.0.get());
246}
247
248pub unsafe fn shader_source(shader: Shader, source: &str) {
249 let ptr = source.as_ptr() as *const ffi::GLchar;
250 let length = source.len() as i32;
251 ffi::glShaderSource(shader.0.get(), 1, &ptr, &length);
252}
253
254pub unsafe fn compile_shader(shader: Shader) {
255 ffi::glCompileShader(shader.0.get());
256}
257
258pub unsafe fn get_shader_compile_status(shader: Shader) -> bool {
259 let mut status = 0;
260 ffi::glGetShaderiv(shader.0.get(), ffi::GL_COMPILE_STATUS, &mut status);
261 status == 1
262}
263
264#[cfg(feature = "alloc")]
265pub unsafe fn get_shader_info_log(shader: Shader) -> String {
266 let mut length = 0;
267 ffi::glGetShaderiv(shader.0.get(), ffi::GL_INFO_LOG_LENGTH, &mut length);
268
269 if length > 0 {
270 use core::mem::MaybeUninit;
271
272 use alloc::vec::Vec;
273
274 let mut log: Vec<MaybeUninit<u8>> = Vec::with_capacity(length as _);
275
276 ffi::glGetShaderInfoLog(shader.0.get(), length, &mut length, log.as_mut_ptr() as _);
277
278 log.set_len(length as _);
279
280 let log: Vec<u8> = core::mem::transmute(log);
281 String::from_utf8_unchecked(log)
282 } else {
283 String::new()
284 }
285}
286
287pub unsafe fn create_program() -> Option<Program> {
288 NonZeroU32::new(ffi::glCreateProgram()).map(Program)
289}
290
291pub unsafe fn attach_shader(program: Program, shader: Shader) {
292 ffi::glAttachShader(program.0.get(), shader.0.get());
293}
294
295pub unsafe fn link_program(program: Program) {
296 ffi::glLinkProgram(program.0.get());
297}
298
299pub unsafe fn use_program(program: Option<Program>) {
300 let raw = program.map(|p| p.0.get()).unwrap_or(0);
301
302 ffi::glUseProgram(raw);
303}
304
305pub unsafe fn get_program_link_status(program: Program) -> bool {
306 let mut status = 0;
307 ffi::glGetProgramiv(program.0.get(), ffi::GL_LINK_STATUS, &mut status);
308 status == 1
309}
310
311pub unsafe fn delete_program(program: Program) {
312 ffi::glDeleteProgram(program.0.get());
313}
314
315#[cfg(feature = "alloc")]
316pub unsafe fn get_program_info_log(program: Program) -> String {
317 let mut length = 0;
318 ffi::glGetProgramiv(program.0.get(), ffi::GL_INFO_LOG_LENGTH, &mut length);
319
320 if length > 0 {
321 use core::mem::MaybeUninit;
322
323 use alloc::vec::Vec;
324
325 let mut log: Vec<MaybeUninit<u8>> = Vec::with_capacity(length as _);
326
327 ffi::glGetProgramInfoLog(program.0.get(), length, &mut length, log.as_mut_ptr() as _);
328
329 log.set_len(length as _);
330
331 let log: Vec<u8> = core::mem::transmute(log);
332 String::from_utf8_unchecked(log)
333 } else {
334 String::new()
335 }
336}
337
338pub unsafe fn draw_arrays(mode: DrawMode, first: i32, count: i32) {
339 ffi::glDrawArrays(mode as _, first, count);
340}
341
342pub unsafe fn create_named_buffer() -> Option<Buffer> {
343 let mut buffer = 0;
344 ffi::glCreateBuffers(1, &mut buffer);
345 NonZeroU32::new(buffer).map(Buffer)
346}
347
348pub unsafe fn named_buffer_data_size(buffer: Buffer, size: i32, usage: BufferUsage) {
358 ffi::glNamedBufferData(buffer.0.get(), size as _, core::ptr::null(), usage as _);
359}
360
361pub unsafe fn named_buffer_data_u8_slice(buffer: Buffer, data: &[u8], usage: BufferUsage) {
371 ffi::glNamedBufferData(
372 buffer.0.get(),
373 data.len() as _,
374 data.as_ptr() as _,
375 usage as _,
376 );
377}
378
379pub unsafe fn delete_buffer(buffer: Buffer) {
380 ffi::glDeleteBuffers(1, &buffer.0.get());
381}
382
383pub unsafe fn create_named_vertex_array() -> Option<VertexArray> {
384 let mut vertex_array = 0;
385 ffi::glCreateVertexArrays(1, &mut vertex_array);
386 NonZeroU32::new(vertex_array).map(VertexArray)
387}
388
389pub unsafe fn delete_vertex_array(vertex_array: VertexArray) {
390 ffi::glDeleteVertexArrays(1, &vertex_array.0.get());
391}
392
393pub unsafe fn enable_vertex_array_attrib(vertex_array: VertexArray, index: u32) {
394 ffi::glEnableVertexArrayAttrib(vertex_array.0.get(), index);
395}
396
397pub unsafe fn vertex_array_element_buffer(vertex_array: VertexArray, buffer: Buffer) {
398 ffi::glVertexArrayElementBuffer(vertex_array.0.get(), buffer.0.get());
399}
400
401pub unsafe fn vertex_array_vertex_buffer(
402 vertex_array: VertexArray,
403 binding_index: u32,
404 buffer: Option<Buffer>,
405 offset: i32,
406 stride: i32,
407) {
408 let buffer = buffer.map_or(0, |b| b.0.get());
409 ffi::glVertexArrayVertexBuffer(
410 vertex_array.0.get(),
411 binding_index,
412 buffer,
413 offset as _,
414 stride,
415 );
416}
417
418pub unsafe fn vertex_array_attrib_format(
419 vertex_array: VertexArray,
420 index: u32,
421 size: i32,
422 data_type: VertexAttribDataType,
423 normalized: bool,
424 relative_offset: u32,
425) {
426 ffi::glVertexArrayAttribFormat(
427 vertex_array.0.get(),
428 index,
429 size,
430 data_type as _,
431 normalized as _,
432 relative_offset as _,
433 );
434}
435
436pub unsafe fn vertex_array_attrib_binding(
437 vertex_array: VertexArray,
438 attrib_index: u32,
439 binding_index: u32,
440) {
441 ffi::glVertexArrayAttribBinding(vertex_array.0.get(), attrib_index, binding_index);
442}
443
444pub unsafe fn create_texture(target: TextureTarget) -> Option<Texture> {
445 let mut texture = 0;
446 ffi::glCreateTextures(target as _, 1, &mut texture);
447 NonZeroU32::new(texture).map(Texture)
448}
449
450pub unsafe fn delete_texture(texture: Texture) {
451 ffi::glDeleteTextures(1, &texture.0.get());
452}
453
454pub unsafe fn texture_storage_2d(
455 texture: Texture,
456 levels: i32,
457 internal_format: TextureSizedInternalFormat,
458 width: i32,
459 height: i32,
460) {
461 ffi::glTextureStorage2D(
462 texture.0.get(),
463 levels as _,
464 internal_format as _,
465 width as _,
466 height as _,
467 );
468}
469
470pub unsafe fn create_framebuffer() -> Option<Framebuffer> {
471 let mut framebuffer = 0;
472 ffi::glCreateFramebuffers(1, &mut framebuffer);
473 NonZeroU32::new(framebuffer).map(Framebuffer)
474}
475
476pub unsafe fn delete_framebuffer(framebuffer: Framebuffer) {
477 ffi::glDeleteFramebuffers(1, &framebuffer.0.get());
478}
479
480pub unsafe fn named_framebuffer_texture(
481 framebuffer: Framebuffer,
482 attachment: FramebufferAttachment,
483 texture: Texture,
484 level: i32,
485) {
486 ffi::glNamedFramebufferTexture(
487 framebuffer.0.get(),
488 attachment.to_u32(),
489 texture.0.get(),
490 level as _,
491 );
492}
493
494pub unsafe fn bind_vertex_array(vertex_array: VertexArray) {
495 ffi::glBindVertexArray(vertex_array.0.get());
496}
497
498pub unsafe fn get_uniform_location(program: Program, name: &CStr) -> UniformLocation {
500 let raw = ffi::glGetUniformLocation(program.0.get(), name.as_ptr() as _);
501 UniformLocation(raw)
502}
503
504pub unsafe fn program_uniform_1_f32(program: Program, location: UniformLocation, value: f32) {
505 ffi::glProgramUniform1f(program.0.get(), location.0, value);
506}
507
508pub unsafe fn program_uniform_1_mat4(
521 program: Program,
522 location: UniformLocation,
523 transpose: bool,
524 value: &[f32],
525) {
526 ffi::glProgramUniformMatrix4fv(
527 program.0.get(),
528 location.0,
529 1,
530 transpose as _,
531 value.as_ptr(),
532 );
533}
534
535pub unsafe fn clear_color(red: f32, green: f32, blue: f32, alpha: f32) {
536 ffi::glClearColor(red, green, blue, alpha);
537}
538
539pub unsafe fn clear(mask: ClearMask) {
540 ffi::glClear(mask.bits());
541}
542
543pub unsafe fn viewport(x: i32, y: i32, width: i32, height: i32) {
544 ffi::glViewport(x, y, width, height);
545}
546
547