Skip to content

Commit 5ed83e7

Browse files
committed
add basic OSD
1 parent 986339f commit 5ed83e7

File tree

7 files changed

+274
-115
lines changed

7 files changed

+274
-115
lines changed

components/retro-go/rg_display.c

Lines changed: 95 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
static rg_task_t *display_task_queue;
1111
static rg_display_counters_t counters;
1212
static rg_display_config_t config;
13-
static rg_surface_t *osd;
1413
static rg_surface_t *border;
1514
static rg_display_t display;
1615
static int16_t map_viewport_to_source_x[RG_SCREEN_WIDTH + 1];
1716
static int16_t map_viewport_to_source_y[RG_SCREEN_HEIGHT + 1];
1817
static 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+
3985
static 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

221300
static 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-
363430
void rg_display_set_scaling(display_scaling_t scaling)
364431
{
365432
config.scaling = RG_MIN(RG_MAX(0, scaling), RG_DISPLAY_SCALING_COUNT - 1);

components/retro-go/rg_display.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ typedef struct
9999

100100
#include "rg_surface.h"
101101

102+
void rg_display_set_osd_surface(rg_surface_t *surface, rg_rect_t rect);
103+
rg_surface_t* rg_display_get_osd_surface();
104+
void rg_display_set_osd_enabled(bool enabled);
105+
bool rg_display_is_osd_enabled();
106+
void deinit_osd();
107+
102108
void rg_display_init(void);
103109
void rg_display_deinit(void);
104110
void rg_display_write_rect(int left, int top, int width, int height, int stride, const uint16_t *buffer, uint32_t flags);
@@ -111,8 +117,6 @@ void rg_display_submit(const rg_surface_t *update, uint32_t flags);
111117

112118
rg_display_counters_t rg_display_get_counters(void);
113119
const rg_display_t *rg_display_get_info(void);
114-
int rg_display_get_width(void);
115-
int rg_display_get_height(void);
116120

117121
void rg_display_set_scaling(display_scaling_t scaling);
118122
display_scaling_t rg_display_get_scaling(void);

0 commit comments

Comments
 (0)