1010static rg_task_t * display_task_queue ;
1111static rg_display_counters_t counters ;
1212static rg_display_config_t config ;
13- static rg_surface_t * osd ;
1413static rg_surface_t * border ;
1514static rg_display_t display ;
1615static int16_t map_viewport_to_source_x [RG_SCREEN_WIDTH + 1 ];
1716static int16_t map_viewport_to_source_y [RG_SCREEN_HEIGHT + 1 ];
1817static uint32_t screen_line_checksum [RG_SCREEN_HEIGHT + 1 ];
1918
19+ // OSD Surface Management
20+ static rg_surface_t * osd_surface = NULL ;
21+ static rg_rect_t osd_rect ; // Store the OSD's position and size
22+ static bool osd_enabled = false;
23+
2024#define LINE_IS_REPEATED (Y ) (map_viewport_to_source_y[(Y)] == map_viewport_to_source_y[(Y) - 1])
2125// This is to avoid flooring a number that is approximated to .9999999 and be explicit about it
2226#define FLOAT_TO_INT (x ) ((int)((x) + 0.1f))
@@ -36,6 +40,48 @@ static const char *SETTING_CUSTOM_ZOOM = "DispCustomZoom";
3640#include "drivers/display/dummy.h"
3741#endif
3842
43+ void rg_display_set_osd_surface (rg_surface_t * surface , rg_rect_t rect )
44+ {
45+ // Free the old surface if it exists
46+ if (osd_surface != NULL ) {
47+ rg_surface_free (osd_surface );
48+ }
49+
50+ osd_surface = surface ;
51+ osd_rect = rect ; // Store the position and size
52+ if (surface != NULL )
53+ { // Only clear if a surface is provided
54+ uint16_t * buffer = surface -> data ; // Treat the buffer as 16-bit values
55+ for (int i = 0 ; i < surface -> width * surface -> height ; i ++ )
56+ buffer [i ] = C_TRANSPARENT ; // Assign the black color directly // C_TRANSPARENT
57+ }
58+
59+ osd_enabled = (surface != NULL ); // Enable OSD if surface is valid
60+ }
61+
62+ rg_surface_t * rg_display_get_osd_surface ()
63+ {
64+ return osd_surface ;
65+ }
66+
67+ void rg_display_set_osd_enabled (bool enabled )
68+ {
69+ osd_enabled = enabled ;
70+ rg_display_force_redraw ();
71+ }
72+
73+ bool rg_display_is_osd_enabled ()
74+ {
75+ return osd_enabled ;
76+ }
77+
78+ void deinit_osd ()
79+ {
80+ rg_surface_free (osd_surface ); // Free the OSD surface
81+ osd_surface = NULL ;
82+ osd_enabled = false;
83+ }
84+
3985static inline unsigned blend_pixels (unsigned a , unsigned b )
4086{
4187 // Fast path (taken 80-90% of the time)
@@ -205,13 +251,46 @@ static inline void write_update(const rg_surface_t *update)
205251 lines_remaining -= lines_to_copy ;
206252 }
207253
208- if (osd != NULL )
254+ if (osd_enabled && osd_surface != NULL )
209255 {
210256 // TODO: Draw on screen display. By default it should be bottom left which is fine
211257 // for both virtual keyboard and info labels. Maybe make it configurable later...
258+ int * buffer = osd_surface -> data ;
259+ RG_ASSERT_ARG (buffer );
260+
261+ // Clipping
262+ int width = RG_MIN (osd_rect .width , display .screen .width - osd_rect .left );
263+ int height = RG_MIN (osd_rect .height , display .screen .height - osd_rect .top );
264+
265+ // This can happen when left or top is out of bound
266+ if (width < 0 || height < 0 )
267+ return ;
268+
269+ lcd_set_window (osd_rect .left + display .screen .margin_left , osd_rect .top + display .screen .margin_top , width , height );
270+
271+ for (size_t y = 0 ; y < height ;)
272+ {
273+ uint16_t * lcd_buffer = lcd_get_buffer (LCD_BUFFER_LENGTH );
274+ size_t num_lines = RG_MIN (LCD_BUFFER_LENGTH / width , height - y );
275+
276+ // Copy line by line because stride may not match width
277+ for (size_t line = 0 ; line < num_lines ; ++ line )
278+ {
279+ uint16_t * src = (void * )buffer + ((y + line ) * osd_rect .width * 2 );
280+ uint16_t * dst = lcd_buffer + (line * width );
281+ for (size_t i = 0 ; i < width ; ++ i ){
282+ if (src [i ] != C_TRANSPARENT ) // only overwrite pixels that aren't transparent
283+ dst [i ] = (src [i ] >> 8 ) | (src [i ] << 8 );
284+ }
285+ }
286+
287+ lcd_send_buffer (lcd_buffer , width * num_lines );
288+ y += num_lines ;
289+ }
290+ lcd_sync ();
212291 }
213292
214- if (lines_updated > draw_height * 0.80f )
293+ if (lines_updated > display . screen . height * 0.80f )
215294 counters .fullFrames ++ ;
216295 else
217296 counters .partFrames ++ ;
@@ -220,25 +299,23 @@ static inline void write_update(const rg_surface_t *update)
220299
221300static void update_viewport_scaling (void )
222301{
223- int screen_width = display .screen .width ;
224- int screen_height = display .screen .height ;
225302 int src_width = display .source .width ;
226303 int src_height = display .source .height ;
227304 int new_width = src_width ;
228305 int new_height = src_height ;
229306
230307 if (config .scaling == RG_DISPLAY_SCALING_FULL )
231308 {
232- new_width = screen_width ;
233- new_height = screen_height ;
309+ new_width = display . screen . width ;
310+ new_height = display . screen . height ;
234311 }
235312 else if (config .scaling == RG_DISPLAY_SCALING_FIT )
236313 {
237- new_width = FLOAT_TO_INT (screen_height * ((float )src_width / src_height ));
238- new_height = screen_height ;
239- if (new_width > screen_width ) {
240- new_width = screen_width ;
241- new_height = FLOAT_TO_INT (screen_width * ((float )src_height / src_width ));
314+ new_width = FLOAT_TO_INT (display . screen . height * ((float )src_width / src_height ));
315+ new_height = display . screen . height ;
316+ if (new_width > display . screen . width ) {
317+ new_width = display . screen . width ;
318+ new_height = FLOAT_TO_INT (display . screen . width * ((float )src_height / src_width ));
242319 }
243320 }
244321 else if (config .scaling == RG_DISPLAY_SCALING_ZOOM )
@@ -251,8 +328,8 @@ static void update_viewport_scaling(void)
251328 new_width &= ~1 ;
252329 new_height &= ~1 ;
253330
254- display .viewport .left = (screen_width - new_width ) / 2 ;
255- display .viewport .top = (screen_height - new_height ) / 2 ;
331+ display .viewport .left = (display . screen . width - new_width ) / 2 ;
332+ display .viewport .top = (display . screen . height - new_height ) / 2 ;
256333 display .viewport .width = new_width ;
257334 display .viewport .height = new_height ;
258335
@@ -266,9 +343,9 @@ static void update_viewport_scaling(void)
266343
267344 memset (screen_line_checksum , 0 , sizeof (screen_line_checksum ));
268345
269- for (int x = 0 ; x < screen_width ; ++ x )
346+ for (int x = 0 ; x < display . screen . width ; ++ x )
270347 map_viewport_to_source_x [x ] = FLOAT_TO_INT (x * display .viewport .step_x );
271- for (int y = 0 ; y < screen_height ; ++ y )
348+ for (int y = 0 ; y < display . screen . height ; ++ y )
272349 map_viewport_to_source_y [y ] = FLOAT_TO_INT (y * display .viewport .step_y );
273350
274351 RG_LOGI ("%dx%d@%.3f => %dx%d@%.3f left:%d top:%d step_x:%.2f step_y:%.2f" , src_width , src_height ,
@@ -285,9 +362,9 @@ static bool load_border_file(const char *filename)
285362
286363 if (filename && (border = rg_surface_load_image_file (filename , 0 )))
287364 {
288- if (border -> width != rg_display_get_width () || border -> height != rg_display_get_height () )
365+ if (border -> width != display . screen . width || border -> height != display . screen . height )
289366 {
290- rg_surface_t * resized = rg_surface_resize (border , rg_display_get_width (), rg_display_get_height () );
367+ rg_surface_t * resized = rg_surface_resize (border , display . screen . width , display . screen . height );
291368 if (resized )
292369 {
293370 rg_surface_free (border );
@@ -350,16 +427,6 @@ rg_display_counters_t rg_display_get_counters(void)
350427 return counters ;
351428}
352429
353- int rg_display_get_width (void )
354- {
355- return display .screen .width ;
356- }
357-
358- int rg_display_get_height (void )
359- {
360- return display .screen .height ;
361- }
362-
363430void rg_display_set_scaling (display_scaling_t scaling )
364431{
365432 config .scaling = RG_MIN (RG_MAX (0 , scaling ), RG_DISPLAY_SCALING_COUNT - 1 );
0 commit comments