Skip to content

Commit 04a83d9

Browse files
committed
WIP: implement cache for rendered text
1 parent ad88235 commit 04a83d9

File tree

2 files changed

+45
-20
lines changed

2 files changed

+45
-20
lines changed

src/font.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use cosmic_text::fontdb::{Database, Source};
33
use cosmic_text::{Attrs, Buffer, Color, FontSystem, Metrics, Shaping, SwashCache};
44
use sdl2::pixels::PixelFormatEnum;
55
use sdl2::surface::Surface;
6+
use std::mem;
67
use std::path::PathBuf;
78

89
use crate::config::CONFIG;
@@ -35,7 +36,7 @@ impl Font {
3536
}
3637
}
3738

38-
pub fn render(&mut self, string: String, width: u32) -> Surface {
39+
pub fn render(&mut self, string: String, width: u32) -> usize {
3940
let metrics = Metrics::new(CJK_FONT_SIZE as f32, CJK_FONT_SIZE as f32);
4041
let mut buffer = Buffer::new(&mut self.font_system, metrics);
4142
let mut buffer = buffer.borrow_with(&mut self.font_system);
@@ -58,8 +59,10 @@ impl Font {
5859
buffer[offset * 4 + 3] = c.a();
5960
});
6061
});
62+
let surface_ptr = surface.raw() as usize;
63+
mem::forget(surface);
6164

62-
return surface;
65+
return surface_ptr;
6366
}
6467

6568
fn load(path: &str) -> Result<FontSystem> {

src/screen.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
use std::{mem, ptr};
1+
use std::{collections::HashMap, mem, ptr};
22

3-
use sdl2::{
4-
pixels::{Color, PixelFormatEnum},
5-
rect::Rect,
6-
surface::Surface,
7-
sys as sdl,
8-
};
3+
use sdl2::{pixels::PixelFormatEnum, rect::Rect, surface::Surface, sys as sdl};
94

105
use crate::{font::FONT, raw};
116

@@ -43,7 +38,7 @@ struct ScreenInfo {
4338
pub origin_y: i32,
4439
}
4540

46-
#[derive(Debug)]
41+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4742
#[repr(C)]
4843
pub struct ScreenChar {
4944
pub ch: u8,
@@ -61,6 +56,9 @@ pub struct Screen {
6156
is_top: bool,
6257
dimension: (u32, u32),
6358
canvas_ptr: usize,
59+
// cache: (content, sc) => surface_ptr
60+
prev: HashMap<(String, ScreenChar), usize>,
61+
next: HashMap<(String, ScreenChar), usize>,
6462
}
6563

6664
impl Screen {
@@ -69,6 +67,8 @@ impl Screen {
6967
is_top,
7068
dimension: Default::default(),
7169
canvas_ptr: Default::default(),
70+
prev: Default::default(),
71+
next: Default::default(),
7272
}
7373
}
7474

@@ -92,6 +92,7 @@ impl Screen {
9292
}
9393

9494
pub fn add(&mut self, gps: usize, x: i32, y: i32, content: String, width: usize) {
95+
// get screen character struct and flags for this text
9596
let offset = (x * self.dimension.1 as i32 + y) as usize;
9697
let screen_offset = if self.is_top { 0x228 } else { 0x1e0 };
9798

@@ -101,27 +102,40 @@ impl Screen {
101102
let flag_base = raw::deref::<usize>(gps + screen_offset + 0x38);
102103
let flag = raw::deref::<u32>(flag_base + offset * 4);
103104

105+
// early return: we only renders the top half by shift down by half font height
104106
if flag & ScreenTexPosFlag::BOTTOM_OF_TEXT as u32 != 0 {
105-
// we only renders the top half
106107
return;
107108
}
108109

110+
// render text or get from cache
111+
let key = (content.clone(), sc);
112+
let surface_ptr = match self.prev.get(&key) {
113+
Some(ptr) => ptr.to_owned() as *mut sdl::SDL_Surface,
114+
None => {
115+
let mut font = FONT.write();
116+
let ptr = font.render(content, width as u32 * CANVAS_FONT_WIDTH as u32) as *mut sdl::SDL_Surface;
117+
mem::drop(font);
118+
119+
unsafe { sdl::SDL_SetSurfaceColorMod(ptr, sc.r, sc.g, sc.b) };
120+
121+
ptr
122+
}
123+
};
124+
self.next.insert(key, surface_ptr as usize);
125+
126+
// calculate render offset
109127
let x = CANVAS_FONT_WIDTH * x;
110-
let mut y = CANVAS_FONT_HEIGHT as i32 * y;
128+
let mut y: i32 = CANVAS_FONT_HEIGHT as i32 * y;
111129
if flag & ScreenTexPosFlag::TOP_OF_TEXT as u32 != 0 {
112-
// shift down by half font height
130+
// shift down by half font height for top half
113131
y += CANVAS_FONT_HEIGHT / 2;
114132
}
115133

134+
// render on canvas
116135
unsafe {
117-
let mut font = FONT.write();
118-
let width = (width * CANVAS_FONT_WIDTH as usize) as u32;
119-
let mut surface = font.render(content, width);
120-
let mut rect = Rect::new(x, y, surface.width(), surface.height());
136+
let mut rect = Rect::new(x, y, (*surface_ptr).w as u32, (*surface_ptr).h as u32);
121137
let canvas = self.canvas_ptr as *mut sdl::SDL_Surface;
122-
surface.set_color_mod(Color::RGB(sc.r, sc.g, sc.b));
123-
124-
sdl::SDL_UpperBlit(surface.raw(), ptr::null(), canvas, rect.raw_mut());
138+
sdl::SDL_UpperBlit(surface_ptr, ptr::null(), canvas, rect.raw_mut());
125139
};
126140
}
127141

@@ -130,6 +144,14 @@ impl Screen {
130144
let canvas = self.canvas_ptr as *mut sdl::SDL_Surface;
131145
sdl::SDL_FillRect(canvas, ptr::null(), 0);
132146
}
147+
148+
for (k, v) in self.prev.iter() {
149+
if !self.next.contains_key(k) {
150+
unsafe { sdl::SDL_FreeSurface(v.to_owned() as *mut sdl::SDL_Surface) };
151+
}
152+
}
153+
154+
self.prev = mem::take(&mut self.next);
133155
}
134156

135157
pub fn render(&mut self, renderer: usize) {

0 commit comments

Comments
 (0)