veloren_voxygen/ui/
cache.rs

1use super::graphic::{Graphic, GraphicCache, Id as GraphicId};
2use crate::{
3    error::Error,
4    render::{Mesh, Renderer, Texture, UiTextureBindGroup, UiVertex},
5};
6use conrod_core::{text::GlyphCache, widget::Id};
7use hashbrown::HashMap;
8use vek::*;
9
10// TODO: probably make cache fields where we have mut getters into just public
11// fields
12
13// Multiplied by current window size
14const GLYPH_CACHE_SIZE: u32 = 1;
15// Glyph cache tolerances
16const SCALE_TOLERANCE: f32 = 0.5;
17const POSITION_TOLERANCE: f32 = 0.5;
18
19type TextCache = HashMap<Id, Mesh<UiVertex>>;
20
21pub struct Cache {
22    // Map from text ids to their positioned glyphs.
23    text_cache: TextCache,
24    glyph_cache: GlyphCache<'static>,
25    glyph_cache_tex: (Texture, UiTextureBindGroup),
26    graphic_cache: GraphicCache,
27}
28
29// TODO: Should functions be returning UiError instead of Error?
30impl Cache {
31    pub fn new(renderer: &mut Renderer) -> Result<Self, Error> {
32        let (w, h) = renderer.resolution().into_tuple();
33
34        let max_texture_size = renderer.max_texture_size();
35
36        let glyph_cache_dims =
37            Vec2::new(w, h).map(|e| (e * GLYPH_CACHE_SIZE).clamp(512, max_texture_size));
38
39        let glyph_cache_tex = {
40            let tex = renderer.create_dynamic_texture(glyph_cache_dims);
41            let bind = renderer.ui_bind_texture(&tex);
42            (tex, bind)
43        };
44
45        Ok(Self {
46            text_cache: Default::default(),
47            glyph_cache: GlyphCache::builder()
48                .dimensions(glyph_cache_dims.x, glyph_cache_dims.y)
49                .scale_tolerance(SCALE_TOLERANCE)
50                .position_tolerance(POSITION_TOLERANCE)
51                .build(),
52            glyph_cache_tex,
53            graphic_cache: GraphicCache::new(renderer),
54        })
55    }
56
57    pub fn glyph_cache_tex(&self) -> (&Texture, &UiTextureBindGroup) {
58        (&self.glyph_cache_tex.0, &self.glyph_cache_tex.1)
59    }
60
61    pub fn cache_mut_and_tex(
62        &mut self,
63    ) -> (
64        &mut GraphicCache,
65        &mut TextCache,
66        &mut GlyphCache<'static>,
67        &(Texture, UiTextureBindGroup),
68    ) {
69        (
70            &mut self.graphic_cache,
71            &mut self.text_cache,
72            &mut self.glyph_cache,
73            &self.glyph_cache_tex,
74        )
75    }
76
77    pub fn graphic_cache(&self) -> &GraphicCache { &self.graphic_cache }
78
79    pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId {
80        self.graphic_cache.add_graphic(graphic)
81    }
82
83    pub fn replace_graphic(&mut self, id: GraphicId, graphic: Graphic) {
84        self.graphic_cache.replace_graphic(id, graphic)
85    }
86
87    /// Resizes and clears the various caches.
88    ///
89    /// To be called when something like the scaling factor changes,
90    /// invalidating all existing cached UI state.
91    pub fn resize(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
92        self.graphic_cache.clear_cache(renderer);
93        self.text_cache.clear();
94        let max_texture_size = renderer.max_texture_size();
95        let cache_dims = renderer
96            .resolution()
97            .map(|e| (e * GLYPH_CACHE_SIZE).clamp(512, max_texture_size));
98        self.glyph_cache = GlyphCache::builder()
99            .dimensions(cache_dims.x, cache_dims.y)
100            .scale_tolerance(SCALE_TOLERANCE)
101            .position_tolerance(POSITION_TOLERANCE)
102            .build();
103        self.glyph_cache_tex = {
104            let tex = renderer.create_dynamic_texture(cache_dims);
105            let bind = renderer.ui_bind_texture(&tex);
106            (tex, bind)
107        };
108        Ok(())
109    }
110}