2020-11-13 00:21:48 +00:00
|
|
|
use std::hash::Hash;
|
|
|
|
|
|
|
|
use ab_glyph::{PxScale, ScaleFont};
|
|
|
|
use bevy_asset::{Assets, Handle, HandleId};
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
use bevy_ecs::system::Resource;
|
2022-04-25 13:54:46 +00:00
|
|
|
use bevy_math::Vec2;
|
2021-12-14 03:58:23 +00:00
|
|
|
use bevy_render::texture::Image;
|
2020-11-13 00:21:48 +00:00
|
|
|
use bevy_sprite::TextureAtlas;
|
|
|
|
use bevy_utils::HashMap;
|
|
|
|
|
|
|
|
use glyph_brush_layout::{FontId, SectionText};
|
|
|
|
|
|
|
|
use crate::{
|
2021-01-25 01:07:43 +00:00
|
|
|
error::TextError, glyph_brush::GlyphBrush, scale_value, Font, FontAtlasSet, PositionedGlyph,
|
|
|
|
TextAlignment, TextSection,
|
2020-11-13 00:21:48 +00:00
|
|
|
};
|
|
|
|
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource)]
|
2020-11-13 00:21:48 +00:00
|
|
|
pub struct TextPipeline<ID> {
|
|
|
|
brush: GlyphBrush,
|
|
|
|
glyph_map: HashMap<ID, TextLayoutInfo>,
|
|
|
|
map_font_id: HashMap<HandleId, FontId>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<ID> Default for TextPipeline<ID> {
|
|
|
|
fn default() -> Self {
|
|
|
|
TextPipeline {
|
|
|
|
brush: GlyphBrush::default(),
|
|
|
|
glyph_map: Default::default(),
|
|
|
|
map_font_id: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct TextLayoutInfo {
|
|
|
|
pub glyphs: Vec<PositionedGlyph>,
|
2022-04-25 13:54:46 +00:00
|
|
|
pub size: Vec2,
|
2020-11-13 00:21:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<ID: Hash + Eq> TextPipeline<ID> {
|
2021-01-25 01:07:43 +00:00
|
|
|
pub fn get_or_insert_font_id(&mut self, handle: &Handle<Font>, font: &Font) -> FontId {
|
2020-11-13 00:21:48 +00:00
|
|
|
let brush = &mut self.brush;
|
|
|
|
*self
|
|
|
|
.map_font_id
|
|
|
|
.entry(handle.id)
|
|
|
|
.or_insert_with(|| brush.add_font(handle.clone(), font.font.clone()))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_glyphs(&self, id: &ID) -> Option<&TextLayoutInfo> {
|
|
|
|
self.glyph_map.get(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
pub fn queue_text(
|
|
|
|
&mut self,
|
|
|
|
id: ID,
|
|
|
|
fonts: &Assets<Font>,
|
2021-01-25 01:07:43 +00:00
|
|
|
sections: &[TextSection],
|
|
|
|
scale_factor: f64,
|
2020-11-13 00:21:48 +00:00
|
|
|
text_alignment: TextAlignment,
|
2022-04-25 13:54:46 +00:00
|
|
|
bounds: Vec2,
|
2020-11-13 00:21:48 +00:00
|
|
|
font_atlas_set_storage: &mut Assets<FontAtlasSet>,
|
|
|
|
texture_atlases: &mut Assets<TextureAtlas>,
|
2021-12-14 03:58:23 +00:00
|
|
|
textures: &mut Assets<Image>,
|
2020-11-13 00:21:48 +00:00
|
|
|
) -> Result<(), TextError> {
|
2021-01-25 01:07:43 +00:00
|
|
|
let mut scaled_fonts = Vec::new();
|
|
|
|
let sections = sections
|
|
|
|
.iter()
|
|
|
|
.map(|section| {
|
|
|
|
let font = fonts
|
Enforce type safe usage of Handle::get (#4794)
# Objective
- Sometimes, people might load an asset as one type, then use it with an `Asset`s for a different type.
- See e.g. #4784.
- This is especially likely with the Gltf types, since users may not have a clear conceptual model of what types the assets will be.
- We had an instance of this ourselves, in the `scene_viewer` example
## Solution
- Make `Assets::get` require a type safe handle.
---
## Changelog
### Changed
- `Assets::<T>::get` and `Assets::<T>::get_mut` now require that the passed handles are `Handle<T>`, improving the type safety of handles.
### Added
- `HandleUntyped::typed_weak`, a helper function for creating a weak typed version of an exisitng `HandleUntyped`.
## Migration Guide
`Assets::<T>::get` and `Assets::<T>::get_mut` now require that the passed handles are `Handle<T>`, improving the type safety of handles. If you were previously passing in:
- a `HandleId`, use `&Handle::weak(id)` instead, to create a weak handle. You may have been able to store a type safe `Handle` instead.
- a `HandleUntyped`, use `&handle_untyped.typed_weak()` to create a weak handle of the specified type. This is most likely to be the useful when using [load_folder](https://docs.rs/bevy_asset/latest/bevy_asset/struct.AssetServer.html#method.load_folder)
- a `Handle<U>` of of a different type, consider whether this is the correct handle type to store. If it is (i.e. the same handle id is used for multiple different Asset types) use `Handle::weak(handle.id)` to cast to a different type.
2022-05-30 16:59:44 +00:00
|
|
|
.get(§ion.style.font)
|
2021-01-25 01:07:43 +00:00
|
|
|
.ok_or(TextError::NoSuchFont)?;
|
|
|
|
let font_id = self.get_or_insert_font_id(§ion.style.font, font);
|
|
|
|
let font_size = scale_value(section.style.font_size, scale_factor);
|
|
|
|
|
|
|
|
scaled_fonts.push(ab_glyph::Font::as_scaled(&font.font, font_size));
|
|
|
|
|
|
|
|
let section = SectionText {
|
|
|
|
font_id,
|
|
|
|
scale: PxScale::from(font_size),
|
|
|
|
text: §ion.value,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(section)
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-11-13 00:21:48 +00:00
|
|
|
|
|
|
|
let section_glyphs = self
|
|
|
|
.brush
|
2021-01-25 01:07:43 +00:00
|
|
|
.compute_glyphs(§ions, bounds, text_alignment)?;
|
2020-11-13 00:21:48 +00:00
|
|
|
|
|
|
|
if section_glyphs.is_empty() {
|
|
|
|
self.glyph_map.insert(
|
|
|
|
id,
|
|
|
|
TextLayoutInfo {
|
|
|
|
glyphs: Vec::new(),
|
2022-07-03 19:55:33 +00:00
|
|
|
size: Vec2::ZERO,
|
2020-11-13 00:21:48 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut min_x: f32 = std::f32::MAX;
|
|
|
|
let mut min_y: f32 = std::f32::MAX;
|
|
|
|
let mut max_x: f32 = std::f32::MIN;
|
|
|
|
let mut max_y: f32 = std::f32::MIN;
|
|
|
|
|
2022-02-13 22:33:55 +00:00
|
|
|
for sg in §ion_glyphs {
|
2021-01-25 01:07:43 +00:00
|
|
|
let scaled_font = scaled_fonts[sg.section_index];
|
|
|
|
let glyph = &sg.glyph;
|
2020-11-13 00:21:48 +00:00
|
|
|
min_x = min_x.min(glyph.position.x);
|
|
|
|
min_y = min_y.min(glyph.position.y - scaled_font.ascent());
|
|
|
|
max_x = max_x.max(glyph.position.x + scaled_font.h_advance(glyph.id));
|
|
|
|
max_y = max_y.max(glyph.position.y - scaled_font.descent());
|
|
|
|
}
|
|
|
|
|
2022-04-25 13:54:46 +00:00
|
|
|
let size = Vec2::new(max_x - min_x, max_y - min_y);
|
2020-11-13 00:21:48 +00:00
|
|
|
|
|
|
|
let glyphs = self.brush.process_glyphs(
|
|
|
|
section_glyphs,
|
2021-01-25 01:07:43 +00:00
|
|
|
§ions,
|
2020-11-13 00:21:48 +00:00
|
|
|
font_atlas_set_storage,
|
|
|
|
fonts,
|
|
|
|
texture_atlases,
|
|
|
|
textures,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
self.glyph_map.insert(id, TextLayoutInfo { glyphs, size });
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|