# for a concrete example."
)]
# for an example implementation."
)]
#[cfg(feature = "bevy")]
use bevy_reflect::prelude::*;
use std::{error::Error, fmt::Debug, marker::PhantomData};
use crate::{
builder::RawFont,
collections::HashMap,
core::{AtlasIndex, Sequence},
tree::{BuildError as LigatureBindingError, LigatureTree, MapLigature},
};
#[cfg(feature = "bevy")]
pub mod bevy_backend;
pub mod prelude {
pub use super::{Backend, BackendBuilder, FontResourceProvider, RasterFont, SpriteSheet};
pub use crate::{
builder::{RawFont, UTokenProps},
core::{AtlasIndex, IGlyphOffset},
tree::{AsLigatureTree, MapLigature},
};
}
#[cfg_attr(
feature = "bevy",
doc = "See the [Bevy backend](crate::backend::bevy_backend) for an example implementation."
)]
#[cfg_attr(
not(feature = "bevy"),
doc = "See the [Bevy backend](https://github.com/cuppachino/pixel_perfect/tree/raster_font-v0.1.0/crates/raster_font/src/bevy_backend) for an example implementation."
)]
pub trait Backend {
type Resources;
}
pub trait BackendBuilder {
type Backend: Backend;
type Error;
type Sheet;
fn build_resources(
self,
raw_font: RawFont<Self::Sheet>,
) -> Result<<Self::Backend as Backend>::Resources, Self::Error>;
}
pub trait SpriteSheet {
type Props;
fn props(&self, index: &AtlasIndex) -> Self::Props;
}
pub trait FontResourceProvider {
type Backend: Backend;
type Error: Error;
type Output<'f, 'r>: SpriteSheet
where
Self: 'r;
fn upgrade_font<'f, 'r>(
&'r self,
res_in: &'f <Self::Backend as Backend>::Resources,
) -> Result<Self::Output<'f, 'r>, Self::Error>;
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "bevy",
derive(Reflect),
reflect(from_reflect = false),
reflect(where B: Clone + std::fmt::Debug, <B as Backend>::Resources: Clone + std::fmt::Debug),
reflect(Clone, Debug),
)]
pub struct RasterFont<B: Backend> {
pub name: Option<String>,
_backend: PhantomData<B>,
pub resources: B::Resources,
#[allow(
dead_code,
reason = "conditional compilation makes this appear unused in some contexts"
)]
pub(crate) height: u32,
#[cfg_attr(feature = "bevy", reflect(ignore))]
pub(crate) tree: LigatureTree<AtlasIndex>,
#[cfg(feature = "font_sequence_map")]
pub(crate) sequence_map: HashMap<Sequence, AtlasIndex>,
}
impl<B: Backend> AsRef<LigatureTree<AtlasIndex>> for RasterFont<B> {
#[inline]
fn as_ref(&self) -> &LigatureTree<AtlasIndex> {
&self.tree
}
}
impl<B: Backend<Resources: SpriteSheet>> MapLigature<AtlasIndex> for RasterFont<B> {
type Output = <B::Resources as SpriteSheet>::Props;
fn map_ligature(&self, index: &AtlasIndex) -> Self::Output {
self.resources.props(index)
}
}
impl<B: Backend> RasterFont<B> {
pub fn new(
name: Option<String>,
height: u32,
resources: B::Resources,
sequence_map: HashMap<Sequence, AtlasIndex>,
) -> Result<Self, LigatureBindingError> {
#[cfg(feature = "font_sequence_map")]
let tree = LigatureTree::try_from_bindings(sequence_map.clone())?;
#[cfg(not(feature = "font_sequence_map"))]
let tree = LigatureTree::try_from_bindings(sequence_map)?;
Ok(Self {
name,
_backend: PhantomData,
height,
resources,
#[cfg(feature = "font_sequence_map")]
sequence_map,
tree,
})
}
#[inline]
pub fn tree(&self) -> &LigatureTree<AtlasIndex> {
&self.tree
}
#[cfg(feature = "font_sequence_map")]
#[inline]
pub fn get(&self, sequence: &Sequence) -> Option<&AtlasIndex> {
self.sequence_map.get(sequence)
}
}
impl<B: Backend> RasterFont<B> {
pub fn upgrade<'f, 'r, Ctx: FontResourceProvider<Backend = B>>(
&'f self,
ctx: &'r Ctx,
) -> Result<RasterFontCtx<'f, 'r, Ctx>, Ctx::Error> {
let resources = ctx.upgrade_font(&self.resources)?;
Ok(RasterFontCtx {
font: self,
resources,
})
}
}
pub struct RasterFontCtx<'f, 'r, Ctx: FontResourceProvider + 'r> {
font: &'f RasterFont<Ctx::Backend>,
resources: Ctx::Output<'f, 'r>,
}
impl<'f, 'r, Ctx: FontResourceProvider> AsRef<LigatureTree<AtlasIndex>>
for RasterFontCtx<'f, 'r, Ctx>
{
#[inline]
fn as_ref(&self) -> &LigatureTree<AtlasIndex> {
&self.font.tree
}
}
impl<'f, 'r, Ctx: FontResourceProvider> MapLigature<AtlasIndex> for RasterFontCtx<'f, 'r, Ctx> {
type Output = <<Ctx as FontResourceProvider>::Output<'f, 'r> as SpriteSheet>::Props;
fn map_ligature(&self, index: &AtlasIndex) -> Self::Output {
self.resources.props(index)
}
}