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
105use 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 ) ]
4843pub 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
6664impl 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