pub mod batch;
pub mod atlas;
pub mod sdf_generator;
pub mod sdf_atlas;
pub mod sdf_batch;
use glam::{Vec2, Vec3, Vec4};
use crate::math::MathFunction;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GlyphId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RenderLayer {
Background, World, Entity, Particle, UI, Overlay, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlendMode {
Normal, Additive, Multiply, Screen, }
#[derive(Clone, Debug)]
pub struct Glyph {
pub character: char,
pub position: Vec3,
pub velocity: Vec3,
pub acceleration: Vec3,
pub rotation: f32, pub scale: Vec2,
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,
pub blend_mode: BlendMode,
pub visible: bool,
}
impl Default for Glyph {
fn default() -> Self {
Self {
character: ' ',
position: Vec3::ZERO,
velocity: Vec3::ZERO,
acceleration: Vec3::ZERO,
rotation: 0.0,
scale: Vec2::ONE,
color: Vec4::ONE,
emission: 0.0,
glow_color: Vec3::ONE,
glow_radius: 0.0,
mass: 1.0,
charge: 0.0,
temperature: 0.5,
entropy: 0.0,
life_function: None,
age: 0.0,
lifetime: -1.0,
layer: RenderLayer::World,
blend_mode: BlendMode::Normal,
visible: true,
}
}
}
impl Glyph {
pub fn is_expired(&self) -> bool {
self.lifetime >= 0.0 && self.age >= self.lifetime
}
}
#[allow(dead_code)]
pub struct GlyphPool {
glyphs: Vec<Option<Glyph>>,
free_slots: Vec<u32>,
next_id: u32,
}
impl GlyphPool {
pub fn new(capacity: usize) -> Self {
Self {
glyphs: vec![None; capacity],
free_slots: (0..capacity as u32).rev().collect(),
next_id: 0,
}
}
pub fn spawn(&mut self, glyph: Glyph) -> GlyphId {
if let Some(slot) = self.free_slots.pop() {
self.glyphs[slot as usize] = Some(glyph);
GlyphId(slot)
} else {
let id = self.glyphs.len() as u32;
self.glyphs.push(Some(glyph));
GlyphId(id)
}
}
pub fn remove(&mut self, id: GlyphId) {
if let Some(slot) = self.glyphs.get_mut(id.0 as usize) {
*slot = None;
self.free_slots.push(id.0);
}
}
pub fn despawn(&mut self, id: GlyphId) {
self.remove(id);
}
pub fn get(&self, id: GlyphId) -> Option<&Glyph> {
self.glyphs.get(id.0 as usize)?.as_ref()
}
pub fn get_mut(&mut self, id: GlyphId) -> Option<&mut Glyph> {
self.glyphs.get_mut(id.0 as usize)?.as_mut()
}
pub fn iter(&self) -> impl Iterator<Item = (GlyphId, &Glyph)> {
self.glyphs.iter().enumerate().filter_map(|(i, g)| {
g.as_ref().map(|g| (GlyphId(i as u32), g))
})
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (GlyphId, &mut Glyph)> {
self.glyphs.iter_mut().enumerate().filter_map(|(i, g)| {
g.as_mut().map(|g| (GlyphId(i as u32), g))
})
}
pub fn tick(&mut self, dt: f32) {
for slot in self.glyphs.iter_mut() {
if let Some(ref mut g) = slot {
g.age += dt;
g.position += g.velocity * dt;
g.velocity += g.acceleration * dt;
}
}
let mut to_remove = Vec::new();
for (i, slot) in self.glyphs.iter().enumerate() {
if let Some(ref g) = slot {
if g.is_expired() {
to_remove.push(i as u32);
}
}
}
for id in to_remove {
self.glyphs[id as usize] = None;
self.free_slots.push(id);
}
}
pub fn count(&self) -> usize {
self.glyphs.iter().filter(|s| s.is_some()).count()
}
}