oxygengine_composite_renderer/
mesh_asset_protocol.rs1use crate::{component::CompositeTransform, composite_renderer::TriangleFace, math::Vec2};
2use core::{
3 assets::protocol::{AssetLoadResult, AssetProtocol},
4 Ignite, Scalar,
5};
6use serde::{Deserialize, Serialize};
7use std::{collections::HashMap, str::from_utf8};
8
9#[derive(Ignite, Debug, Default, Copy, Clone, Serialize, Deserialize)]
10pub struct MeshFace {
11 pub a: usize,
12 pub b: usize,
13 pub c: usize,
14}
15
16#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
17pub struct MeshVertexBoneInfo {
18 #[serde(default)]
19 pub name: String,
20 #[serde(default)]
21 pub weight: Scalar,
22}
23
24#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
25pub struct MeshVertex {
26 pub position: Vec2,
27 pub tex_coord: Vec2,
28 #[serde(default)]
29 pub bone_info: Vec<MeshVertexBoneInfo>,
30}
31
32impl MeshVertex {
33 pub fn fix_bone_info(&mut self) {
34 let total_weight = self.bone_info.iter().map(|i| i.weight).sum::<Scalar>();
35 if total_weight > 0.0 {
36 for info in &mut self.bone_info {
37 info.weight /= total_weight;
38 }
39 }
40 }
41}
42
43#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
44pub struct MeshBone {
45 pub transform: CompositeTransform,
46 #[serde(default)]
47 pub children: HashMap<String, MeshBone>,
48}
49
50impl MeshBone {
51 pub fn bones_count(&self) -> usize {
52 self.children
53 .values()
54 .map(|child| child.bones_count())
55 .sum::<usize>()
56 + 1
57 }
58}
59
60#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
61pub struct SubMesh {
62 pub faces: Vec<MeshFace>,
63 #[serde(default)]
64 pub masks: Vec<usize>,
65 #[serde(skip)]
66 #[ignite(ignore)]
67 cached_faces: Vec<TriangleFace>,
68}
69
70impl SubMesh {
71 pub fn cached_faces(&self) -> &[TriangleFace] {
72 &self.cached_faces
73 }
74
75 pub fn cache(&mut self) {
76 self.cached_faces = self
77 .faces
78 .iter()
79 .map(|f| TriangleFace::new(f.a, f.b, f.c))
80 .collect::<Vec<_>>()
81 }
82}
83
84#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
85pub struct MeshMask {
86 pub indices: Vec<usize>,
87 #[serde(default = "MeshMask::default_enabled")]
88 pub enabled: bool,
89}
90
91impl MeshMask {
92 fn default_enabled() -> bool {
93 true
94 }
95}
96
97#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
98pub struct Mesh {
99 pub vertices: Vec<MeshVertex>,
100 pub submeshes: Vec<SubMesh>,
101 #[serde(default)]
102 pub masks: Vec<MeshMask>,
103 #[serde(default)]
104 pub rig: Option<MeshBone>,
105}
106
107impl Mesh {
108 pub fn initialize(&mut self) {
109 for vertex in &mut self.vertices {
110 vertex.fix_bone_info();
111 }
112 for submesh in &mut self.submeshes {
113 submesh.cache();
114 }
115 }
116}
117
118pub struct MeshAsset(Mesh);
119
120impl MeshAsset {
121 pub fn mesh(&self) -> &Mesh {
122 &self.0
123 }
124}
125
126pub struct MeshAssetProtocol;
127
128impl AssetProtocol for MeshAssetProtocol {
129 fn name(&self) -> &str {
130 "mesh"
131 }
132
133 fn on_load_with_path(&mut self, path: &str, data: Vec<u8>) -> AssetLoadResult {
134 let mut mesh = if path.ends_with(".json") {
135 let data = from_utf8(&data).unwrap();
136 serde_json::from_str::<Mesh>(data).unwrap()
137 } else if path.ends_with(".yaml") {
138 let data = from_utf8(&data).unwrap();
139 serde_yaml::from_str::<Mesh>(data).unwrap()
140 } else {
141 bincode::deserialize::<Mesh>(&data).unwrap()
142 };
143 mesh.initialize();
144 AssetLoadResult::Data(Box::new(MeshAsset(mesh)))
145 }
146
147 fn on_load(&mut self, _data: Vec<u8>) -> AssetLoadResult {
149 unreachable!()
150 }
151}