radiant_rs/core/
context.rs1use crate::core::{font, SpriteData};
2use crate::prelude::*;
3use crate::backends::backend;
4
5pub const NUM_BUCKETS: usize = 6;
7
8pub const INITIAL_CAPACITY: usize = 512;
10
11static GENERATION: AtomicUsize = AtomicUsize::new(0);
13
14#[derive(Clone)]
18pub struct Context (Arc<Mutex<ContextData>>);
19
20unsafe impl Send for Context { }
21unsafe impl Sync for Context { }
22
23impl Debug for Context {
24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 write!(f, "Context")
26 }
27}
28
29impl Context {
30 pub fn new() -> Context {
33 let context_data = ContextData::new();
34 Context(Arc::new(Mutex::new(context_data)))
35 }
36 pub fn prune(self: &Self) {
39 self.lock().prune();
40 }
41 pub(crate) fn lock<'a>(self: &'a Self) -> MutexGuard<'a, ContextData> {
43 self.0.lock().unwrap()
44 }
45}
46
47#[derive(Clone)]
49pub struct RawFrame {
50 pub data : Vec<u8>,
51 pub width : u32,
52 pub height : u32,
53 pub channels: u8,
54}
55
56struct SpriteBackRef (Weak<SpriteData>);
58
59impl SpriteBackRef {
60 fn new(data: Weak<SpriteData>) -> Self {
62 SpriteBackRef(data)
63 }
64 fn upgrade(self: &Self) -> Option<Arc<SpriteData>> {
66 self.0.upgrade()
67 }
68 fn range(self: &Self) -> Option<(usize, usize)> {
70 if let Some(data) = self.upgrade() {
71 Some((data.texture_id.load(Ordering::Relaxed), data.num_frames as usize * data.components as usize))
72 } else {
73 None
74 }
75 }
76}
77
78pub struct RawFrameArray {
80 pub dirty : bool,
81 pub data : backend::Texture2dArray,
82 pub raw : Vec<RawFrame>,
83 sprites : Vec<SpriteBackRef>,
84}
85
86impl RawFrameArray {
87 fn new(context: &backend::Context) -> Self {
88 RawFrameArray {
89 dirty : false,
90 data : backend::Texture2dArray::new(context, &Vec::new()),
91 raw : Vec::new(),
92 sprites : Vec::new(),
93 }
94 }
95 pub fn store_frames<'a>(self: &mut Self, raw_frames: Vec<RawFrame>) -> u32 {
97 let texture_id = self.raw.len() as u32;
98 for frame in raw_frames {
99 self.raw.push(frame);
100 }
101 self.dirty = true;
102 texture_id
103 }
104 pub fn store_sprite(self: &mut Self, sprite_data: Weak<SpriteData>) {
106 self.sprites.push(SpriteBackRef::new(sprite_data));
107 }
108 fn update(self: &mut Self, context: &backend::Context) {
110 if self.dirty {
111 self.dirty = false;
112 self.data = backend::Texture2dArray::new(context, &self.raw);
113 }
114 }
115 fn create_prune_map(self: &Self) -> Option<Vec<(usize, usize)>> {
117 let mut mapping = self.sprites.iter().filter_map(|sprite| sprite.range()).collect::<Vec<(usize, usize)>>();
118 mapping.sort_by_key(|a| a.0);
119 let mut num_items = 0;
120 for i in 0..mapping.len() {
121 let items = mapping[i].1;
122 mapping[i].1 = mapping[i].0 - num_items;
123 num_items += items;
124 }
125 if mapping.len() > 0 { Some(mapping) } else { None }
126 }
127 fn prune_raw_textures(self: &mut Self, mapping: &Vec<(usize, usize)>) -> HashMap<usize, usize> {
129 let new_size = self.raw.len() - mapping.last().unwrap().1;
130 let mut destination_map = HashMap::new();
131 for m in 0..mapping.len() {
132 destination_map.insert(mapping[m].0, mapping[m].0 - mapping[m].1);
133 let end = if m + 1 < mapping.len() { mapping[m+1].0 } else { new_size -1 };
134 for i in (mapping[m].0)..end {
135 let destination_index = i - mapping[m].1;
136 self.raw.swap(i, destination_index);
137 }
138 }
139 self.raw.truncate(new_size);
140 destination_map
141 }
142 fn prune_sprites<T>(self: &mut Self, mut func: T) where T: FnMut(&Arc<SpriteData>) {
144 let mut removed = Vec::new();
145 for (i, sprite) in self.sprites.iter().enumerate() {
146 if let Some(sprite) = sprite.upgrade() {
147 func(&sprite);
148 } else {
149 removed.push(i);
150 }
151 }
152 for index in removed.iter().rev() {
153 self.sprites.swap_remove(*index);
154 }
155 }
156 fn prune(self: &mut Self, context: &backend::Context, generation: usize) {
158 if let Some(mapping) = self.create_prune_map() {
159 let destination_map = self.prune_raw_textures(&mapping);
161 self.dirty = true;
162 self.update(context);
163 self.prune_sprites(|sprite| {
165 let texture_id = sprite.texture_id.load(Ordering::Relaxed);
166 if let Some(new_texture_id) = destination_map.get(&texture_id) {
167 sprite.texture_id.store(*new_texture_id, Ordering::Relaxed);
168 }
169 sprite.generation.store(generation, Ordering::Relaxed);
170 });
171 } else {
172 self.prune_sprites(|sprite| {
174 sprite.generation.store(generation, Ordering::Relaxed);
175 })
176 }
177 }
178}
179
180pub struct ContextData {
182 pub backend_context : Option<backend::Context>,
183 pub tex_arrays : Vec<RawFrameArray>,
184 pub font_cache_dimensions: u32,
185 pub font_cache : font::FontCache,
186 pub font_texture : Option<backend::Texture2d>,
187 generation : usize,
188}
189
190impl ContextData {
191
192 fn init_backend(self: &mut Self, display: &backend::Display) {
194
195 let backend_context = backend::Context::new(display, INITIAL_CAPACITY);
196
197 for _ in 0..NUM_BUCKETS {
200 self.tex_arrays.push(RawFrameArray::new(&backend_context));
201 }
202
203 let data = crate::core::RawFrame {
206 width : self.font_cache_dimensions,
207 height : self.font_cache_dimensions,
208 data : vec![0u8; self.font_cache_dimensions as usize * self.font_cache_dimensions as usize],
209 channels: 1,
210 };
211
212 let texture = backend::Texture2d::new(&backend_context, self.font_cache_dimensions, self.font_cache_dimensions, crate::core::TextureFormat::U8, Some(data));
213
214 self.font_texture = Some(texture);
215 self.backend_context = Some(backend_context);
216 }
217
218 fn new() -> Self {
220
221 let font_cache_dimensions = 512;
222
223 ContextData {
224 backend_context : None,
225 tex_arrays : Vec::new(),
226 font_cache : font::FontCache::new(font_cache_dimensions, font_cache_dimensions, 0.01, 0.01),
227 font_texture : None,
228 font_cache_dimensions,
229 generation : Self::create_generation(),
230 }
231 }
232
233 pub fn has_primary_display(self: &Self) -> bool {
235 self.backend_context.is_some()
236 }
237
238 pub fn set_primary_display(self: &mut Self, display: &backend::Display) {
240 self.init_backend(&display);
241 }
242
243 pub fn generation(self: &Self) -> usize {
245 self.generation
246 }
247
248 pub fn update_font_cache(self: &Self) {
250 self.font_cache.update(self.font_texture.as_ref().unwrap());
251 }
252
253 pub fn update_tex_array(self: &mut Self) {
255 for ref mut array in self.tex_arrays.iter_mut() {
256 array.update(self.backend_context.as_ref().unwrap());
257 }
258 }
259
260 pub fn store_frames(self: &mut Self, bucket_id: u32, raw_frames: Vec<RawFrame>) -> u32 {
262 self.tex_arrays[bucket_id as usize].store_frames(raw_frames)
263 }
264
265 pub fn store_sprite(self: &mut Self, bucket_id: u32, sprite_data: Weak<SpriteData>) {
267 self.tex_arrays[bucket_id as usize].store_sprite(sprite_data);
268 }
269
270 fn prune(self: &mut Self) {
272 self.generation = Self::create_generation();
273 for array in self.tex_arrays.iter_mut() {
274 array.prune(self.backend_context.as_ref().unwrap(), self.generation);
275 }
276 }
277
278 fn create_generation() -> usize {
280 GENERATION.fetch_add(1, Ordering::Relaxed) + 1
282 }
283}