cgl_rs/graphics/
mesh.rs

1//! The Mesh (CPU & GPU) module for CGL
2
3#![allow(non_camel_case_types)]
4use libc::{c_void, c_int, size_t, c_char, c_float};
5
6use crate::math::{IVector4, Vector4, Vector3, Matrix4x4};
7
8/// The internal handle used by CGL
9#[repr(C)]
10pub(crate) struct CGL_mesh_gpu {
11    _private: c_void
12}
13
14/// The Mesh Vertex Structure
15#[repr(C)] #[derive(Copy, Clone)]
16pub struct MeshVertex {
17    pub position: Vector4,
18    pub normal: Vector4,
19    pub texture_coordinates: Vector4,
20    pub bone_weights: Vector4,
21    pub bone_ids: IVector4
22}
23
24/// The Mesh Structure
25#[repr(C)] #[derive(Debug)]
26pub struct MeshCPU_C {
27    pub(crate) index_count: usize,
28    pub(crate) index_count_used: usize,
29    pub(crate) indices: *mut u32,
30    pub(crate) vertex_count: usize,
31    pub(crate) vertex_count_used: usize,
32    pub(crate) vertices: *mut MeshVertex
33}
34
35pub struct MeshCPU {
36    pub(crate) handle: *mut MeshCPU_C,
37    pub(crate) has_been_destroyed: bool
38}
39
40pub struct MeshGPU {
41    pub(crate) handle: *mut CGL_mesh_gpu,
42    pub(crate) has_been_destroyed: bool
43}
44
45
46extern {
47    fn CGL_mesh_cpu_create(vertex_count: size_t, index_count: size_t) -> *mut MeshCPU_C;
48    fn CGL_mesh_cpu_recalculate_normals(mesh: *mut MeshCPU_C) -> *mut MeshCPU_C;
49    fn CGL_mesh_cpu_load_obj(path: *const c_char) -> *mut MeshCPU_C;
50    fn CGL_mesh_cpu_triangle(a: Vector3, b: Vector3, c: Vector3) -> *mut MeshCPU_C;
51    fn CGL_mesh_cpu_plane(front: Vector3, right: Vector3, resolution: c_int, scale: c_float) -> *mut MeshCPU_C;
52    fn CGL_mesh_cpu_quad(a: Vector3, b: Vector3, c: Vector3, d: Vector3) -> *mut MeshCPU_C;
53    fn CGL_mesh_cpu_cube(use_3d_tex_coords: c_int) -> *mut MeshCPU_C;
54    fn CGL_mesh_cpu_sphere(res_u: c_int, res_v: c_int) -> *mut MeshCPU_C;
55    fn CGL_mesh_cpu_create_cylinder(start: Vector3, end: Vector3, radius0: c_float, radius1: c_float, resolution: c_int) -> *mut MeshCPU_C;
56    fn CGL_mesh_cpu_add_mesh(mesh: *mut MeshCPU_C, mesh_other: *mut MeshCPU_C) -> *mut MeshCPU_C;
57    fn CGL_mesh_cpu_add_cube(mesh: *mut MeshCPU_C, use_3d_tex_coords: c_int) -> *mut MeshCPU_C;
58    fn CGL_mesh_cpu_add_triangle(mesh: *mut MeshCPU_C, a: Vector3, b: Vector3, c: Vector3) -> *mut MeshCPU_C;
59    fn CGL_mesh_cpu_add_quad(mesh: *mut MeshCPU_C, a: Vector3, b: Vector3, c: Vector3, d: Vector3) -> *mut MeshCPU_C;
60    fn CGL_mesh_cpu_add_sphere(mesh: *mut MeshCPU_C, res_u: c_int, res_v: c_int) -> *mut MeshCPU_C;
61    fn CGL_mesh_cpu_add_cylinder(mesh: *mut MeshCPU_C, start: Vector3, end: Vector3, radius0: f32, radius1: f32, resolution: c_int) -> *mut MeshCPU_C;
62    fn CGL_mesh_cpu_offset_vertices(mesh: *mut MeshCPU_C, offset: Vector3) -> *mut MeshCPU_C;
63    fn CGL_mesh_cpu_scale_vertices(mesh: *mut MeshCPU_C, scale: c_float) -> *mut MeshCPU_C;
64    // fn CGL_mesh_cpu_rotate_vertices(mesh: *mut MeshCPU_C, CGL_quat rotation) -> *mut MeshCPU_C; // for future
65    fn CGL_mesh_cpu_transform_vertices(mesh: *mut MeshCPU_C, transform: &Matrix4x4) -> *mut MeshCPU_C;
66    fn CGL_mesh_cpu_destroy(mesh: *mut MeshCPU_C) -> c_void;
67
68    fn CGL_mesh_gpu_create() -> *mut CGL_mesh_gpu; // create mesh (gpu)
69    fn CGL_mesh_gpu_destroy(mesh: *mut CGL_mesh_gpu); // destroy mesh (gpu)
70    fn CGL_mesh_gpu_render(mesh: *mut CGL_mesh_gpu); // render mesh (gpu)
71    fn CGL_mesh_gpu_render_instanced(mesh: *mut CGL_mesh_gpu, count: u32); // render mesh instanced (gpu)
72    fn CGL_mesh_gpu_set_user_data(mesh: *mut CGL_mesh_gpu, user_data: *mut std::os::raw::c_void); // set mesh user data
73    fn CGL_mesh_gpu_get_user_data(mesh: *mut CGL_mesh_gpu) -> *mut std::os::raw::c_void; // get mesh user data
74    fn CGL_mesh_gpu_upload(mesh: *mut CGL_mesh_gpu, mesh_cpu: *mut MeshCPU_C, static_draw: c_int); // upload mesh from (cpu) to (gpu)
75}
76
77impl MeshVertex {
78    /// Creates a new `MeshVertex` object with default values.
79    /// 
80    /// # Examples
81    /// 
82    /// ```
83    /// let vertex = cgl_rs::graphics::MeshVertex::new();
84    /// ```
85    pub fn new() -> MeshVertex {
86        MeshVertex {
87            position: Vector4::new(0.0, 0.0, 0.0, 0.0),
88            normal: Vector4::new(0.0, 0.0, 0.0, 0.0),
89            texture_coordinates: Vector4::new(0.0, 0.0, 0.0, 0.0),
90            bone_weights: Vector4::new(0.0, 0.0, 0.0, 0.0),
91            bone_ids: IVector4::new(0, 0, 0, 0)
92        }
93    }
94}
95
96impl MeshCPU {
97
98    fn from_handle(handle: *mut MeshCPU_C) -> Result<MeshCPU, &'static str> {
99        if handle.is_null() {
100            Err("Failed to create MeshCPU_C")
101        } else {
102            Ok(MeshCPU {
103                handle: handle,
104                has_been_destroyed: false
105            })
106        }
107    }
108
109    /// Create a new MeshCPU object with the given vertex and index count
110    /// 
111    /// # Arguments
112    /// 
113    /// * `vertex_count` - The number of vertices in the mesh
114    /// * `index_count` - The number of indices in the mesh
115    /// 
116    /// # Returns
117    /// 
118    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
119    /// 
120    /// # Example
121    /// 
122    /// ```
123    /// cgl_rs::init();
124    /// {
125    ///     let mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
126    /// }
127    /// cgl_rs::shutdown();
128    /// ```
129    pub fn new(vertex_count: usize, index_count: usize) -> Result<MeshCPU, &'static str> {
130        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_create(vertex_count, index_count) })
131    }
132
133    /// Loads a mesh from an OBJ file
134    /// 
135    /// # Arguments
136    /// 
137    /// * `path` - The path to the OBJ file
138    /// 
139    /// # Returns
140    /// 
141    /// * `Result<MeshCPU, &'static str>` - The loaded MeshCPU object, or an error message
142    /// 
143    /// # Example
144    /// 
145    /// ```no_run
146    /// cgl_rs::init();
147    /// {
148    ///     let mesh = cgl_rs::graphics::MeshCPU::load_obj("path/to/mesh.obj").unwrap();
149    /// }
150    /// cgl_rs::shutdown();
151    /// ```
152    pub fn load_obj(path: &str) -> Result<MeshCPU, &'static str> {
153        let c_path = std::ffi::CString::new(path).unwrap();
154        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_load_obj(c_path.as_ptr()) })
155    }
156
157    /// Creates a new MeshCPU object with a single triangle
158    /// 
159    /// # Arguments
160    /// 
161    /// * `a` - The first vertex of the triangle
162    /// * `b` - The second vertex of the triangle
163    /// * `c` - The third vertex of the triangle
164    /// 
165    /// # Returns
166    /// 
167    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
168    /// 
169    /// # Example
170    /// 
171    /// ```
172    /// use cgl_rs::math::*;
173    /// cgl_rs::init();
174    /// {
175    ///     let mesh = cgl_rs::graphics::MeshCPU::triangle(
176    ///         Vector3::new(0.0, 0.0, 0.0),
177    ///         Vector3::new(1.0, 0.0, 0.0),
178    ///         Vector3::new(0.0, 1.0, 0.0)
179    ///     ).unwrap();
180    /// }
181    /// cgl_rs::shutdown();
182    /// ```
183    pub fn triangle(a: Vector3, b: Vector3, c: Vector3) -> Result<MeshCPU, &'static str> {
184        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_triangle(a, b, c) })
185    }
186
187    /// Creates a new MeshCPU object representing a plane with the given front and right vectors, resolution, and scale.
188    ///
189    /// # Arguments
190    ///
191    /// * `front` - The front vector of the plane
192    /// * `right` - The right vector of the plane
193    /// * `resolution` - The number of subdivisions along each axis of the plane
194    /// * `scale` - The scale of the plane
195    ///
196    /// # Returns
197    ///
198    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
199    ///
200    /// # Example
201    ///
202    /// ```
203    /// use cgl_rs::math::*;
204    /// cgl_rs::init();
205    /// {
206    ///    let mesh = cgl_rs::graphics::MeshCPU::plane(
207    ///       Vector3::new(0.0, 0.0, 1.0),
208    ///       Vector3::new(1.0, 0.0, 0.0),
209    ///       10,
210    ///       1.0
211    ///    ).unwrap();
212    /// }
213    /// cgl_rs::shutdown();
214    /// ```
215    pub fn plane(front: Vector3, right: Vector3, resolution: i32, scale: f32) -> Result<MeshCPU, &'static str> {
216        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_plane(front, right, resolution, scale) })
217    }
218
219    /// Creates a new MeshCPU object representing a quad with the given vertices.
220    ///
221    /// # Arguments
222    ///
223    /// * `a` - The first vertex of the quad
224    /// * `b` - The second vertex of the quad
225    /// * `c` - The third vertex of the quad
226    /// * `d` - The fourth vertex of the quad
227    ///
228    /// # Returns
229    ///
230    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
231    ///
232    /// # Example
233    ///
234    /// ```
235    /// use cgl_rs::math::*;
236    /// cgl_rs::init();
237    /// {
238    ///    let mesh = cgl_rs::graphics::MeshCPU::quad(
239    ///       Vector3::new(-1.0, -1.0, 0.0),
240    ///       Vector3::new(1.0, -1.0, 0.0),
241    ///       Vector3::new(1.0, 1.0, 0.0),
242    ///       Vector3::new(-1.0, 1.0, 0.0)
243    ///    ).unwrap();
244    /// }
245    /// cgl_rs::shutdown();
246    /// ```
247    pub fn quad(a: Vector3, b: Vector3, c: Vector3, d: Vector3) -> Result<MeshCPU, &'static str> {
248        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_quad(a, b, c, d) })
249    }
250
251    /// Creates a new MeshCPU object representing a cube.
252    ///
253    /// # Arguments
254    ///
255    /// * `use_3d_tex_coords` - Whether to use 3D texture coordinates
256    ///
257    /// # Returns
258    ///
259    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
260    ///
261    /// # Example
262    ///
263    /// ```
264    /// cgl_rs::init();
265    /// {
266    ///    let mesh = cgl_rs::graphics::MeshCPU::cube(true).unwrap();
267    /// }
268    /// cgl_rs::shutdown();
269    /// ```
270    pub fn cube(use_3d_tex_coords: bool) -> Result<MeshCPU, &'static str> {
271        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_cube(use_3d_tex_coords as i32) })
272    }
273
274    /// Creates a new MeshCPU object representing a sphere.
275    ///
276    /// # Arguments
277    ///
278    /// * `res_u` - The number of subdivisions along the u-axis of the sphere
279    /// * `res_v` - The number of subdivisions along the v-axis of the sphere
280    ///
281    /// # Returns
282    ///
283    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
284    ///
285    /// # Example
286    ///
287    /// ```
288    /// cgl_rs::init();
289    /// {
290    ///    let mesh = cgl_rs::graphics::MeshCPU::sphere(10, 10).unwrap();
291    /// }
292    /// cgl_rs::shutdown();
293    /// ```
294    pub fn sphere(res_u: i32, res_v: i32) -> Result<MeshCPU, &'static str> {
295        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_sphere(res_u, res_v) })
296    }
297
298    /// Creates a new MeshCPU object representing a cylinder.
299    ///
300    /// # Arguments
301    ///
302    /// * `start` - The start position of the cylinder
303    /// * `end` - The end position of the cylinder
304    /// * `radius0` - The radius of the cylinder at the start position
305    /// * `radius1` - The radius of the cylinder at the end position
306    /// * `resolution` - The number of subdivisions around the cylinder
307    ///
308    /// # Returns
309    ///
310    /// * `Result<MeshCPU, &'static str>` - The new MeshCPU object, or an error message
311    ///
312    /// # Example
313    ///
314    /// ```
315    /// use cgl_rs::math::*;
316    /// cgl_rs::init();
317    /// {
318    ///    let mesh = cgl_rs::graphics::MeshCPU::cylinder(
319    ///       Vector3::new(0.0, 0.0, 0.0),
320    ///       Vector3::new(0.0, 1.0, 0.0),
321    ///       1.0,
322    ///       1.0,
323    ///       10
324    ///    ).unwrap();
325    /// }
326    /// cgl_rs::shutdown();
327    /// ```
328    pub fn cylinder(start: Vector3, end: Vector3, radius0: f32, radius1: f32, resolution: i32) -> Result<MeshCPU, &'static str> {
329        MeshCPU::from_handle(unsafe { CGL_mesh_cpu_create_cylinder(start, end, radius0, radius1, resolution) })
330    }
331
332    /// Adds the vertices and indices of another MeshCPU object to this MeshCPU object.
333    ///
334    /// # Arguments
335    ///
336    /// * `other` - The MeshCPU object to add to this MeshCPU object
337    ///
338    /// # Example
339    ///
340    /// ```
341    /// cgl_rs::init();
342    /// {
343    ///    let mesh1 = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
344    ///    let mesh2 = cgl_rs::graphics::MeshCPU::sphere(3, 3).unwrap();
345    ///    mesh1.add_mesh(&mesh2);
346    /// }
347    /// cgl_rs::shutdown();
348    /// ```
349    pub fn add_mesh(&self, other: &MeshCPU) {
350        unsafe {
351            CGL_mesh_cpu_add_mesh(self.handle, other.handle);
352        }
353    }
354
355    /// Adds the vertices and indices of a cube to this MeshCPU object.
356    ///
357    /// # Arguments
358    ///
359    /// * `use_3d_tex_coords` - Whether or not to use 3D texture coordinates
360    ///
361    /// # Example
362    ///
363    /// ```
364    /// cgl_rs::init();
365    /// {
366    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
367    ///    mesh.add_cube(true);
368    /// }
369    /// cgl_rs::shutdown();
370    /// ```
371    pub fn add_cube(&self, use_3d_tex_coords: bool) {
372        unsafe {
373            CGL_mesh_cpu_add_cube(self.handle, use_3d_tex_coords as i32);
374        }
375    }
376
377    /// Adds the vertices and indices of a sphere to this MeshCPU object.
378    ///
379    /// # Arguments
380    ///
381    /// * `res_u` - The number of subdivisions along the u-axis of the sphere
382    /// * `res_v` - The number of subdivisions along the v-axis of the sphere
383    ///
384    /// # Example
385    ///
386    /// ```
387    /// cgl_rs::init();
388    /// {
389    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
390    ///    mesh.add_sphere(2, 2);
391    /// }
392    /// cgl_rs::shutdown();
393    /// ```
394    pub fn add_sphere(&self, res_u: i32, res_v: i32) {
395        unsafe {
396            CGL_mesh_cpu_add_sphere(self.handle, res_u, res_v);
397        }
398    }
399
400    /// Adds a triangle to this MeshCPU object.
401    ///
402    /// # Arguments
403    ///
404    /// * `a` - The first vertex of the triangle
405    /// * `b` - The second vertex of the triangle
406    /// * `c` - The third vertex of the triangle
407    ///
408    /// # Example
409    ///
410    /// ```
411    /// use cgl_rs::math::*;
412    /// cgl_rs::init();
413    /// {
414    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
415    ///    mesh.add_triangle(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 0.0, 0.0), Vector3::new(0.0, 1.0, 0.0));
416    /// }
417    /// cgl_rs::shutdown();
418    /// ```
419    pub fn add_triangle(&self, a: Vector3, b: Vector3, c: Vector3) {
420        unsafe {
421            CGL_mesh_cpu_add_triangle(self.handle, a, b, c);
422        }
423    }
424
425    /// Adds a quad to this MeshCPU object.
426    ///
427    /// # Arguments
428    ///
429    /// * `a` - The first vertex of the quad
430    /// * `b` - The second vertex of the quad
431    /// * `c` - The third vertex of the quad
432    /// * `d` - The fourth vertex of the quad
433    ///
434    /// # Example
435    ///
436    /// ```
437    /// use cgl_rs::math::*;
438    /// cgl_rs::init();
439    /// {
440    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
441    ///    mesh.add_quad(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0));
442    /// }
443    /// cgl_rs::shutdown();
444    /// ```
445    pub fn add_quad(&self, a: Vector3, b: Vector3, c: Vector3, d: Vector3) {
446        unsafe {
447            CGL_mesh_cpu_add_quad(self.handle, a, b, c, d);
448        }
449    }
450
451    // Adds a cylinder to this MeshCPU object.
452    ///
453    /// # Arguments
454    ///
455    /// * `start` - The starting point of the cylinder
456    /// * `end` - The ending point of the cylinder
457    /// * `radius0` - The radius of the cylinder at the starting point
458    /// * `radius1` - The radius of the cylinder at the ending point
459    /// * `resolution` - The number of subdivisions around the circumference of the cylinder
460    ///
461    /// # Example
462    ///
463    /// ```
464    /// use cgl_rs::math::*;
465    /// cgl_rs::init();
466    /// {
467    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
468    ///    mesh.add_cylinder(Vector3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 1.0, 0.0), 0.5, 0.5, 10);
469    /// }
470    /// cgl_rs::shutdown();
471    /// ```
472    pub fn add_cylinder(&self, start: Vector3, end: Vector3, radius0: f32, radius1: f32, resolution: i32) {
473        unsafe {
474            CGL_mesh_cpu_add_cylinder(self.handle, start, end, radius0, radius1, resolution);
475        }
476    }
477
478    // Offsets the vertices of this MeshCPU object by a given vector.
479    ///
480    /// # Arguments
481    ///
482    /// * `offset` - The vector by which to offset the vertices
483    ///
484    /// # Example
485    ///
486    /// ```
487    /// use cgl_rs::math::*;
488    /// cgl_rs::init();
489    /// {
490    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
491    ///    mesh.offset_vertices(Vector3::new(1.0, 0.0, 0.0));
492    /// }
493    /// cgl_rs::shutdown();
494    /// ```
495    pub fn offset_vertices(&self, offset: Vector3) {
496        unsafe {
497            CGL_mesh_cpu_offset_vertices(self.handle, offset);
498        }
499    }
500
501    // Scales the vertices of this MeshCPU object by a given factor.
502    ///
503    /// # Arguments
504    ///
505    /// * `scale` - The factor by which to scale the vertices
506    ///
507    /// # Example
508    ///
509    /// ```
510    /// cgl_rs::init();
511    /// {
512    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
513    ///    mesh.scale_vertices(2.0);
514    /// }
515    /// cgl_rs::shutdown();
516    /// ```
517    pub fn scale_vertices(&self, scale: f32) {
518        unsafe {
519            CGL_mesh_cpu_scale_vertices(self.handle, scale);
520        }
521    }
522
523    // Transforms the vertices of this MeshCPU object by a given transformation matrix.
524    ///
525    /// # Arguments
526    ///
527    /// * `transform` - The transformation matrix by which to transform the vertices
528    ///
529    /// # Example
530    ///
531    /// ```
532    /// use cgl_rs::math::*;
533    /// cgl_rs::init();
534    /// {
535    ///    let mesh = cgl_rs::graphics::MeshCPU::new(100, 100).unwrap();
536    ///    let transform = Matrix4x4::identity();
537    ///    mesh.transform_vertices(&transform);
538    /// }
539    /// cgl_rs::shutdown();
540    /// ```
541    pub fn transform_vertices(&self, transform: &Matrix4x4) {
542        unsafe {
543            CGL_mesh_cpu_transform_vertices(self.handle, transform);
544        }
545    }
546
547    /// Destroy the MeshCPU object
548    /// 
549    /// # Example
550    /// 
551    /// ```
552    /// cgl_rs::init();
553    /// {
554    ///    let mut mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
555    ///    mesh.destroy(); // or just let the mesh go out of scope
556    /// }
557    /// cgl_rs::shutdown();
558    /// ```
559    pub fn destroy(&mut self) {
560        if !self.has_been_destroyed {
561            unsafe {
562                CGL_mesh_cpu_destroy(self.handle);
563            }
564            self.has_been_destroyed = true;
565        }
566    }
567
568    /// Recalculates the normals of the mesh
569    /// 
570    /// # Example
571    /// 
572    /// ```
573    /// cgl_rs::init();
574    /// {
575    ///     let mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
576    ///     mesh.recalculate_normals();
577    /// }
578    /// cgl_rs::shutdown();
579    /// ```
580    pub fn recalculate_normals(&self) {
581        unsafe {
582            CGL_mesh_cpu_recalculate_normals(self.handle);
583        }
584    }
585
586
587    // Get the vertex at the specified index.
588    ///
589    /// # Arguments
590    ///
591    /// * `index` - The index of the vertex to retrieve
592    ///
593    /// # Example
594    ///
595    /// ```
596    /// cgl_rs::init();
597    /// {
598    ///     let mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
599    ///     let vertex = mesh.get_vertex(0);
600    /// }
601    /// cgl_rs::shutdown();
602    /// ```
603    pub fn get_vertex(&self, index: usize) -> &MeshVertex {
604        unsafe {
605            let vertex_array = self.handle.as_ref().unwrap().vertices;
606            vertex_array.offset(index as isize).as_ref().unwrap()
607        }
608    }
609
610    // Set the vertex at the specified index.
611    ///
612    /// # Arguments
613    ///
614    /// * `index` - The index of the vertex to set
615    /// * `vertex` - The vertex to set
616    ///
617    /// # Example
618    ///
619    /// ```
620    /// cgl_rs::init();
621    /// {
622    ///     let mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
623    ///     let vertex = cgl_rs::graphics::MeshVertex::new();
624    ///     mesh.set_vertex(0, &vertex);
625    /// }
626    /// cgl_rs::shutdown();
627    /// ```
628    pub fn set_vertex(&self, index: usize, vertex: &MeshVertex) {
629        unsafe {
630            let vertex_array = self.handle.as_ref().unwrap().vertices;
631            let vertex_ptr = vertex_array.offset(index as isize);
632            *vertex_ptr = *vertex;
633        }
634    }
635
636    // Get the index at the specified index.
637    ///
638    /// # Arguments
639    ///
640    /// * `index` - The index of the index to retrieve
641    ///
642    /// # Example
643    ///
644    /// ```
645    /// cgl_rs::init();
646    /// {
647    ///     let mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
648    ///     let index = mesh.get_index(0);
649    /// }
650    /// cgl_rs::shutdown();
651    /// ```
652    pub fn get_index(&self, index: usize) -> u32 {
653        unsafe {
654            let index_array = self.handle.as_ref().unwrap().indices;
655            *index_array.offset(index as isize)
656        }
657    }
658
659    // Set the index at the specified index.
660    ///
661    /// # Arguments
662    ///
663    /// * `index` - The index of the index to set
664    /// * `value` - The value to set
665    ///
666    /// # Example
667    ///
668    /// ```
669    /// cgl_rs::init();
670    /// {
671    ///     let mesh = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
672    ///     mesh.set_index(0, 1);
673    /// }
674    /// cgl_rs::shutdown();
675    /// ```
676    pub fn set_index(&self, index: usize, value: u32) {
677        unsafe {
678            let index_array = self.handle.as_ref().unwrap().indices;
679            let index_ptr = index_array.offset(index as isize);
680            *index_ptr = value;
681        }
682    }
683
684
685}
686
687impl Drop for MeshCPU {
688    fn drop(&mut self) {
689        self.destroy();
690    }
691}
692
693impl Clone for MeshCPU {
694    fn clone(&self) -> Self {
695        MeshCPU {
696            handle: self.handle.clone(),
697            has_been_destroyed: true
698        }
699    }
700}
701
702
703impl MeshGPU {
704
705    /// Creates a new MeshGPU instance.
706    ///
707    /// # Returns
708    ///
709    /// Returns a `Result` containing a `MeshGPU` instance if successful, or a `&'static str` error message if unsuccessful.
710    ///
711    /// # Example
712    ///
713    /// ```
714    /// cgl_rs::init();
715    /// let mut window = cgl_rs::window::Window::new("Test Window", 800, 600).unwrap();
716    /// cgl_rs::graphics::init();
717    /// {
718    ///     let mesh = cgl_rs::graphics::MeshGPU::new().unwrap();
719    /// }
720    /// cgl_rs::graphics::shutdown();
721    /// window.destroy();
722    /// cgl_rs::shutdown();
723    /// ```
724    pub fn new() -> Result<MeshGPU, &'static str> {
725        let handle = unsafe {
726            CGL_mesh_gpu_create()
727        };
728        if handle.is_null() {
729            Err("Failed to create MeshGPU")
730        } else {
731            Ok(MeshGPU {
732                handle: handle,
733                has_been_destroyed: false
734            })
735        }
736    }
737
738
739    /// Renders the mesh using the GPU.
740    ///
741    /// # Example
742    ///
743    /// ```
744    /// cgl_rs::init();
745    /// let mut window = cgl_rs::window::Window::new("Test Window", 800, 600).unwrap();
746    /// cgl_rs::graphics::init();
747    /// {
748    ///     let mesh = cgl_rs::graphics::MeshGPU::new().unwrap();
749    ///     mesh.render();
750    /// }
751    /// cgl_rs::graphics::shutdown();
752    /// window.destroy();
753    /// cgl_rs::shutdown();
754    /// ```
755    pub fn render(&self) {
756        unsafe {
757            CGL_mesh_gpu_render(self.handle);
758        }
759    }
760
761    /// Renders the mesh using the GPU with instancing.
762    ///
763    /// * `instance_count` - The number of instances to render.
764    ///
765    /// # Example
766    ///
767    /// ```
768    /// cgl_rs::init();
769    /// let mut window = cgl_rs::window::Window::new("Test Window", 800, 600).unwrap();
770    /// cgl_rs::graphics::init();
771    /// {
772    ///     let mesh = cgl_rs::graphics::MeshGPU::new().unwrap();
773    ///     mesh.render_instanced(10);
774    /// }
775    /// cgl_rs::graphics::shutdown();
776    /// window.destroy();
777    /// cgl_rs::shutdown();
778    /// ```
779    pub fn render_instanced(&self, instance_count: u32) {
780        unsafe {
781            CGL_mesh_gpu_render_instanced(self.handle, instance_count);
782        }
783    }
784
785    /// Uploads the mesh data to the GPU.
786    ///
787    /// * `mesh_cpu` - The mesh data to upload.
788    /// * `static_draw` - Whether the mesh data is static or dynamic.
789    ///
790    /// # Example
791    ///
792    /// ```
793    /// cgl_rs::init();
794    /// let mut window = cgl_rs::window::Window::new("Test Window", 800, 600).unwrap();
795    /// cgl_rs::graphics::init();
796    /// {
797    ///     let mut mesh_cpu = cgl_rs::graphics::MeshCPU::new(3, 3).unwrap();
798    ///     let mut mesh_gpu = cgl_rs::graphics::MeshGPU::new().unwrap();
799    ///     mesh_gpu.upload(&mesh_cpu, true);
800    /// }
801    /// cgl_rs::graphics::shutdown();
802    /// window.destroy();
803    /// cgl_rs::shutdown();
804    /// ```
805    pub fn upload(&mut self, mesh_cpu: &MeshCPU, static_draw: bool) {
806        unsafe {
807            CGL_mesh_gpu_upload(self.handle, mesh_cpu.handle, static_draw as i32);
808        }
809    }
810
811    /// Destroys the mesh GPU handle if it has not already been destroyed.
812    ///
813    /// # Example
814    ///
815    /// ```
816    /// cgl_rs::init();
817    /// let mut window = cgl_rs::window::Window::new("Test Window", 800, 600).unwrap();
818    /// cgl_rs::graphics::init();
819    /// {
820    ///     let mut mesh = cgl_rs::graphics::MeshGPU::new().unwrap();
821    ///     mesh.destroy();
822    /// }
823    /// cgl_rs::graphics::shutdown();
824    /// window.destroy();
825    /// cgl_rs::shutdown();
826    /// ```
827    pub fn destroy(&mut self) {
828        if !self.has_been_destroyed {
829            unsafe {
830                CGL_mesh_gpu_destroy(self.handle);
831            }
832            self.has_been_destroyed = true;
833        }
834    }
835
836}
837
838impl Drop for MeshGPU {
839    fn drop(&mut self) {
840        self.destroy();
841    }
842}
843
844impl Clone for MeshGPU {
845    fn clone(&self) -> Self {
846        MeshGPU {
847            handle: self.handle.clone(),
848            has_been_destroyed: true
849        }
850    }
851}