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