oxygengine_composite_renderer/system/
mesh.rs1use crate::{
2 component::{CompositeMesh, CompositeRenderable, CompositeSurfaceCache},
3 composite_renderer::{Command, Mask, PathElement, Renderable, Triangles},
4 math::Vec2,
5 mesh_asset_protocol::{Mesh, MeshAsset, MeshVertex},
6};
7use core::{
8 assets::{asset::AssetId, database::AssetsDatabase},
9 ecs::{Comp, Universe, WorldRef},
10};
11use std::collections::HashMap;
12
13#[derive(Debug, Default)]
14pub struct CompositeMeshSystemCache {
15 meshes_cache: HashMap<String, Mesh>,
16 meshes_table: HashMap<AssetId, String>,
17}
18
19pub type CompositeMeshSystemResources<'a> = (
20 WorldRef,
21 &'a AssetsDatabase,
22 &'a mut CompositeMeshSystemCache,
23 Comp<&'a mut CompositeMesh>,
24 Comp<&'a mut CompositeRenderable>,
25 Comp<&'a mut CompositeSurfaceCache>,
26);
27
28pub fn composite_mesh_system(universe: &mut Universe) {
29 let (world, assets, mut cache, ..) = universe.query_resources::<CompositeMeshSystemResources>();
30
31 for id in assets.lately_loaded_protocol("mesh") {
32 let id = *id;
33 let asset = assets
34 .asset_by_id(id)
35 .expect("trying to use not loaded mesh asset");
36 let path = asset.path().to_owned();
37 let asset = asset
38 .get::<MeshAsset>()
39 .expect("trying to use non-mesh asset");
40 let mesh = asset.mesh().clone();
41 cache.meshes_cache.insert(path.clone(), mesh);
42 cache.meshes_table.insert(id, path);
43 }
44 for id in assets.lately_unloaded_protocol("mesh") {
45 if let Some(path) = cache.meshes_table.remove(id) {
46 cache.meshes_cache.remove(&path);
47 }
48 }
49
50 for (_, (mesh, renderable, surface)) in world
51 .query::<(
52 &mut CompositeMesh,
53 &mut CompositeRenderable,
54 Option<&mut CompositeSurfaceCache>,
55 )>()
56 .iter()
57 {
58 if mesh.dirty_mesh || mesh.dirty_visuals {
59 if let Some(r) = build_renderable(mesh, &cache.meshes_cache) {
60 renderable.0 = r;
61 if let Some(surface) = surface {
62 surface.rebuild();
63 }
64 mesh.dirty_mesh = false;
65 mesh.dirty_visuals = false;
66 }
67 }
68 }
69}
70
71fn build_renderable<'a>(
72 mesh: &mut CompositeMesh,
73 meshes: &HashMap<String, Mesh>,
74) -> Option<Renderable<'a>> {
75 if let Some(asset) = meshes.get(mesh.mesh()) {
76 if mesh.dirty_mesh {
77 if let Some(root) = &asset.rig {
78 mesh.setup_bones_from_rig(root);
79 }
80 }
81 if mesh.dirty_visuals {
82 let vertices = if let Some(root) = &asset.rig {
83 mesh.rebuild_model_space(root);
84 build_skined_vertices(&asset.vertices, mesh)
85 } else {
86 build_vertices(&asset.vertices)
87 };
88 let masks = asset
89 .masks
90 .iter()
91 .map(|indices| build_mask(&vertices, &indices.indices))
92 .collect::<Vec<_>>();
93 let mut meta = asset
94 .submeshes
95 .iter()
96 .zip(mesh.materials().iter())
97 .filter_map(|(submesh, material)| {
98 if material.alpha > 0.0 {
99 let triangles = Triangles {
100 image: material.image.to_string().into(),
101 color: Default::default(),
102 vertices: vertices.to_vec(),
103 faces: submesh.cached_faces().to_vec(),
104 };
105 let masks = submesh
106 .masks
107 .iter()
108 .map(|i| masks[*i].to_vec())
109 .collect::<Vec<_>>();
110 Some((triangles, material.alpha, material.order, masks))
111 } else {
112 None
113 }
114 })
115 .collect::<Vec<_>>();
116 meta.sort_by(|a, b| a.2.partial_cmp(&b.2).unwrap());
117 let count = meta.len() * 4 + meta.iter().fold(0, |a, v| a + v.3.len());
118 let mut commands = Vec::with_capacity(count);
119 for (triangles, alpha, _, masks) in meta {
120 commands.push(Command::Store);
121 for mask in masks {
122 let mask = Mask { elements: mask };
123 commands.push(Command::Draw(mask.into()));
124 }
125 commands.push(Command::Alpha(alpha));
126 commands.push(Command::Draw(triangles.into()));
127 commands.push(Command::Restore);
128 }
129 return Some(Renderable::Commands(commands));
130 }
131 }
132 None
133}
134
135fn build_skined_vertices(vertices: &[MeshVertex], mesh: &CompositeMesh) -> Vec<(Vec2, Vec2)> {
136 vertices
137 .iter()
138 .map(|v| {
139 let p = v.bone_info.iter().fold(Vec2::default(), |a, i| {
140 let p = if let Some(m) = mesh.bones_model_space.get(&i.name) {
141 *m * v.position
142 } else {
143 v.position
144 };
145 a + p * i.weight
146 });
147 (p, v.tex_coord)
148 })
149 .collect::<Vec<_>>()
150}
151
152fn build_vertices(vertices: &[MeshVertex]) -> Vec<(Vec2, Vec2)> {
153 vertices
154 .iter()
155 .map(|v| (v.position, v.tex_coord))
156 .collect::<Vec<_>>()
157}
158
159fn build_mask(vertices: &[(Vec2, Vec2)], indices: &[usize]) -> Vec<PathElement> {
160 let mut result = Vec::with_capacity(indices.len());
161 for index in indices {
162 if *index == 0 {
163 result.push(PathElement::MoveTo(vertices[*index].0));
164 } else {
165 result.push(PathElement::LineTo(vertices[*index].0));
166 }
167 }
168 result
169}