use bevy::render::render_resource::PrimitiveTopology;
use bevy::{prelude::*, render::mesh::Indices};
use crate::{
font_loader::TextMeshFont, mesh_cache::MeshCache, mesh_data_generator::generate_text_mesh,
};
use crate::{mesh_data_generator::MeshData, text_mesh::TextMesh};
pub(crate) fn text_mesh(
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut fonts: ResMut<Assets<TextMeshFont>>,
mut text_meshes: Query<
(
Entity,
&Transform,
&GlobalTransform,
Option<&Handle<StandardMaterial>>,
&TextMesh,
Option<&Handle<Mesh>>,
&mut TextMeshState,
),
Or<(Changed<TextMesh>, Changed<TextMeshState>)>,
>,
mut cache: ResMut<MeshCache>,
) {
for text_mesh in text_meshes.iter_mut() {
let (entity, transform, global_transform, material, text_mesh, mesh, mut state) = text_mesh;
let font = match fonts.get_mut(&text_mesh.style.font) {
Some(font) => font,
None => {
if !state.warning_shown {
state.warning_trigger_count += 1;
if state.warning_trigger_count > 5 {
warn!("font mesh not found - did you load the font? (`asset_server.load('font.ttf#mesh'))`");
state.warning_shown = true;
}
}
continue;
}
};
let ttf2_mesh = generate_text_mesh(&text_mesh, &mut font.ttf_font, Some(&mut cache));
match mesh {
Some(mesh) => {
let mesh = meshes.get_mut(mesh).unwrap();
apply_mesh(ttf2_mesh, mesh);
}
None => {
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
apply_mesh(ttf2_mesh, &mut mesh);
commands.entity(entity).insert(PbrBundle {
mesh: meshes.add(mesh),
material: material.map(|m| m.clone()).unwrap_or_else(|| {
materials.add(StandardMaterial {
base_color: text_mesh.style.color,
..Default::default()
})
}),
transform: transform.clone(),
global_transform: global_transform.clone(),
..Default::default()
});
}
}
}
}
pub(crate) fn font_loaded(
mut events: EventReader<AssetEvent<TextMeshFont>>,
mut query: Query<(&mut TextMeshState, &TextMesh)>,
) {
for event in events.read() {
match event {
AssetEvent::LoadedWithDependencies { id } => {
for (mut state, text_mesh) in query.iter_mut() {
if id == &text_mesh.style.font.id() {
state.font_loaded = Some(true);
}
}
}
AssetEvent::Removed { id } => {
for (mut state, text_mesh) in query.iter_mut() {
if id == &text_mesh.style.font.id() {
state.font_loaded = Some(false);
}
}
}
_ => (),
}
}
}
#[derive(Debug, Component)]
pub struct TextMeshState {
font_loaded: Option<bool>,
warning_trigger_count: usize,
warning_shown: bool,
}
impl Default for TextMeshState {
fn default() -> Self {
Self {
font_loaded: None,
warning_trigger_count: 0,
warning_shown: false,
}
}
}
fn apply_mesh(mesh_data: MeshData, mesh: &mut Mesh) {
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, mesh_data.vertices);
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_data.normals);
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, mesh_data.uvs);
mesh.set_indices(Some(Indices::U32(mesh_data.indices)));
}