tea/
lib.rs

1extern crate gl;
2
3use std::ffi::{c_void, CStr};
4
5pub mod buffer;
6pub mod glsl;
7pub mod vec;
8pub mod texture;
9pub mod target;
10pub mod vertex;
11
12pub use vec::{Vec2, Vec3, Vec4};
13
14pub trait GlslType {
15    fn to_glsl() -> String {
16        "".to_owned()
17    }
18}
19
20#[macro_export]
21macro_rules! impl_glsl {
22    ($tp: ty, $name: literal) => {
23        impl GlslType for $tp {
24            fn to_glsl() -> String { $name.to_owned() }
25        }
26    };
27}
28
29impl_glsl!(bool, "bool");
30impl_glsl!(i32, "int");
31impl_glsl!(u32, "uint");
32impl_glsl!(f32, "float");
33impl_glsl!(f64, "double");
34
35pub trait GlTarget {
36    fn target() -> u32;
37    fn binding() -> u32;
38    fn current_bind() -> u32 {
39        let mut gl_id = 0;
40        unsafe { gl::GetIntegerv(Self::binding(), &mut gl_id) };
41        return gl_id as u32;
42    }
43}
44
45pub trait GlBind {
46    fn bind(&self);
47    fn unbind(&self);
48}
49
50pub trait GlUse {
51    fn set_used(&self);
52    fn set_unused(&self);
53}
54
55pub trait GlEnum {
56    fn gl_enum() -> u32 { gl::NONE }
57    fn to_enum(&self) -> u32 { gl::NONE }
58}
59
60pub trait GlObject {
61    fn get_id(&self) -> u32;
62}
63
64pub trait GlAttrib: GlEnum + Sized {
65    fn size() -> u32 { 1 }
66    fn stride() -> usize { std::mem::size_of::<Self>() }
67    fn get_size(&self) -> u32 { Self::size() }
68    fn get_stride(&self) -> usize { Self::stride() }
69
70    fn setup_attrib(index: u32, normalized: bool, stride: i32, start: i32) {
71        unsafe { gl::VertexAttribPointer(index, Self::size() as i32, Self::gl_enum(), normalized as u8, stride, start as *const c_void) };
72    }
73}
74
75pub trait GlUniform {
76    fn uniform(location: i32, val: &Self);
77    fn uniformv(location: i32, count: i32, ptr: *const Self);
78
79    fn send_uniform(&self, location: i32);
80}
81
82#[derive(Default, Debug)]
83pub enum GlType {
84    #[default]
85    Byte,
86    UByte,
87    Short,
88    UShort,
89    Int,
90    UInt,
91    Float,
92    Double
93}
94
95impl GlEnum for GlType {
96    fn to_enum(&self) -> u32 {
97        match self {
98            GlType::Byte => { return gl::BYTE },
99            GlType::UByte => { return gl::UNSIGNED_BYTE },
100            GlType::Short => { return gl::SHORT },
101            GlType::UShort => { return gl::UNSIGNED_SHORT },
102            GlType::Int => { return gl::INT },
103            GlType::UInt => { return gl::UNSIGNED_INT },
104            GlType::Float => { return gl::FLOAT },
105            GlType::Double => { return gl::DOUBLE }
106        }
107    }
108}
109
110macro_rules! impl_type {
111    ($tp: ty, $Enum: expr) => {
112        impl GlEnum for $tp {
113            fn gl_enum() -> u32 { $Enum }
114            fn to_enum(&self) -> u32 { $Enum }
115        }
116
117        impl GlAttrib for $tp {}
118    };
119    ($tp: ty, $Enum: expr, $Uniform: ident, $Uniformv: ident) => {
120        impl GlEnum for $tp {
121            fn gl_enum() -> u32 { $Enum }
122            fn to_enum(&self) -> u32 { $Enum }
123        }
124
125        impl GlAttrib for $tp {}
126
127        impl GlUniform for $tp {
128            fn uniform(location: i32, val: &$tp) {
129                unsafe { gl::$Uniform(location, *val) };
130            }
131
132            fn uniformv(location: i32, count: i32, ptr: *const $tp) {
133                unsafe { gl::$Uniformv(location, count, ptr) };
134            }
135
136            fn send_uniform(&self, location: i32) {
137                unsafe { gl::$Uniform(location, *self) };
138            }
139        }
140
141        // impl GlUniform for &[$tp] {
142        //     fn send_uniform(&self, location: i32) {
143        //         let count = std::mem::size_of_val(self) /
144        //             std::mem::size_of::<$tp>();
145        //         unsafe {
146        //             gl::$Uniform(location, count as i32, self.as_ptr() as *const $tp);
147        //         }
148        //     }
149        // }
150    };
151    ($tp: ty, $Enum: expr, $Uniform: ident, $Uniformv: ident, $convert: ty) => {
152        impl GlEnum for $tp {
153            fn gl_enum() -> u32 { $Enum }
154            fn to_enum(&self) -> u32 { $Enum }
155        }
156
157        impl GlAttrib for $tp {}
158
159        impl GlUniform for $tp {
160            fn uniform(location: i32, val: &$tp) {
161                unsafe { gl::$Uniform(location, *val as $convert) };
162            }
163            fn uniformv(location: i32, count: i32, ptr: *const Self) {
164                unsafe { gl::$Uniformv(location, count, ptr as *const $convert) };
165            }
166
167            fn send_uniform(&self, location: i32) {
168                unsafe { gl::$Uniform(location, *self as $convert) };
169            }
170        }
171
172        // impl GlUniform for $tp {
173        //     fn send_uniform(&self, location: i32) {
174        //         let p = self as *const Self;
175        //         unsafe { gl::$Uniform(location, 1, p as *const $convert) };
176        //     }
177        // }
178
179        // impl GlUniform for &[$tp] {
180        //     fn send_uniform(&self, location: i32) {
181        //         unsafe {
182        //             gl::$Uniform(location, 1, self.as_ptr() as *const $convert)
183        //         }
184        //     }
185        // }
186    };
187}
188
189// impl<T: GlUniform> GlUniform for &[T] {
190//     fn send_uniform(&self, location: i32) {
191//         for v in *self {
192//             v.send_uniform(location);
193//         }
194//     }
195// }
196
197impl_type!(bool, gl::BOOL, Uniform1i, Uniform1iv, i32);
198impl_type!(i8, gl::BYTE, Uniform1i, Uniform1iv, i32);
199impl_type!(u8, gl::UNSIGNED_BYTE, Uniform1ui, Uniform1uiv, u32);
200impl_type!(i16, gl::SHORT, Uniform1i, Uniform1iv, i32);
201impl_type!(u16, gl::UNSIGNED_SHORT, Uniform1ui, Uniform1uiv, u32);
202impl_type!(i32, gl::INT, Uniform1i, Uniform1iv);
203impl_type!(u32, gl::UNSIGNED_INT, Uniform1ui, Uniform1uiv);
204impl_type!(f32, gl::FLOAT, Uniform1f, Uniform1fv);
205impl_type!(f64, gl::DOUBLE, Uniform1d, Uniform1dv);
206
207#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
208pub enum ClearFlags {
209    #[default]
210    ColorBufferBit,
211    DepthBufferBit,
212    StencilBufferBit
213}
214
215impl GlEnum for ClearFlags {
216    fn to_enum(&self) -> u32 {
217        match self {
218            Self::ColorBufferBit => { gl::COLOR_BUFFER_BIT },
219            Self::DepthBufferBit => { gl::DEPTH_BUFFER_BIT },
220            Self::StencilBufferBit => { gl::STENCIL_BUFFER_BIT },
221        }
222    }
223}
224
225#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
226pub enum EnableFlags {
227    #[default]
228    Blend,
229    CullFace,
230    DepthTest,
231    Dither,
232    Texture2D,
233    ScissorTest,
234}
235
236impl GlEnum for EnableFlags {
237    fn to_enum(&self) -> u32 {
238        match self {
239            Self::Blend => { gl::BLEND },
240            Self::CullFace => { gl::CULL_FACE },
241            Self::DepthTest => { gl::DEPTH_TEST },
242            Self::Dither => { gl::DITHER },
243            Self::Texture2D => { gl::TEXTURE_2D },
244            Self::ScissorTest => { gl::SCISSOR_TEST }
245        }
246    }
247}
248
249
250#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
251pub enum DrawMode {
252    Points,
253    Lines,
254    #[default]
255    Triangles
256}
257
258impl GlEnum for DrawMode {
259    fn to_enum(&self) -> u32 {
260        match self {
261            Self::Points => { gl::POINTS },
262            Self::Lines => { gl::LINES },
263            Self::Triangles => { gl::TRIANGLES }
264        }
265    }
266}
267
268#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
269pub enum BlendFunc {
270    Zero,
271    One,
272    SrcColor,
273    OneMinusSrcColor,
274    DstColor,
275    OneMinusDstColor,
276    SrcAlpha,
277    OneMinusSrcAlpha,
278    DstAlpha,
279    OneMinusDstAlpha,
280    ConstantColor,
281    OneMinusConstantColor,
282    ConstantAlpha,
283    OneMinusConstantAlpha,
284}
285
286impl GlEnum for BlendFunc {
287    fn to_enum(&self) -> u32 {
288        match self {
289            Self::Zero => { gl::ZERO },
290            Self::SrcAlpha => { gl::SRC_ALPHA },
291            Self::OneMinusSrcAlpha => { gl::ONE_MINUS_SRC_ALPHA },
292            _ => { gl::NONE }
293        }
294    }
295}
296
297#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
298pub enum CullMode {
299    #[default]
300    Front,
301    Back,
302    FrontAndBack,
303}
304
305impl GlEnum for CullMode {
306    fn to_enum(&self) -> u32 {
307        match self {
308            Self::Front => { gl::FRONT },
309            Self::Back => { gl::BACK },
310            Self::FrontAndBack => { gl::FRONT_AND_BACK },
311        }
312    }
313}
314
315#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
316pub enum FrontFace {
317    #[default]
318    CCW,
319    CW
320}
321
322impl GlEnum for FrontFace {
323    fn to_enum(&self) -> u32 {
324        match self {
325            Self::CCW => { gl::CCW },
326            Self::CW => { gl::CW },
327        }
328    }
329}
330
331#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
332pub enum GlFunc {
333    Never,
334    Less,
335    Equal,
336    LEqual,
337    Greater,
338    NotEqual,
339    GEqual,
340    Always
341}
342
343impl GlEnum for GlFunc {
344    fn to_enum(&self) -> u32 {
345        match self {
346            Self::Never => { gl::NEVER },
347            Self::Less => { gl::LESS },
348            Self::Equal => { gl::EQUAL },
349            Self::LEqual => { gl::LEQUAL },
350            Self::Greater => { gl::GREATER },
351            Self::NotEqual => { gl::NOTEQUAL },
352            Self::GEqual => { gl::GEQUAL },
353            Self::Always => { gl::ALWAYS },
354        }
355    }
356}
357
358pub fn gl_version() -> String {
359    let version = unsafe { gl::GetString(gl::VERSION) };
360    #[cfg(target_arch="aarch64")]
361    let ptr = unsafe { CStr::from_ptr(version as *const u8) };
362    #[cfg(not(target_arch="aarch64"))]
363    let ptr = unsafe { CStr::from_ptr(version as *const i8) };
364    return ptr.to_str().unwrap().to_string()
365}
366
367pub fn glsl_version() -> String {
368    let version = unsafe { gl::GetString(gl::SHADING_LANGUAGE_VERSION) };
369    #[cfg(target_arch="aarch64")]
370    let ptr = unsafe { CStr::from_ptr(version as *const u8) };
371    #[cfg(not(target_arch="aarch64"))]
372    let ptr = unsafe { CStr::from_ptr(version as *const i8) };
373    return ptr.to_str().unwrap().to_string()
374}
375
376pub fn load_with<F: FnMut(&'static str) -> *const c_void>(loadfn: F) { gl::load_with(loadfn) }
377
378pub fn enable(flags: &[EnableFlags]) {
379    for flag in flags {
380        unsafe { gl::Enable(flag.to_enum()) };
381    }
382}
383
384pub fn disable(flags: &[EnableFlags]) {
385    for flag in flags {
386        unsafe { gl::Disable(flag.to_enum()) };
387    }
388}
389
390// Blend
391pub fn blend_color(color: Vec4) {
392    unsafe { gl::BlendColor(color.x, color.y, color.z, color.w) };
393}
394
395pub fn blend_func(sfactor: BlendFunc, dfactor: BlendFunc) {
396    unsafe { gl::BlendFunc(sfactor.to_enum(), dfactor.to_enum()) };
397}
398
399pub fn blend_func_separate(src_rgb: BlendFunc, dst_rgb: BlendFunc, src_alpha: BlendFunc, dst_alpha: BlendFunc) {
400    unsafe { gl::BlendFuncSeparate(src_rgb.to_enum(), dst_rgb.to_enum(), src_alpha.to_enum(), dst_alpha.to_enum()) };
401}
402
403// Color
404pub fn color_mask(r: bool, g: bool, b: bool, a: bool) {
405    unsafe { gl::ColorMask(r.to_enum() as u8, g.to_enum() as u8, b.to_enum() as u8, a.to_enum() as u8) }
406}
407
408pub fn clear_color(r: f32, g: f32, b: f32, a: f32) {
409    unsafe { gl::ClearColor(r, g, b, a) };
410}
411
412// Culling
413pub fn cull_face(mode: CullMode) {
414    unsafe { gl::CullFace(mode.to_enum()) };
415}
416
417pub fn front_face(mode: FrontFace) {
418    unsafe { gl::FrontFace(mode.to_enum()) };
419}
420
421// Depth
422pub fn depth_func(func: GlFunc) {
423    unsafe { gl::DepthFunc(func.to_enum()) };
424}
425
426pub fn depth_mask(enabled: bool) {
427    unsafe { gl::DepthMask(enabled.to_enum() as u8) };
428}
429
430pub fn clear_depth(d: f64) {
431    unsafe { gl::ClearDepth(d) };
432}
433
434// Stencil
435pub fn stencil_func(func: GlFunc, ref_: i32, mask: u32) {
436    unsafe { gl::StencilFunc(func.to_enum(), ref_, mask) };
437}
438
439pub fn stencil_func_separate(face: CullMode, func: GlFunc, ref_: i32, mask: u32) {
440    unsafe { gl::StencilFuncSeparate(face.to_enum(), func.to_enum(), ref_, mask) };
441}
442
443pub fn clear_stencil(s: i32) {
444    unsafe { gl::ClearStencil(s) };
445}
446
447// States
448pub fn clear(flags: &[ClearFlags]) {
449    let mut mask = 0;
450    for flag in flags {
451        mask = mask | (flag.to_enum());
452    }
453    unsafe { gl::Clear(mask) };
454}
455
456pub fn scissor(x: i32, y: i32, width: i32, height: i32) {
457    unsafe { gl::Scissor(x, y, width, height) };
458}
459
460pub fn viewport(x: i32, y: i32, width: i32, height: i32) {
461    unsafe { gl::Viewport(x, y, width, height) };
462}
463
464pub fn draw_arrays(mode: DrawMode, start: i32, count: i32) {
465    unsafe { gl::DrawArrays(mode.to_enum(), start, count) };
466}
467
468pub fn draw_elements(mode: DrawMode, start: i32, count: i32) {
469    unsafe { gl::DrawElements(mode.to_enum(), count, gl::UNSIGNED_INT, start as *const c_void) };
470}