proof_engine/glyph/
mod.rs1pub mod batch;
7pub mod atlas;
8pub mod sdf_generator;
9pub mod sdf_atlas;
10pub mod sdf_batch;
11pub mod font_to_mesh;
12pub mod glyph_mesh;
13pub mod glyph_materials;
14pub mod glyph_3d_dissolve;
15
16use glam::{Vec2, Vec3, Vec4};
17use crate::math::MathFunction;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct GlyphId(pub u32);
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum RenderLayer {
26 Background, World, Entity, Particle, UI, Overlay, }
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum BlendMode {
37 Normal, Additive, Multiply, Screen, }
42
43#[derive(Clone, Debug)]
45pub struct Glyph {
46 pub character: char,
48
49 pub position: Vec3,
51 pub velocity: Vec3,
52 pub acceleration: Vec3,
53 pub rotation: f32, pub scale: Vec2,
55
56 pub color: Vec4, pub emission: f32, pub glow_color: Vec3, pub glow_radius: f32, pub mass: f32, pub charge: f32, pub temperature: f32, pub entropy: f32, pub life_function: Option<MathFunction>, pub age: f32, pub lifetime: f32, pub layer: RenderLayer,
75 pub blend_mode: BlendMode,
76 pub visible: bool,
77}
78
79impl Default for Glyph {
80 fn default() -> Self {
81 Self {
82 character: ' ',
83 position: Vec3::ZERO,
84 velocity: Vec3::ZERO,
85 acceleration: Vec3::ZERO,
86 rotation: 0.0,
87 scale: Vec2::ONE,
88 color: Vec4::ONE,
89 emission: 0.0,
90 glow_color: Vec3::ONE,
91 glow_radius: 0.0,
92 mass: 1.0,
93 charge: 0.0,
94 temperature: 0.5,
95 entropy: 0.0,
96 life_function: None,
97 age: 0.0,
98 lifetime: -1.0,
99 layer: RenderLayer::World,
100 blend_mode: BlendMode::Normal,
101 visible: true,
102 }
103 }
104}
105
106impl Glyph {
107 pub fn is_expired(&self) -> bool {
109 self.lifetime >= 0.0 && self.age >= self.lifetime
110 }
111}
112
113#[allow(dead_code)]
115pub struct GlyphPool {
116 glyphs: Vec<Option<Glyph>>,
117 free_slots: Vec<u32>,
118 next_id: u32,
119}
120
121impl GlyphPool {
122 pub fn new(capacity: usize) -> Self {
123 Self {
124 glyphs: vec![None; capacity],
125 free_slots: (0..capacity as u32).rev().collect(),
126 next_id: 0,
127 }
128 }
129
130 pub fn spawn(&mut self, glyph: Glyph) -> GlyphId {
131 if let Some(slot) = self.free_slots.pop() {
132 self.glyphs[slot as usize] = Some(glyph);
133 GlyphId(slot)
134 } else {
135 let id = self.glyphs.len() as u32;
137 self.glyphs.push(Some(glyph));
138 GlyphId(id)
139 }
140 }
141
142 pub fn remove(&mut self, id: GlyphId) {
143 if let Some(slot) = self.glyphs.get_mut(id.0 as usize) {
144 *slot = None;
145 self.free_slots.push(id.0);
146 }
147 }
148
149 pub fn despawn(&mut self, id: GlyphId) {
151 self.remove(id);
152 }
153
154 pub fn get(&self, id: GlyphId) -> Option<&Glyph> {
155 self.glyphs.get(id.0 as usize)?.as_ref()
156 }
157
158 pub fn get_mut(&mut self, id: GlyphId) -> Option<&mut Glyph> {
159 self.glyphs.get_mut(id.0 as usize)?.as_mut()
160 }
161
162 pub fn iter(&self) -> impl Iterator<Item = (GlyphId, &Glyph)> {
163 self.glyphs.iter().enumerate().filter_map(|(i, g)| {
164 g.as_ref().map(|g| (GlyphId(i as u32), g))
165 })
166 }
167
168 pub fn iter_mut(&mut self) -> impl Iterator<Item = (GlyphId, &mut Glyph)> {
169 self.glyphs.iter_mut().enumerate().filter_map(|(i, g)| {
170 g.as_mut().map(|g| (GlyphId(i as u32), g))
171 })
172 }
173
174 pub fn tick(&mut self, dt: f32) {
176 for slot in self.glyphs.iter_mut() {
177 if let Some(ref mut g) = slot {
178 g.age += dt;
179 g.position += g.velocity * dt;
181 g.velocity += g.acceleration * dt;
182 }
184 }
185 let mut to_remove = Vec::new();
187 for (i, slot) in self.glyphs.iter().enumerate() {
188 if let Some(ref g) = slot {
189 if g.is_expired() {
190 to_remove.push(i as u32);
191 }
192 }
193 }
194 for id in to_remove {
195 self.glyphs[id as usize] = None;
196 self.free_slots.push(id);
197 }
198 }
199
200 pub fn count(&self) -> usize {
201 self.glyphs.iter().filter(|s| s.is_some()).count()
202 }
203}