1use std::error::Error as StdError;
5use std::ffi::CString;
6use std::fmt::Debug;
7use std::fmt::Display;
8use std::fmt::Formatter;
9use std::fmt::Result as FmtResult;
10use std::mem::MaybeUninit;
11use std::ops::BitOr;
12use std::ops::BitOrAssign;
13use std::ptr::null_mut;
14use std::slice;
15
16use crate::sys::BuiltinType;
17use crate::sys::Gl;
18use crate::sys::Sealed;
19
20use super::gl;
21
22
23#[derive(Debug)]
24pub struct Program(u32);
25
26#[derive(Debug)]
27pub struct Shader(u32);
28
29#[derive(Debug)]
30pub struct Framebuffer(u32);
31
32#[derive(Debug)]
33pub struct Texture(u32);
34
35#[derive(Debug)]
36pub struct VertexArrayObject(u32);
37
38#[derive(Debug)]
39pub struct VertexBufferObject(u32);
40
41#[derive(Debug)]
42pub struct UniformLocation(i32);
43
44
45#[derive(Eq, PartialEq)]
46pub struct Error(u32);
47
48impl Debug for Error {
49 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
50 Display::fmt(self, f)
51 }
52}
53
54impl Display for Error {
55 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
56 let err = match self.0 {
57 gl::INVALID_ENUM => "invalid enum",
58 gl::INVALID_VALUE => "invalid value",
59 gl::INVALID_OPERATION => "invalid operation",
60 gl::OUT_OF_MEMORY => "out of memory",
61 gl::INVALID_FRAMEBUFFER_OPERATION => "invalid framebuffer operation",
62 _ => return write!(f, "OpenGL error: {:#x}", self.0),
63 };
64 write!(f, "OpenGL error: {err} ({:#x})", self.0)
65 }
66}
67
68impl StdError for Error {}
69
70
71#[repr(u32)]
72#[non_exhaustive]
73#[derive(Clone, Copy, Debug)]
74pub enum Type {
75 Float = gl::FLOAT,
76 Short = gl::SHORT,
77 UnsignedByte = gl::UNSIGNED_BYTE,
78 UnsignedShort = gl::UNSIGNED_SHORT,
79}
80
81
82#[repr(u32)]
83#[non_exhaustive]
84#[derive(Clone, Copy, Debug)]
85pub enum Capability {
86 Blend = gl::BLEND,
87 CullFace = gl::CULL_FACE,
88 DepthTest = gl::DEPTH_TEST,
89 FramebufferSRGB = gl::FRAMEBUFFER_SRGB,
90 Multisample = gl::MULTISAMPLE,
91 ScissorTest = gl::SCISSOR_TEST,
92}
93
94
95#[repr(u32)]
96#[non_exhaustive]
97#[derive(Clone, Copy, Debug)]
98pub enum Func {
99 LessOrEqual = gl::LEQUAL,
100 Greater = gl::GREATER,
101}
102
103
104#[repr(u32)]
105#[non_exhaustive]
106#[derive(Clone, Copy, Debug)]
107pub enum Factor {
108 SrcAlpha = gl::SRC_ALPHA,
109 OneMinusSrcAlpha = gl::ONE_MINUS_SRC_ALPHA,
110}
111
112
113#[repr(u32)]
114#[non_exhaustive]
115#[derive(Clone, Copy, Debug)]
116pub enum FrontFace {
117 ClockWise = gl::CW,
118}
119
120
121#[repr(u32)]
122#[non_exhaustive]
123#[derive(Clone, Copy, Debug)]
124pub enum CullFace {
125 Back = gl::BACK,
126}
127
128
129#[repr(u32)]
130#[non_exhaustive]
131#[derive(Clone, Copy, Debug, Eq, PartialEq)]
132pub enum Primitive {
133 Lines = gl::LINES,
134 Triangles = gl::TRIANGLES,
135 TriangleFan = gl::TRIANGLE_FAN,
136 TriangleStrip = gl::TRIANGLE_STRIP,
137}
138
139
140#[derive(Clone, Copy, Debug)]
141pub struct ClearMask(u32);
142
143#[expect(non_upper_case_globals)]
144impl ClearMask {
145 pub const ColorBuffer: Self = Self(gl::COLOR_BUFFER_BIT);
146 pub const DepthBuffer: Self = Self(gl::DEPTH_BUFFER_BIT);
147}
148
149impl BitOr for ClearMask {
150 type Output = Self;
151
152 #[inline]
153 fn bitor(self, other: Self) -> Self::Output {
154 let mut result = self;
155 result |= other;
156 result
157 }
158}
159
160impl BitOrAssign for ClearMask {
161 #[inline]
162 fn bitor_assign(&mut self, other: Self) {
163 self.0 |= other.0;
164 }
165}
166
167
168#[derive(Debug, Eq, PartialEq)]
169pub struct FramebufferStatus(u32);
170
171#[expect(non_upper_case_globals)]
172impl FramebufferStatus {
173 pub const Complete: Self = Self(gl::FRAMEBUFFER_COMPLETE);
174}
175
176impl Display for FramebufferStatus {
177 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
178 write!(f, "{:#x}", self.0)
179 }
180}
181
182
183#[repr(u32)]
184#[non_exhaustive]
185#[derive(Clone, Copy, Debug)]
186pub enum ShaderType {
187 Fragment = gl::FRAGMENT_SHADER,
188 Vertex = gl::VERTEX_SHADER,
189}
190
191impl ShaderType {
192 pub fn as_str(&self) -> &'static str {
193 match self {
194 Self::Fragment => "fragment",
195 Self::Vertex => "vertex",
196 }
197 }
198}
199
200
201#[repr(u32)]
202#[non_exhaustive]
203#[derive(Clone, Copy, Debug)]
204pub enum VertexBufferTarget {
205 Array = gl::ARRAY_BUFFER,
206 ElementArray = gl::ELEMENT_ARRAY_BUFFER,
207}
208
209#[repr(u32)]
210#[non_exhaustive]
211#[derive(Clone, Copy, Debug)]
212pub enum VertexBufferUsage {
213 DynamicDraw = gl::DYNAMIC_DRAW,
214 StaticDraw = gl::STATIC_DRAW,
215 StreamDraw = gl::STREAM_DRAW,
216}
217
218
219#[repr(u32)]
220#[non_exhaustive]
221#[derive(Clone, Copy, Debug)]
222pub enum TextureTarget {
223 Texture2D = gl::TEXTURE_2D,
224 Texture2DArray = gl::TEXTURE_2D_ARRAY,
225}
226
227#[repr(u32)]
228#[non_exhaustive]
229#[derive(Clone, Copy, Debug)]
230pub enum TextureInternalFormat {
231 Gray8 = gl::R8,
232 Depth = gl::DEPTH_COMPONENT,
233 RGB8 = gl::RGB8,
234 SRGB8 = gl::SRGB8,
235 RGBA8 = gl::RGBA8,
236 SRGBA8 = gl::SRGB8_ALPHA8,
237}
238
239#[repr(u32)]
240#[non_exhaustive]
241#[derive(Clone, Copy, Debug)]
242pub enum TexturePixelFormat {
243 Gray = gl::RED,
244 Depth = gl::DEPTH_COMPONENT,
245 RGB = gl::RGB,
246 RGBA = gl::RGBA,
247}
248
249#[repr(u32)]
250#[non_exhaustive]
251#[derive(Clone, Copy, Debug)]
252pub enum TextureCompareMode {
253 RefToTexture = gl::COMPARE_REF_TO_TEXTURE,
254}
255
256#[repr(u32)]
257#[non_exhaustive]
258#[derive(Clone, Copy, Debug)]
259pub enum TextureWrap {
260 ClampToEdge = gl::CLAMP_TO_EDGE,
261 Repeat = gl::REPEAT,
262}
263
264#[repr(u32)]
265#[non_exhaustive]
266#[derive(Clone, Copy, Debug)]
267pub enum TextureFilterType {
268 Minimize = gl::TEXTURE_MIN_FILTER,
269 Magnify = gl::TEXTURE_MAG_FILTER,
270}
271
272#[repr(u32)]
273#[non_exhaustive]
274#[derive(Clone, Copy, Debug)]
275pub enum TextureFilter {
276 Linear = gl::LINEAR,
277 LinearMipmapLinear = gl::LINEAR_MIPMAP_LINEAR,
278}
279
280
281impl BuiltinType<Context> for u16 {
282 fn as_type() -> Type {
283 Type::UnsignedShort
284 }
285}
286
287
288#[derive(Clone, Debug, Default)]
292pub struct Context {}
293
294impl Context {
295 fn check_program(&self, program: &Program, status_attrib: u32) -> Result<(), Vec<u8>> {
296 let mut status = MaybeUninit::uninit();
297 let () = unsafe { gl::GetProgramiv(program.0, status_attrib, status.as_mut_ptr()) };
298 let status = unsafe { status.assume_init() };
299 if status == i32::from(false) {
300 let mut info_len = MaybeUninit::uninit();
301 let () = unsafe { gl::GetProgramiv(program.0, gl::INFO_LOG_LENGTH, info_len.as_mut_ptr()) };
302 let info_len = unsafe { info_len.assume_init() };
303
304 let mut log = Vec::<u8>::with_capacity(info_len as _);
305 let () = unsafe {
306 gl::GetProgramInfoLog(program.0, info_len, null_mut(), log.as_mut_ptr().cast());
307 };
308 let () = unsafe { log.set_len(info_len as _) };
309 Err(log)
310 } else {
311 Ok(())
312 }
313 }
314
315 #[inline]
316 fn set_uniform_matrices_impl(&self, location: &UniformLocation, matrices: &[[f32; 16]]) {
317 let transpose = 0;
318 let () = unsafe {
319 gl::UniformMatrix4fv(
320 location.0,
321 matrices.len() as _,
322 transpose,
323 matrices.as_ptr().cast(),
324 )
325 };
326 debug_assert_eq!(self.error(), Ok(()));
327 }
328}
329
330impl Sealed for Context {}
331
332impl Gl for Context {
333 type Error = Error;
334
335 type Capability = Capability;
336 type ClearMask = ClearMask;
337 type CullFace = CullFace;
338 type Factor = Factor;
339 type FramebufferStatus = FramebufferStatus;
340 type FrontFace = FrontFace;
341 type Func = Func;
342 type Primitive = Primitive;
343 type ShaderType = ShaderType;
344 type TextureCompareMode = TextureCompareMode;
345 type TextureFilter = TextureFilter;
346 type TextureFilterType = TextureFilterType;
347 type TextureInternalFormat = TextureInternalFormat;
348 type TexturePixelFormat = TexturePixelFormat;
349 type TextureTarget = TextureTarget;
350 type TextureWrap = TextureWrap;
351 type Type = Type;
352 type VertexBufferTarget = VertexBufferTarget;
353 type VertexBufferUsage = VertexBufferUsage;
354
355 type Framebuffer = Framebuffer;
356 type Program = Program;
357 type Shader = Shader;
358 type Texture = Texture;
359 type VertexArrayObject = VertexArrayObject;
360 type VertexBufferObject = VertexBufferObject;
361
362 type UniformLocation = UniformLocation;
363
364 #[inline]
365 fn error(&self) -> Result<(), Error> {
366 let error = unsafe { gl::GetError() };
367 if error == gl::NO_ERROR {
368 Ok(())
369 } else {
370 Err(Error(error))
371 }
372 }
373
374 #[inline]
375 fn enable(&self, capability: Capability) {
376 let () = unsafe { gl::Enable(capability as _) };
377 debug_assert_eq!(self.error(), Ok(()));
378 }
379
380 #[inline]
381 fn disable(&self, capability: Capability) {
382 let () = unsafe { gl::Disable(capability as _) };
383 debug_assert_eq!(self.error(), Ok(()));
384 }
385
386 #[inline]
387 fn set_depth_func(&self, func: Func) {
388 let () = unsafe { gl::DepthFunc(func as _) };
389 debug_assert_eq!(self.error(), Ok(()));
390 }
391
392 #[inline]
393 fn set_blend_func(&self, src_factor: Factor, dst_factor: Factor) {
394 let () = unsafe { gl::BlendFunc(src_factor as _, dst_factor as _) };
395 debug_assert_eq!(self.error(), Ok(()));
396 }
397
398 #[inline]
399 fn set_front_face(&self, face: FrontFace) {
400 let () = unsafe { gl::FrontFace(face as _) };
401 debug_assert_eq!(self.error(), Ok(()));
402 }
403
404 #[inline]
405 fn set_cull_face(&self, face: CullFace) {
406 let () = unsafe { gl::CullFace(face as _) };
407 debug_assert_eq!(self.error(), Ok(()));
408 }
409
410 #[inline]
411 fn set_viewport(&self, x: i32, y: i32, w: i32, h: i32) {
412 let () = unsafe { gl::Viewport(x, y, w, h) };
413 debug_assert_eq!(self.error(), Ok(()));
414 }
415
416 #[inline]
417 fn set_clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
418 let () = unsafe { gl::ClearColor(r, g, b, a) };
419 debug_assert_eq!(self.error(), Ok(()));
420 }
421
422 #[inline]
423 fn set_pixel_unpack_alignment(&self, alignment: u32) {
424 let () = unsafe { gl::PixelStorei(gl::UNPACK_ALIGNMENT, alignment as _) };
425 debug_assert_eq!(self.error(), Ok(()));
426 }
427
428 #[inline]
429 fn clear(&self, mask: ClearMask) {
430 let () = unsafe { gl::Clear(mask.0) };
431 debug_assert_eq!(self.error(), Ok(()));
432 }
433
434 #[inline]
435 fn draw_arrays(&self, primitive: Primitive, count: i32) {
436 let () = unsafe { gl::DrawArrays(primitive as _, 0, count) };
437 debug_assert_eq!(self.error(), Ok(()));
438 }
439
440 #[inline]
441 fn draw_arrays_instanced(&self, primitive: Primitive, count: i32, instance_count: i32) {
442 let () = unsafe { gl::DrawArraysInstanced(primitive as _, 0, count, instance_count) };
443 debug_assert_eq!(self.error(), Ok(()));
444 }
445
446 #[inline]
447 fn draw_elements<T>(&self, primitive: Primitive, count: i32)
448 where
449 T: BuiltinType<Self>,
450 {
451 let () = unsafe { gl::DrawElements(primitive as _, count, T::as_type() as _, null_mut()) };
452 debug_assert_eq!(self.error(), Ok(()));
453 }
454
455 #[inline]
456 fn create_framebuffer(&self) -> Result<Framebuffer, Error> {
457 let mut fbo = 0;
458 let () = unsafe { gl::GenFramebuffers(1, &mut fbo) };
459 let () = self.error()?;
460 Ok(Framebuffer(fbo))
461 }
462
463 #[inline]
464 fn delete_framebuffer(&self, fbo: &Framebuffer) {
465 let () = unsafe { gl::DeleteFramebuffers(1, &fbo.0) };
466 debug_assert_eq!(self.error(), Ok(()));
467 }
468
469 #[inline]
470 fn bind_framebuffer(&self, fbo: Option<&Framebuffer>) {
471 let fbo = fbo.map(|fbo| fbo.0).unwrap_or(0);
472 let () = unsafe { gl::BindFramebuffer(gl::FRAMEBUFFER, fbo) };
473 debug_assert_eq!(self.error(), Ok(()));
474 }
475
476 #[inline]
477 fn set_framebuffer_depth_texture(&self, texture_target: TextureTarget, texture: &Texture) {
478 let mipmap_level = 0;
479 let () = unsafe {
480 gl::FramebufferTexture2D(
481 gl::FRAMEBUFFER,
482 gl::DEPTH_ATTACHMENT,
483 texture_target as _,
484 texture.0,
485 mipmap_level,
486 )
487 };
488 debug_assert_eq!(self.error(), Ok(()));
489 }
490
491 #[inline]
492 fn unset_draw_buffer(&self) {
493 let () = unsafe { gl::DrawBuffer(gl::NONE) };
494 debug_assert_eq!(self.error(), Ok(()));
495 }
496
497 #[inline]
498 fn unset_read_buffer(&self) {
499 let () = unsafe { gl::ReadBuffer(gl::NONE) };
500 debug_assert_eq!(self.error(), Ok(()));
501 }
502
503 #[inline]
504 fn check_framebuffer_status(&self) -> FramebufferStatus {
505 let status = unsafe { gl::CheckFramebufferStatus(gl::FRAMEBUFFER) };
506 FramebufferStatus(status)
507 }
508
509 #[inline]
510 fn create_shader(&self, ty: ShaderType) -> Option<Shader> {
511 let shader = unsafe { gl::CreateShader(ty as _) };
512 if shader != 0 {
513 Some(Shader(shader))
514 } else {
515 None
516 }
517 }
518
519 #[inline]
520 fn delete_shader(&self, shader: &Shader) {
521 let () = unsafe { gl::DeleteShader(shader.0) };
522 debug_assert_eq!(self.error(), Ok(()));
523 }
524
525 #[inline]
526 fn set_shader_source(&self, shader: &Shader, source: &str) {
527 let srcs = [source.as_ptr().cast::<u8>()];
528 let src_lens = [source.len() as i32];
529 let () = unsafe {
530 gl::ShaderSource(
531 shader.0,
532 srcs.len() as _,
533 srcs.as_ptr().cast(),
534 src_lens.as_ptr(),
535 )
536 };
537 debug_assert_eq!(self.error(), Ok(()));
538 }
539
540 #[inline]
541 fn compile_shader(&self, shader: &Shader) -> Result<(), Vec<u8>> {
542 let () = unsafe { gl::CompileShader(shader.0) };
543 let mut status = MaybeUninit::uninit();
544 let () = unsafe { gl::GetShaderiv(shader.0, gl::COMPILE_STATUS, status.as_mut_ptr()) };
545 let status = unsafe { status.assume_init() };
546 if status == i32::from(false) {
547 let mut info_len = MaybeUninit::uninit();
548 let () = unsafe { gl::GetShaderiv(shader.0, gl::INFO_LOG_LENGTH, info_len.as_mut_ptr()) };
549 let info_len = unsafe { info_len.assume_init() };
550
551 let mut log = Vec::<u8>::with_capacity(info_len as _);
552 let () =
553 unsafe { gl::GetShaderInfoLog(shader.0, info_len, null_mut(), log.as_mut_ptr().cast()) };
554 let () = unsafe { log.set_len(info_len as _) };
555 Err(log)
556 } else {
557 Ok(())
558 }
559 }
560
561 #[inline]
562 fn attach_shader(&self, program: &Program, shader: &Shader) {
563 let () = unsafe { gl::AttachShader(program.0, shader.0) };
564 debug_assert_eq!(self.error(), Ok(()));
565 }
566
567 #[inline]
568 fn detach_shader(&self, program: &Program, shader: &Shader) {
569 let () = unsafe { gl::DetachShader(program.0, shader.0) };
570 debug_assert_eq!(self.error(), Ok(()));
571 }
572
573 #[inline]
574 fn create_program(&self) -> Option<Program> {
575 let program = unsafe { gl::CreateProgram() };
576 if program != 0 {
577 Some(Program(program))
578 } else {
579 None
580 }
581 }
582
583 #[inline]
584 fn delete_program(&self, program: &Program) {
585 let () = unsafe { gl::DeleteProgram(program.0) };
586 debug_assert_eq!(self.error(), Ok(()));
587 }
588
589 fn link_program(&self, program: &Program) -> Result<(), Vec<u8>> {
590 let () = unsafe { gl::LinkProgram(program.0) };
591 let () = self.check_program(program, gl::LINK_STATUS)?;
592 Ok(())
593 }
594
595 fn validate_program(&self, program: &Program) -> Result<(), Vec<u8>> {
596 let () = unsafe { gl::ValidateProgram(program.0) };
597 let () = self.check_program(program, gl::VALIDATE_STATUS)?;
598 Ok(())
599 }
600
601 #[inline]
602 fn use_program(&self, program: &Program) {
603 let () = unsafe { gl::UseProgram(program.0) };
604 debug_assert_eq!(self.error(), Ok(()));
605 }
606
607 #[inline]
608 fn attrib_location(&self, program: &Program, attrib: &str) -> Option<u32> {
609 let cattrib = CString::new(attrib).unwrap();
612 let idx = unsafe { gl::GetAttribLocation(program.0, cattrib.as_ptr()) };
613 if idx >= 0 {
614 Some(u32::try_from(idx).unwrap())
615 } else {
616 None
617 }
618 }
619
620 #[inline]
621 fn uniform_location(&self, program: &Program, uniform: &str) -> Option<UniformLocation> {
622 let cuniform = CString::new(uniform).unwrap();
625 let idx = unsafe { gl::GetUniformLocation(program.0, cuniform.as_ptr()) };
626 if idx >= -1 {
627 Some(UniformLocation(idx))
628 } else {
629 None
630 }
631 }
632
633 #[inline]
634 fn uniform_fv<const N: usize>(&self, program: &Program, location: &UniformLocation) -> [f32; N] {
635 let mut data = MaybeUninit::<[f32; N]>::uninit();
636 let () = unsafe { gl::GetUniformfv(program.0, location.0, data.as_mut_ptr().cast()) };
637 assert_eq!(self.error(), Ok(()));
640
641 unsafe { data.assume_init() }
643 }
644
645 #[inline]
646 fn set_uniform_1i(&self, location: &UniformLocation, data: i32) {
647 let () = unsafe { gl::Uniform1i(location.0, data) };
648 debug_assert_eq!(self.error(), Ok(()));
649 }
650
651 #[inline]
652 fn set_uniform_1ui(&self, location: &UniformLocation, data: u32) {
653 let () = unsafe { gl::Uniform1ui(location.0, data) };
654 debug_assert_eq!(self.error(), Ok(()));
655 }
656
657 #[inline]
658 fn set_uniform_1iv(&self, location: &UniformLocation, data: &[i32]) {
659 let () = unsafe { gl::Uniform1iv(location.0, data.len() as _, data.as_ptr()) };
660 debug_assert_eq!(self.error(), Ok(()));
661 }
662
663 #[inline]
664 fn set_uniform_1fv(&self, location: &UniformLocation, data: &[f32]) {
665 let () = unsafe { gl::Uniform1fv(location.0, data.len() as _, data.as_ptr()) };
666 debug_assert_eq!(self.error(), Ok(()));
667 }
668
669 #[inline]
670 fn set_uniform_3f(&self, location: &UniformLocation, data: &[f32; 3]) {
671 let () = unsafe { gl::Uniform3fv(location.0, 1, data.as_ptr()) };
672 debug_assert_eq!(self.error(), Ok(()));
673 }
674
675 #[inline]
676 fn set_uniform_4f(&self, location: &UniformLocation, data: &[f32; 4]) {
677 let () = unsafe { gl::Uniform4fv(location.0, 1, data.as_ptr()) };
678 debug_assert_eq!(self.error(), Ok(()));
679 }
680
681 #[inline]
682 fn set_uniform_matrices(&self, location: &UniformLocation, matrices: &[[f32; 16]]) {
683 self.set_uniform_matrices_impl(location, matrices)
684 }
685
686 #[inline]
687 fn set_uniform_matrix(&self, location: &UniformLocation, matrix: &[f32; 16]) {
688 self.set_uniform_matrices_impl(location, slice::from_ref(matrix))
689 }
690
691 #[inline]
692 fn create_vertex_buffer(&self) -> Result<VertexBufferObject, Error> {
693 let mut vbo = 0;
694 let () = unsafe { gl::GenBuffers(1, &mut vbo) };
695 let () = self.error()?;
696 Ok(VertexBufferObject(vbo))
697 }
698
699 #[inline]
700 fn delete_vertex_buffer(&self, vbo: &VertexBufferObject) {
701 let () = unsafe { gl::DeleteBuffers(1, &vbo.0) };
702 debug_assert_eq!(self.error(), Ok(()));
703 }
704
705 #[inline]
706 fn bind_vertex_buffer(&self, target: VertexBufferTarget, vbo: Option<&VertexBufferObject>) {
707 let vbo = vbo.map(|vbo| vbo.0).unwrap_or(0);
708 let () = unsafe { gl::BindBuffer(target as _, vbo) };
709 debug_assert_eq!(self.error(), Ok(()));
710 }
711
712 #[inline]
713 fn set_vertex_buffer_data<T>(
714 &self,
715 target: VertexBufferTarget,
716 usage: VertexBufferUsage,
717 data: &[T],
718 ) {
719 let () = unsafe {
720 gl::BufferData(
721 target as _,
722 size_of_val(data) as _,
723 data.as_ptr().cast(),
724 usage as _,
725 )
726 };
727 debug_assert_eq!(self.error(), Ok(()));
728 }
729
730 #[inline]
731 fn set_vertex_buffer_sub_data<T>(&self, target: VertexBufferTarget, data: &[T], offset: i32) {
732 let () = unsafe {
733 gl::BufferSubData(
734 target as _,
735 offset as _,
736 size_of_val(data) as _,
737 data.as_ptr().cast(),
738 )
739 };
740 debug_assert_eq!(self.error(), Ok(()));
741 }
742
743 #[inline]
744 fn create_vertex_array(&self) -> Result<VertexArrayObject, Error> {
745 let mut vao = 0;
746 let () = unsafe { gl::GenVertexArrays(1, &mut vao) };
747 let () = self.error()?;
748 Ok(VertexArrayObject(vao))
749 }
750
751 #[inline]
752 fn delete_vertex_array(&self, vao: &VertexArrayObject) {
753 let () = unsafe { gl::DeleteVertexArrays(1, &vao.0) };
754 debug_assert_eq!(self.error(), Ok(()));
755 }
756
757 #[inline]
758 fn bind_vertex_array(&self, vao: Option<&VertexArrayObject>) {
759 let vao = vao.map(|vao| vao.0).unwrap_or(0);
760 let () = unsafe { gl::BindVertexArray(vao) };
761 debug_assert_eq!(self.error(), Ok(()));
762 }
763
764 #[inline]
765 fn enable_vertex_attrib_array(&self, idx: u32) {
766 let () = unsafe { gl::EnableVertexAttribArray(idx) };
767 debug_assert_eq!(self.error(), Ok(()));
768 }
769
770 #[inline]
771 fn set_vertex_attrib_pointer(
772 &self,
773 idx: u32,
774 size: i32,
775 ty: Type,
776 normalize: bool,
777 stride: i32,
778 offset: i32,
779 ) {
780 let () = unsafe {
781 gl::VertexAttribPointer(
782 idx,
783 size,
784 ty as _,
785 normalize as u8,
786 stride,
787 offset as *const _,
788 )
789 };
790 debug_assert_eq!(self.error(), Ok(()));
791 }
792
793 fn create_texture(&self) -> Result<Texture, Error> {
794 let mut id = 0;
795 let () = unsafe { gl::GenTextures(1, &mut id) };
796 let () = self.error()?;
797 Ok(Texture(id))
798 }
799
800 #[inline]
801 fn delete_texture(&self, texture: &Texture) {
802 let () = unsafe { gl::DeleteTextures(1, &texture.0) };
803 debug_assert_eq!(self.error(), Ok(()));
804 }
805
806 #[inline]
807 fn bind_texture(&self, target: TextureTarget, texture: Option<&Texture>) {
808 let texture = texture.map(|texture| texture.0).unwrap_or(0);
809 let () = unsafe { gl::BindTexture(target as _, texture) };
810 debug_assert_eq!(self.error(), Ok(()));
811 }
812
813 #[inline]
814 fn set_active_texture_unit(&self, unit: u32) {
815 let () = unsafe { gl::ActiveTexture(gl::TEXTURE0 + unit) };
816 debug_assert_eq!(self.error(), Ok(()));
817 }
818
819 #[inline]
820 fn set_texture_image_2d(
821 &self,
822 target: TextureTarget,
823 internal_format: TextureInternalFormat,
824 pixel_format: TexturePixelFormat,
825 channel_type: Type,
826 w: u32,
827 h: u32,
828 pixels: Option<&[u8]>,
829 ) -> Result<(), Error> {
830 let level = 0;
831 let border = 0;
832
833 let () = unsafe {
834 gl::TexImage2D(
835 target as _,
836 level,
837 internal_format as _,
838 w as _,
839 h as _,
840 border,
841 pixel_format as _,
842 channel_type as _,
843 pixels
844 .map(|pixels| pixels.as_ptr().cast())
845 .unwrap_or_default(),
846 )
847 };
848 let () = self.error()?;
849 Ok(())
850 }
851
852 #[inline]
853 fn set_texture_image_3d(
854 &self,
855 target: TextureTarget,
856 internal_format: TextureInternalFormat,
857 pixel_format: TexturePixelFormat,
858 channel_type: Type,
859 w: u32,
860 h: u32,
861 count: u32,
862 pixels: Option<&[u8]>,
863 ) -> Result<(), Error> {
864 let level = 0;
865 let border = 0;
866
867 let () = unsafe {
868 gl::TexImage3D(
869 target as _,
870 level,
871 internal_format as _,
872 w as _,
873 h as _,
874 count as _,
875 border,
876 pixel_format as _,
877 channel_type as _,
878 pixels
879 .map(|pixels| pixels.as_ptr().cast())
880 .unwrap_or_default(),
881 )
882 };
883 let () = self.error()?;
884 Ok(())
885 }
886
887 #[inline]
888 fn set_texture_sub_image_3d(
889 &self,
890 target: TextureTarget,
891 pixel_format: TexturePixelFormat,
892 channel_type: Type,
893 x: u32,
894 y: u32,
895 z: u32,
896 w: u32,
897 h: u32,
898 pixels: &[u8],
899 ) -> Result<(), Error> {
900 let level = 0;
901 let depth = 1;
902
903 let () = unsafe {
904 gl::TexSubImage3D(
905 target as _,
906 level,
907 x as _,
908 y as _,
909 z as _,
910 w as _,
911 h as _,
912 depth,
913 pixel_format as _,
914 channel_type as _,
915 pixels.as_ptr().cast(),
916 )
917 };
918 let () = self.error()?;
919 Ok(())
920 }
921
922 #[inline]
923 fn set_texture_filter(
924 &self,
925 target: TextureTarget,
926 ty: TextureFilterType,
927 filter: TextureFilter,
928 ) {
929 let () = unsafe { gl::TexParameteri(target as _, ty as _, filter as _) };
930 debug_assert_eq!(self.error(), Ok(()));
931 }
932
933 #[inline]
934 fn set_texture_compare_mode(&self, target: TextureTarget, mode: TextureCompareMode) {
935 let () = unsafe { gl::TexParameteri(target as _, gl::TEXTURE_COMPARE_MODE, mode as _) };
936 debug_assert_eq!(self.error(), Ok(()));
937 }
938
939 #[inline]
940 fn set_texture_compare_func(&self, target: TextureTarget, func: Func) {
941 let () = unsafe { gl::TexParameteri(target as _, gl::TEXTURE_COMPARE_FUNC, func as _) };
942 debug_assert_eq!(self.error(), Ok(()));
943 }
944
945 #[inline]
946 fn set_texture_wrap(&self, target: TextureTarget, wrap: TextureWrap) {
947 let () = unsafe { gl::TexParameteri(target as _, gl::TEXTURE_WRAP_S, wrap as _) };
948 let () = unsafe { gl::TexParameteri(target as _, gl::TEXTURE_WRAP_T, wrap as _) };
949 debug_assert_eq!(self.error(), Ok(()));
950 }
951
952 #[inline]
953 fn generate_mipmaps(&self, target: TextureTarget) {
954 let () = unsafe { gl::GenerateMipmap(target as _) };
955 debug_assert_eq!(self.error(), Ok(()));
956 }
957}
958
959
960#[cfg(test)]
961mod tests {
962 use super::*;
963
964
965 #[test]
968 fn error_debug_impl() {
969 let err = Error(gl::INVALID_VALUE);
970 let s = format!("{err:?}");
971 assert_eq!(s, "OpenGL error: invalid value (0x501)");
972
973 let err = Error(0xfff);
974 let s = format!("{err:?}");
975 assert_eq!(s, "OpenGL error: 0xfff");
976 }
977}