1use std::{ffi::CString, mem::ManuallyDrop};
2
3use static_assertions::{assert_eq_align, assert_eq_size};
4
5use crate::{
6 color::Color,
7 ffi,
8 math::{BoundingBox, Matrix, Transform, Vector2, Vector3, Vector4},
9 shader::Shader,
10 texture::{Image, Texture2D},
11};
12
13pub use crate::ffi::MaterialMapIndex;
14
15#[derive(Debug)]
17#[repr(transparent)]
18pub struct Mesh {
19 pub(crate) raw: ffi::Mesh,
20}
21
22impl Mesh {
23 #[inline]
25 pub fn vertices(&self) -> &[Vector3] {
26 unsafe {
27 std::slice::from_raw_parts(self.raw.vertices as *const _, self.raw.vertexCount as _)
28 }
29 }
30
31 #[inline]
33 pub fn vertices_mut(&mut self) -> &mut [Vector3] {
34 unsafe {
35 std::slice::from_raw_parts_mut(self.raw.vertices as *mut _, self.raw.vertexCount as _)
36 }
37 }
38
39 #[inline]
41 pub fn texcoords(&self) -> &[Vector2] {
42 unsafe {
43 std::slice::from_raw_parts(self.raw.texcoords as *const _, self.raw.vertexCount as _)
44 }
45 }
46
47 #[inline]
49 pub fn texcoords_mut(&mut self) -> &mut [Vector2] {
50 unsafe {
51 std::slice::from_raw_parts_mut(self.raw.texcoords as *mut _, self.raw.vertexCount as _)
52 }
53 }
54
55 #[inline]
57 pub fn texcoords2(&self) -> &[Vector2] {
58 unsafe {
59 std::slice::from_raw_parts(self.raw.texcoords as *const _, self.raw.vertexCount as _)
60 }
61 }
62
63 #[inline]
65 pub fn texcoords2_mut(&mut self) -> &mut [Vector2] {
66 unsafe {
67 std::slice::from_raw_parts_mut(self.raw.texcoords as *mut _, self.raw.vertexCount as _)
68 }
69 }
70
71 #[inline]
73 pub fn normals(&self) -> &[Vector3] {
74 unsafe {
75 std::slice::from_raw_parts(self.raw.normals as *const _, self.raw.vertexCount as _)
76 }
77 }
78
79 #[inline]
81 pub fn normals_mut(&mut self) -> &mut [Vector3] {
82 unsafe {
83 std::slice::from_raw_parts_mut(self.raw.normals as *mut _, self.raw.vertexCount as _)
84 }
85 }
86
87 #[inline]
89 pub fn tangents(&self) -> &[Vector4] {
90 unsafe {
91 std::slice::from_raw_parts(self.raw.tangents as *const _, self.raw.vertexCount as _)
92 }
93 }
94
95 #[inline]
97 pub fn tangents_mut(&mut self) -> &mut [Vector4] {
98 unsafe {
99 std::slice::from_raw_parts_mut(self.raw.tangents as *mut _, self.raw.vertexCount as _)
100 }
101 }
102
103 #[inline]
105 pub fn colors(&self) -> &[Color] {
106 unsafe {
107 std::slice::from_raw_parts(self.raw.colors as *const _, self.raw.vertexCount as _)
108 }
109 }
110
111 #[inline]
113 pub fn colors_mut(&mut self) -> &mut [Color] {
114 unsafe {
115 std::slice::from_raw_parts_mut(self.raw.colors as *mut _, self.raw.vertexCount as _)
116 }
117 }
118
119 #[inline]
121 pub fn indices(&self) -> &[u16] {
122 unsafe {
123 std::slice::from_raw_parts(self.raw.indices as *const _, self.raw.triangleCount as _)
124 }
125 }
126
127 #[inline]
129 pub fn indices_mut(&mut self) -> &mut [u16] {
130 unsafe {
131 std::slice::from_raw_parts_mut(self.raw.indices as *mut _, self.raw.triangleCount as _)
132 }
133 }
134
135 #[inline]
137 pub fn upload(&mut self, dynamic: bool) {
138 unsafe { ffi::UploadMesh(&mut self.raw as *mut _, dynamic) }
139 }
140
141 #[inline]
143 pub fn update_buffer(&self, index: u32, data: &[u8], offset: u32) {
144 unsafe {
145 ffi::UpdateMeshBuffer(
146 self.raw.clone(),
147 index as _,
148 data.as_ptr() as *const _,
149 data.len() as _,
150 offset as _,
151 )
152 }
153 }
154
155 #[inline]
157 pub fn export(&self, file_name: &str) -> bool {
158 let file_name = CString::new(file_name).unwrap();
159
160 unsafe { ffi::ExportMesh(self.raw.clone(), file_name.as_ptr()) }
161 }
162
163 #[inline]
165 pub fn get_bounding_box(&self) -> BoundingBox {
166 unsafe { ffi::GetMeshBoundingBox(self.raw.clone()).into() }
167 }
168
169 #[inline]
171 pub fn generate_tangents(&mut self) {
172 unsafe { ffi::GenMeshTangents(&mut self.raw as *mut _) }
173 }
174
175 #[inline]
177 pub fn generate_polygon(sides: u32, radius: f32) -> Self {
178 Self {
179 raw: unsafe { ffi::GenMeshPoly(sides as _, radius) },
180 }
181 }
182
183 #[inline]
185 pub fn generate_plane(width: f32, length: f32, res_x: u32, res_z: u32) -> Self {
186 Self {
187 raw: unsafe { ffi::GenMeshPlane(width, length, res_x as _, res_z as _) },
188 }
189 }
190
191 #[inline]
193 pub fn generate_cube(width: f32, height: f32, length: f32) -> Self {
194 Self {
195 raw: unsafe { ffi::GenMeshCube(width, height, length) },
196 }
197 }
198
199 #[inline]
201 pub fn generate_sphere(radius: f32, rings: u32, slices: u32) -> Self {
202 Self {
203 raw: unsafe { ffi::GenMeshSphere(radius, rings as _, slices as _) },
204 }
205 }
206
207 #[inline]
209 pub fn generate_hemisphere(radius: f32, rings: u32, slices: u32) -> Self {
210 Self {
211 raw: unsafe { ffi::GenMeshHemiSphere(radius, rings as _, slices as _) },
212 }
213 }
214
215 #[inline]
217 pub fn generate_cylinder(radius: f32, height: f32, slices: u32) -> Self {
218 Self {
219 raw: unsafe { ffi::GenMeshCylinder(radius, height, slices as _) },
220 }
221 }
222
223 #[inline]
225 pub fn generate_cone(radius: f32, height: f32, slices: u32) -> Self {
226 Self {
227 raw: unsafe { ffi::GenMeshCone(radius, height, slices as _) },
228 }
229 }
230
231 #[inline]
233 pub fn generate_torus(radius: f32, size: f32, rad_seg: u32, sides: u32) -> Self {
234 Self {
235 raw: unsafe { ffi::GenMeshTorus(radius, size, rad_seg as _, sides as _) },
236 }
237 }
238
239 #[inline]
241 pub fn generate_knot(radius: f32, size: f32, rad_seg: u32, sides: u32) -> Self {
242 Self {
243 raw: unsafe { ffi::GenMeshKnot(radius, size, rad_seg as _, sides as _) },
244 }
245 }
246
247 #[inline]
249 pub fn generate_heightmap(heightmap: &Image, size: Vector3) -> Self {
250 Self {
251 raw: unsafe { ffi::GenMeshHeightmap(heightmap.raw.clone(), size.into()) },
252 }
253 }
254
255 #[inline]
257 pub fn generate_cubicmap(cubicmap: &Image, cube_size: Vector3) -> Self {
258 Self {
259 raw: unsafe { ffi::GenMeshCubicmap(cubicmap.raw.clone(), cube_size.into()) },
260 }
261 }
262
263 #[inline]
266 pub fn as_raw(&self) -> &ffi::Mesh {
267 &self.raw
268 }
269
270 #[inline]
273 pub fn as_raw_mut(&mut self) -> &mut ffi::Mesh {
274 &mut self.raw
275 }
276
277 #[inline]
283 pub unsafe fn from_raw(raw: ffi::Mesh) -> Self {
284 Self { raw }
285 }
286}
287
288impl Drop for Mesh {
289 #[inline]
290 fn drop(&mut self) {
291 unsafe { ffi::UnloadMesh(self.raw.clone()) }
292 }
293}
294
295#[derive(Debug)]
297#[repr(transparent)]
298pub struct Model {
299 pub(crate) raw: ffi::Model,
300}
301
302impl Model {
303 #[inline]
305 pub fn transform(&self) -> Matrix {
306 self.raw.transform.clone().into()
307 }
308
309 #[inline]
311 pub fn set_transform(&mut self, mat: Matrix) {
312 self.raw.transform = mat.into();
313 }
314
315 #[inline]
319 pub fn meshes(&self) -> &[ManuallyDrop<Mesh>] {
320 unsafe { std::slice::from_raw_parts(self.raw.meshes as *const _, self.raw.meshCount as _) }
321 }
322
323 #[inline]
327 pub fn meshes_mut(&mut self) -> &mut [ManuallyDrop<Mesh>] {
328 unsafe {
329 std::slice::from_raw_parts_mut(self.raw.meshes as *mut _, self.raw.meshCount as _)
330 }
331 }
332
333 #[inline]
337 pub fn materials(&self) -> &[ManuallyDrop<Material>] {
338 unsafe {
339 std::slice::from_raw_parts(self.raw.materials as *const _, self.raw.materialCount as _)
340 }
341 }
342
343 #[inline]
347 pub fn materials_mut(&mut self) -> &mut [ManuallyDrop<Material>] {
348 unsafe {
349 std::slice::from_raw_parts_mut(
350 self.raw.materials as *mut _,
351 self.raw.materialCount as _,
352 )
353 }
354 }
355
356 #[inline]
358 pub fn bones(&self) -> &[ffi::BoneInfo] {
359 unsafe { std::slice::from_raw_parts(self.raw.bones as *const _, self.raw.boneCount as _) }
360 }
361
362 #[inline]
364 pub fn bones_mut(&mut self) -> &mut [ffi::BoneInfo] {
365 unsafe { std::slice::from_raw_parts_mut(self.raw.bones, self.raw.boneCount as _) }
366 }
367
368 #[inline]
370 pub fn bind_pose(&self) -> &[Transform] {
371 unsafe {
372 std::slice::from_raw_parts(self.raw.bindPose as *const _, self.raw.boneCount as _)
373 }
374 }
375
376 #[inline]
378 pub fn bind_pose_mut(&mut self) -> &mut [Transform] {
379 unsafe {
380 std::slice::from_raw_parts_mut(self.raw.bindPose as *mut _, self.raw.boneCount as _)
381 }
382 }
383
384 #[inline]
386 pub fn from_file(file_name: &str) -> Option<Self> {
387 let file_name = CString::new(file_name).unwrap();
388
389 let raw = unsafe { ffi::LoadModel(file_name.as_ptr()) };
390
391 if unsafe { ffi::IsModelReady(raw.clone()) } {
392 Some(Self { raw })
393 } else {
394 None
395 }
396 }
397
398 #[inline]
400 pub fn from_mesh(mesh: Mesh) -> Self {
401 let mesh = ManuallyDrop::new(mesh);
402
403 Self {
404 raw: unsafe { ffi::LoadModelFromMesh(mesh.raw.clone()) },
405 }
406 }
407
408 #[inline]
410 pub fn get_bounding_box(&self) -> BoundingBox {
411 unsafe { ffi::GetModelBoundingBox(self.raw.clone()).into() }
412 }
413
414 #[inline]
416 pub fn set_mesh_material(&mut self, mesh_id: u32, material_id: u32) {
417 unsafe {
418 ffi::SetModelMeshMaterial(&mut self.raw as *mut _, mesh_id as _, material_id as _)
419 }
420 }
421
422 #[inline]
424 pub fn update_animation(&self, anim: &ModelAnimation, frame: u32) {
425 unsafe { ffi::UpdateModelAnimation(self.raw.clone(), anim.raw.clone(), frame as _) }
426 }
427
428 #[inline]
430 pub fn is_animation_valid(&self, anim: &ModelAnimation) -> bool {
431 unsafe { ffi::IsModelAnimationValid(self.raw.clone(), anim.raw.clone()) }
432 }
433
434 #[inline]
437 pub fn as_raw(&self) -> &ffi::Model {
438 &self.raw
439 }
440
441 #[inline]
444 pub fn as_raw_mut(&mut self) -> &mut ffi::Model {
445 &mut self.raw
446 }
447
448 #[inline]
454 pub unsafe fn from_raw(raw: ffi::Model) -> Self {
455 Self { raw }
456 }
457}
458
459impl Drop for Model {
460 #[inline]
461 fn drop(&mut self) {
462 unsafe { ffi::UnloadModel(self.raw.clone()) }
463 }
464}
465
466#[repr(C)]
468#[derive(Debug)]
469pub struct MaterialMap {
470 pub texture: ManuallyDrop<Texture2D>,
472 pub color: Color,
474 pub value: f32,
476}
477
478assert_eq_size!(MaterialMap, ffi::MaterialMap);
479assert_eq_align!(MaterialMap, ffi::MaterialMap);
480
481#[derive(Debug)]
483#[repr(transparent)]
484pub struct Material {
485 pub(crate) raw: ffi::Material,
486}
487
488impl Material {
489 #[inline]
491 pub fn shader(&self) -> &ManuallyDrop<Shader> {
492 unsafe { std::mem::transmute(&self.raw.shader) }
493 }
494
495 #[inline]
497 pub fn shader_mut(&mut self) -> &mut ManuallyDrop<Shader> {
498 unsafe { std::mem::transmute(&mut self.raw.shader) }
499 }
500
501 #[inline]
503 pub fn maps(&self) -> &[MaterialMap] {
504 unsafe { std::slice::from_raw_parts(self.raw.maps as *const _, ffi::MAX_MATERIAL_MAPS) }
505 }
506
507 #[inline]
509 pub fn maps_mut(&mut self) -> &mut [MaterialMap] {
510 unsafe { std::slice::from_raw_parts_mut(self.raw.maps as *mut _, ffi::MAX_MATERIAL_MAPS) }
511 }
512
513 #[inline]
515 pub fn params(&self) -> &[f32; 4] {
516 &self.raw.params
517 }
518
519 #[inline]
521 pub fn params_mut(&mut self) -> &mut [f32; 4] {
522 &mut self.raw.params
523 }
524
525 #[inline]
527 pub fn from_file(file_name: &str) -> Vec<Self> {
528 let file_name = CString::new(file_name).unwrap();
529 let mut count: i32 = 0;
530
531 let mats = unsafe { ffi::LoadMaterials(file_name.as_ptr(), &mut count as *mut _) };
532
533 let mut vec = Vec::new();
534
535 for i in 0..(count as usize) {
536 let mat = unsafe { mats.add(i).read() };
537
538 if unsafe { ffi::IsMaterialReady(mat.clone()) } {
539 vec.push(Self { raw: mat });
540 }
541 }
542
543 vec
544 }
545
546 #[inline]
548 pub fn set_texture(&mut self, map_type: MaterialMapIndex, texture: Texture2D) {
549 let texture = ManuallyDrop::new(texture);
550
551 unsafe {
552 ffi::SetMaterialTexture(&mut self.raw as *mut _, map_type as _, texture.raw.clone());
553 }
554 }
555
556 #[inline]
559 pub fn as_raw(&self) -> &ffi::Material {
560 &self.raw
561 }
562
563 #[inline]
566 pub fn as_raw_mut(&mut self) -> &mut ffi::Material {
567 &mut self.raw
568 }
569
570 #[inline]
576 pub unsafe fn from_raw(raw: ffi::Material) -> Self {
577 Self { raw }
578 }
579}
580
581impl Default for Material {
582 #[inline]
583 fn default() -> Self {
584 Self {
585 raw: unsafe { ffi::LoadMaterialDefault() },
586 }
587 }
588}
589
590impl Drop for Material {
591 #[inline]
592 fn drop(&mut self) {
593 unsafe { ffi::UnloadMaterial(self.raw.clone()) }
594 }
595}
596
597#[derive(Debug)]
599#[repr(transparent)]
600pub struct ModelAnimation {
601 raw: ffi::ModelAnimation,
602}
603
604impl ModelAnimation {
605 #[inline]
607 pub fn bones(&self) -> &[ffi::BoneInfo] {
608 unsafe { std::slice::from_raw_parts(self.raw.bones as *const _, self.raw.boneCount as _) }
609 }
610
611 #[inline]
613 pub fn bones_mut(&mut self) -> &mut [ffi::BoneInfo] {
614 unsafe { std::slice::from_raw_parts_mut(self.raw.bones, self.raw.boneCount as _) }
615 }
616
617 #[inline]
619 pub fn frame_poses(&self) -> Vec<&[Transform]> {
620 let mut vec = Vec::new();
621
622 for i in 0..(self.raw.frameCount as usize) {
623 vec.push(unsafe {
624 std::slice::from_raw_parts(
625 self.raw.framePoses.add(i).read() as *const _,
626 self.raw.boneCount as _,
627 )
628 })
629 }
630
631 vec
632 }
633
634 #[inline]
636 pub fn frame_poses_mut(&mut self) -> Vec<&mut [Transform]> {
637 let mut vec = Vec::new();
638
639 for i in 0..(self.raw.frameCount as usize) {
640 vec.push(unsafe {
641 std::slice::from_raw_parts_mut(
642 self.raw.framePoses.add(i).read() as *mut _,
643 self.raw.boneCount as _,
644 )
645 })
646 }
647
648 vec
649 }
650
651 #[inline]
653 pub fn from_file(file_name: &str) -> Vec<Self> {
654 let file_name = CString::new(file_name).unwrap();
655 let mut count: u32 = 0;
656
657 let anims = unsafe { ffi::LoadModelAnimations(file_name.as_ptr(), &mut count as *mut _) };
658
659 let mut vec = Vec::new();
660
661 for i in 0..(count as usize) {
662 vec.push(ModelAnimation {
663 raw: unsafe { anims.add(i).read() },
664 })
665 }
666
667 unsafe {
668 ffi::UnloadModelAnimations(anims, count);
669 }
670
671 vec
672 }
673
674 #[inline]
677 pub fn as_raw(&self) -> &ffi::ModelAnimation {
678 &self.raw
679 }
680
681 #[inline]
684 pub fn as_raw_mut(&mut self) -> &mut ffi::ModelAnimation {
685 &mut self.raw
686 }
687
688 #[inline]
694 pub unsafe fn from_raw(raw: ffi::ModelAnimation) -> Self {
695 Self { raw }
696 }
697}
698
699impl Drop for ModelAnimation {
700 #[inline]
701 fn drop(&mut self) {
702 unsafe { ffi::UnloadModelAnimation(self.raw.clone()) }
703 }
704}