1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 * Copyright (C) 2016-2019 - Brad Parker
5 *
6 * RetroArch is free software: you can redistribute it and/or modify it under the terms
7 * of the GNU General Public License as published by the Free Software Found-
8 * ation, either version 3 of the License, or (at your option) any later version.
9 *
10 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with RetroArch.
15 * If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "gfx_display.h"
18
19 #include "video_coord_array.h"
20 #include "../configuration.h"
21 #include "../verbosity.h"
22
23 /* Standard reference DPI value, used when determining
24 * DPI-aware scaling factors */
25 #define REFERENCE_DPI 96.0f
26
27 /* 'OZONE_SIDEBAR_WIDTH' must be kept in sync
28 * with Ozone driver metrics */
29 #define OZONE_SIDEBAR_WIDTH 408
30
31 /* TODO/FIXME - global that gets referenced outside,
32 * needs to be refactored */
33 uintptr_t gfx_display_white_texture;
34
gfx_display_null_font_init_first(void ** font_handle,void * video_data,const char * font_path,float font_size,bool is_threaded)35 static bool gfx_display_null_font_init_first(
36 void **font_handle, void *video_data,
37 const char *font_path, float font_size,
38 bool is_threaded)
39 {
40 font_data_t **handle = (font_data_t**)font_handle;
41 if ((*handle = font_driver_init_first(video_data,
42 font_path, font_size, true,
43 is_threaded,
44 FONT_DRIVER_RENDER_DONT_CARE)))
45 return true;
46 return false;
47 }
48
null_get_default_matrix(void)49 static const float *null_get_default_matrix(void)
50 {
51 static float dummy[16] = {0.0f};
52 return &dummy[0];
53 }
54
55 gfx_display_ctx_driver_t gfx_display_ctx_null = {
56 NULL, /* draw */
57 NULL, /* draw_pipeline */
58 NULL, /* blend_begin */
59 NULL, /* blend_end */
60 NULL, /* get_default_mvp */
61 null_get_default_matrix,
62 null_get_default_matrix,
63 gfx_display_null_font_init_first,
64 GFX_VIDEO_DRIVER_GENERIC,
65 "null",
66 false,
67 NULL,
68 NULL
69 };
70
71 /* Menu display drivers */
72 static gfx_display_ctx_driver_t *gfx_display_ctx_drivers[] = {
73 #ifdef HAVE_D3D8
74 &gfx_display_ctx_d3d8,
75 #endif
76 #ifdef HAVE_D3D9
77 &gfx_display_ctx_d3d9,
78 #endif
79 #ifdef HAVE_D3D10
80 &gfx_display_ctx_d3d10,
81 #endif
82 #ifdef HAVE_D3D11
83 &gfx_display_ctx_d3d11,
84 #endif
85 #ifdef HAVE_D3D12
86 &gfx_display_ctx_d3d12,
87 #endif
88 #ifdef HAVE_OPENGL
89 &gfx_display_ctx_gl,
90 #endif
91 #ifdef HAVE_OPENGL1
92 &gfx_display_ctx_gl1,
93 #endif
94 #ifdef HAVE_OPENGL_CORE
95 &gfx_display_ctx_gl_core,
96 #endif
97 #ifdef HAVE_VULKAN
98 &gfx_display_ctx_vulkan,
99 #endif
100 #ifdef HAVE_METAL
101 &gfx_display_ctx_metal,
102 #endif
103 #ifdef HAVE_VITA2D
104 &gfx_display_ctx_vita2d,
105 #endif
106 #ifdef _3DS
107 &gfx_display_ctx_ctr,
108 #endif
109 #ifdef WIIU
110 &gfx_display_ctx_wiiu,
111 #endif
112 #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
113 #ifdef HAVE_GDI
114 &gfx_display_ctx_gdi,
115 #endif
116 #endif
117 &gfx_display_ctx_null,
118 NULL,
119 };
120
gfx_display_get_adjusted_scale(gfx_display_t * p_disp,float base_scale,float scale_factor,unsigned width)121 float gfx_display_get_adjusted_scale(
122 gfx_display_t *p_disp,
123 float base_scale, float scale_factor, unsigned width)
124 {
125 /* Apply user-set scaling factor */
126 float adjusted_scale = base_scale * scale_factor;
127 #ifdef HAVE_OZONE
128 /* Ozone has a capped scale factor */
129 if (p_disp->menu_driver_id == MENU_DRIVER_ID_OZONE)
130 {
131 float new_width = (float)width * 0.3333333f;
132 if (((float)OZONE_SIDEBAR_WIDTH * adjusted_scale)
133 > new_width)
134 adjusted_scale = (new_width / (float)OZONE_SIDEBAR_WIDTH);
135 }
136 #endif
137
138 /* Ensure final scale is 'sane' */
139 if (adjusted_scale <= 0.0001f)
140 return 1.0f;
141 return adjusted_scale;
142 }
143
144 /* Check if the current menu driver is compatible
145 * with your video driver. */
gfx_display_check_compatibility(enum gfx_display_driver_type type,bool video_is_threaded)146 static bool gfx_display_check_compatibility(
147 enum gfx_display_driver_type type,
148 bool video_is_threaded)
149 {
150 const char *video_driver = video_driver_get_ident();
151
152 switch (type)
153 {
154 case GFX_VIDEO_DRIVER_GENERIC:
155 return true;
156 case GFX_VIDEO_DRIVER_OPENGL:
157 if (string_is_equal(video_driver, "gl"))
158 return true;
159 break;
160 case GFX_VIDEO_DRIVER_OPENGL1:
161 if (string_is_equal(video_driver, "gl1"))
162 return true;
163 break;
164 case GFX_VIDEO_DRIVER_OPENGL_CORE:
165 if (string_is_equal(video_driver, "glcore"))
166 return true;
167 break;
168 case GFX_VIDEO_DRIVER_VULKAN:
169 if (string_is_equal(video_driver, "vulkan"))
170 return true;
171 break;
172 case GFX_VIDEO_DRIVER_METAL:
173 if (string_is_equal(video_driver, "metal"))
174 return true;
175 break;
176 case GFX_VIDEO_DRIVER_DIRECT3D8:
177 if (string_is_equal(video_driver, "d3d8"))
178 return true;
179 break;
180 case GFX_VIDEO_DRIVER_DIRECT3D9:
181 if (string_is_equal(video_driver, "d3d9"))
182 return true;
183 break;
184 case GFX_VIDEO_DRIVER_DIRECT3D10:
185 if (string_is_equal(video_driver, "d3d10"))
186 return true;
187 break;
188 case GFX_VIDEO_DRIVER_DIRECT3D11:
189 if (string_is_equal(video_driver, "d3d11"))
190 return true;
191 break;
192 case GFX_VIDEO_DRIVER_DIRECT3D12:
193 if (string_is_equal(video_driver, "d3d12"))
194 return true;
195 break;
196 case GFX_VIDEO_DRIVER_VITA2D:
197 if (string_is_equal(video_driver, "vita2d"))
198 return true;
199 break;
200 case GFX_VIDEO_DRIVER_CTR:
201 if (string_is_equal(video_driver, "ctr"))
202 return true;
203 break;
204 case GFX_VIDEO_DRIVER_WIIU:
205 if (string_is_equal(video_driver, "gx2"))
206 return true;
207 break;
208 case GFX_VIDEO_DRIVER_GDI:
209 if (string_is_equal(video_driver, "gdi"))
210 return true;
211 break;
212 case GFX_VIDEO_DRIVER_SWITCH:
213 if (string_is_equal(video_driver, "switch"))
214 return true;
215 break;
216 }
217
218 return false;
219 }
220
gfx_display_get_dpi_scale_internal(unsigned width,unsigned height)221 float gfx_display_get_dpi_scale_internal(
222 unsigned width, unsigned height)
223 {
224 float dpi;
225 float diagonal_pixels;
226 float pixel_scale;
227 static unsigned last_width = 0;
228 static unsigned last_height = 0;
229 static float scale = 0.0f;
230 static bool scale_cached = false;
231 gfx_ctx_metrics_t metrics;
232
233 if (scale_cached &&
234 (width == last_width) &&
235 (height == last_height))
236 return scale;
237
238 /* Determine the diagonal 'size' of the display
239 * (or window) in terms of pixels */
240 diagonal_pixels = (float)sqrt(
241 (double)((width * width) + (height * height)));
242
243 /* TODO/FIXME: On Mac, calling video_context_driver_get_metrics()
244 * here causes RetroArch to crash (EXC_BAD_ACCESS). This is
245 * unfortunate, and needs to be fixed at the gfx context driver
246 * level. Until this is done, all we can do is fallback to using
247 * the old legacy 'magic number' scaling on Mac platforms. */
248 #if !defined(HAVE_COCOATOUCH) && (defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL))
249 if (true)
250 {
251 scale = (diagonal_pixels / 6.5f) / 212.0f;
252 scale_cached = true;
253 last_width = width;
254 last_height = height;
255 return scale;
256 }
257 #endif
258
259 /* Get pixel scale relative to baseline 1080p display */
260 pixel_scale = diagonal_pixels / DIAGONAL_PIXELS_1080P;
261
262 /* Attempt to get display DPI */
263 metrics.type = DISPLAY_METRIC_DPI;
264 metrics.value = &dpi;
265
266 if (video_context_driver_get_metrics(&metrics) && (dpi > 0.0f))
267 {
268 float display_size;
269 float dpi_scale;
270
271 #if defined(ANDROID) || defined(HAVE_COCOATOUCH)
272 /* Android/iOS devices tell complete lies when
273 * reporting DPI values. From the Android devices
274 * I've had access to, the DPI is generally
275 * overestimated by 17%. All we can do is apply
276 * a blind correction factor... */
277 dpi *= 0.83f;
278 #endif
279
280 /* Note: If we are running in windowed mode, this
281 * 'display size' is actually the window size - which
282 * kinda makes a mess of everything. Since we cannot
283 * get fullscreen resolution when running in windowed
284 * mode, there is nothing we can do about this. So just
285 * treat the window as a display, and hope for the best... */
286 display_size = diagonal_pixels / dpi;
287 dpi_scale = dpi / REFERENCE_DPI;
288
289 /* Note: We have tried leveraging every possible metric
290 * (and numerous studies on TV/monitor/mobile device
291 * usage habits) to determine an appropriate auto scaling
292 * factor. *None of these 'smart'/technical methods work
293 * consistently in the real world* - there is simply too
294 * much variance.
295 * So instead we have implemented a very fuzzy/loose
296 * method which is crude as can be, but actually has
297 * some semblance of usability... */
298
299 if (display_size > 24.0f)
300 {
301 /* DPI scaling fails miserably when using large
302 * displays. Having a UI element that's 1 inch high
303 * on all screens might seem like a good idea - until
304 * you realise that a HTPC user is probably sitting
305 * several metres from their TV, which makes something
306 * 1 inch high virtually invisible.
307 * So we make some assumptions:
308 * - Normal size displays <= 24 inches are probably
309 * PC monitors, with an eye-to-screen distance of
310 * 1 arm length. Under these conditions, fixed size
311 * (DPI scaled) UI elements should be visible for most
312 * users
313 * - Large displays > 24 inches start to encroach on
314 * TV territory. Once we start working with TVs, we
315 * have to consider users sitting on a couch - and
316 * in this situation, we fall back to the age-old
317 * standard of UI elements occupying a fixed fraction
318 * of the display size (i.e. just look at the menu of
319 * any console system for the past decade)
320 * - 24 -> 32 inches is a grey area, where the display
321 * might be a monitor or a TV. Above 32 inches, a TV
322 * is almost a certainty. So we simply lerp between
323 * dpi scaling and pixel scaling as the display size
324 * increases from 24 to 32 */
325 float fraction = (display_size > 32.0f) ? 32.0f : display_size;
326 fraction -= 24.0f;
327 fraction /= (32.0f - 24.0f);
328
329 scale = ((1.0f - fraction) * dpi_scale)
330 + (fraction * pixel_scale);
331 }
332 else if (display_size < 12.0f)
333 {
334 /* DPI scaling also fails when using very small
335 * displays - i.e. mobile devices (tablets/phones).
336 * That 1 inch UI element is going to look pretty
337 * dumb on a 5 inch screen in landscape orientation...
338 * We're essentially in the opposite situation to the
339 * TV case above, and it turns out that a similar
340 * solution provides relief: as screen size reduces
341 * from 12 inches to zero, we lerp from dpi scaling
342 * to pixel scaling */
343 float fraction = display_size / 12.0f;
344
345 scale = ((1.0f - fraction) * pixel_scale)
346 + (fraction * dpi_scale);
347 }
348 else
349 scale = dpi_scale;
350 }
351 /* If DPI retrieval is unsupported, all we can do
352 * is use the raw pixel scale */
353 else
354 scale = pixel_scale;
355
356 scale_cached = true;
357 last_width = width;
358 last_height = height;
359
360 return scale;
361 }
362
gfx_display_get_dpi_scale(gfx_display_t * p_disp,void * settings_data,unsigned width,unsigned height)363 float gfx_display_get_dpi_scale(
364 gfx_display_t *p_disp,
365 void *settings_data,
366 unsigned width, unsigned height)
367 {
368 static unsigned last_width = 0;
369 static unsigned last_height = 0;
370 static float scale = 0.0f;
371 static bool scale_cached = false;
372 bool scale_updated = false;
373 static float last_menu_scale_factor = 0.0f;
374 static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN;
375 static float adjusted_scale = 1.0f;
376 settings_t *settings = (settings_t*)settings_data;
377 float menu_scale_factor = settings->floats.menu_scale_factor;
378
379 /* Scale is based on display metrics - these are a fixed
380 * hardware property. To minimise performance overheads
381 * we therefore only call video_context_driver_get_metrics()
382 * on first run, or when the current video resolution changes */
383 if (!scale_cached ||
384 (width != last_width) ||
385 (height != last_height))
386 {
387 scale = gfx_display_get_dpi_scale_internal(width, height);
388 scale_cached = true;
389 scale_updated = true;
390 last_width = width;
391 last_height = height;
392 }
393
394 /* Adjusted scale calculation may also be slow, so
395 * only update if something changes */
396 if (scale_updated ||
397 (menu_scale_factor != last_menu_scale_factor) ||
398 (p_disp->menu_driver_id != last_menu_driver_id))
399 {
400 adjusted_scale = gfx_display_get_adjusted_scale(
401 p_disp,
402 scale, menu_scale_factor, width);
403 last_menu_scale_factor = menu_scale_factor;
404 last_menu_driver_id = p_disp->menu_driver_id;
405 }
406
407 return adjusted_scale;
408 }
409
410 /* Begin scissoring operation */
gfx_display_scissor_begin(gfx_display_t * p_disp,void * userdata,unsigned video_width,unsigned video_height,int x,int y,unsigned width,unsigned height)411 void gfx_display_scissor_begin(
412 gfx_display_t *p_disp,
413 void *userdata,
414 unsigned video_width,
415 unsigned video_height,
416 int x, int y, unsigned width, unsigned height)
417 {
418 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
419 if (dispctx && dispctx->scissor_begin)
420 {
421 if (y < 0)
422 {
423 if (height < (unsigned)(-y))
424 height = 0;
425 else
426 height += y;
427 y = 0;
428 }
429 if (x < 0)
430 {
431 if (width < (unsigned)(-x))
432 width = 0;
433 else
434 width += x;
435 x = 0;
436 }
437 if (y >= (int)video_height)
438 {
439 height = 0;
440 y = 0;
441 }
442 if (x >= (int)video_width)
443 {
444 width = 0;
445 x = 0;
446 }
447 if ((y + height) > video_height)
448 height = video_height - y;
449 if ((x + width) > video_width)
450 width = video_width - x;
451
452 dispctx->scissor_begin(userdata,
453 video_width, video_height,
454 x, y, width, height);
455 }
456 }
457
gfx_display_font_file(gfx_display_t * p_disp,char * fontpath,float menu_font_size,bool is_threaded)458 font_data_t *gfx_display_font_file(
459 gfx_display_t *p_disp,
460 char* fontpath, float menu_font_size, bool is_threaded)
461 {
462 font_data_t *font_data = NULL;
463 float font_size = menu_font_size;
464 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
465
466 if (!dispctx)
467 return NULL;
468
469 /* Font size must be at least 2, or font_init_first()
470 * will generate a heap-buffer-overflow when using
471 * many font drivers */
472 if (font_size < 2.0f)
473 font_size = 2.0f;
474
475 if (!dispctx->font_init_first((void**)&font_data,
476 video_driver_get_ptr(),
477 fontpath, font_size, is_threaded))
478 return NULL;
479
480 return font_data;
481 }
482
gfx_display_draw_bg(gfx_display_t * p_disp,gfx_display_ctx_draw_t * draw,void * userdata,bool add_opacity_to_wallpaper,float override_opacity)483 void gfx_display_draw_bg(
484 gfx_display_t *p_disp,
485 gfx_display_ctx_draw_t *draw,
486 void *userdata, bool add_opacity_to_wallpaper,
487 float override_opacity)
488 {
489 static struct video_coords coords;
490 const float *new_vertex = NULL;
491 const float *new_tex_coord = NULL;
492 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
493 if (!dispctx || !draw)
494 return;
495
496 if (draw->vertex)
497 new_vertex = draw->vertex;
498 else if (dispctx->get_default_vertices)
499 new_vertex = dispctx->get_default_vertices();
500
501 if (draw->tex_coord)
502 new_tex_coord = draw->tex_coord;
503 else if (dispctx->get_default_tex_coords)
504 new_tex_coord = dispctx->get_default_tex_coords();
505
506 coords.vertices = (unsigned)draw->vertex_count;
507 coords.vertex = new_vertex;
508 coords.tex_coord = new_tex_coord;
509 coords.lut_tex_coord = new_tex_coord;
510 coords.color = (const float*)draw->color;
511
512 draw->coords = &coords;
513 draw->scale_factor = 1.0f;
514 draw->rotation = 0.0f;
515
516 if (draw->texture)
517 add_opacity_to_wallpaper = true;
518 else
519 draw->texture = gfx_display_white_texture;
520
521 if (add_opacity_to_wallpaper)
522 gfx_display_set_alpha(draw->color, override_opacity);
523
524 if (dispctx->get_default_mvp)
525 draw->matrix_data = (math_matrix_4x4*)dispctx->get_default_mvp(
526 userdata);
527 }
528
gfx_display_draw_quad(gfx_display_t * p_disp,void * data,unsigned video_width,unsigned video_height,int x,int y,unsigned w,unsigned h,unsigned width,unsigned height,float * color)529 void gfx_display_draw_quad(
530 gfx_display_t *p_disp,
531 void *data,
532 unsigned video_width,
533 unsigned video_height,
534 int x, int y, unsigned w, unsigned h,
535 unsigned width, unsigned height,
536 float *color)
537 {
538 gfx_display_ctx_draw_t draw;
539 struct video_coords coords;
540 gfx_display_ctx_driver_t
541 *dispctx = p_disp->dispctx;
542
543 if (w == 0 || h == 0)
544 return;
545 if (!dispctx)
546 return;
547
548 coords.vertices = 4;
549 coords.vertex = NULL;
550 coords.tex_coord = NULL;
551 coords.lut_tex_coord = NULL;
552 coords.color = color;
553
554 draw.x = x;
555 draw.y = (int)height - y - (int)h;
556 draw.width = w;
557 draw.height = h;
558 draw.coords = &coords;
559 draw.matrix_data = NULL;
560 draw.texture = gfx_display_white_texture;
561 draw.prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
562 draw.pipeline_id = 0;
563 draw.scale_factor = 1.0f;
564 draw.rotation = 0.0f;
565
566 if (dispctx->blend_begin)
567 dispctx->blend_begin(data);
568 if (dispctx->draw)
569 dispctx->draw(&draw, data, video_width, video_height);
570 if (dispctx->blend_end)
571 dispctx->blend_end(data);
572 }
573
gfx_display_draw_polygon(gfx_display_t * p_disp,void * userdata,unsigned video_width,unsigned video_height,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,unsigned width,unsigned height,float * color)574 void gfx_display_draw_polygon(
575 gfx_display_t *p_disp,
576 void *userdata,
577 unsigned video_width,
578 unsigned video_height,
579 int x1, int y1,
580 int x2, int y2,
581 int x3, int y3,
582 int x4, int y4,
583 unsigned width, unsigned height,
584 float *color)
585 {
586 float vertex[8];
587 gfx_display_ctx_draw_t draw;
588 struct video_coords coords;
589 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
590
591 if (width == 0 || height == 0)
592 return;
593 if (!dispctx)
594 return;
595
596 vertex[0] = x1 / (float)width;
597 vertex[1] = y1 / (float)height;
598 vertex[2] = x2 / (float)width;
599 vertex[3] = y2 / (float)height;
600 vertex[4] = x3 / (float)width;
601 vertex[5] = y3 / (float)height;
602 vertex[6] = x4 / (float)width;
603 vertex[7] = y4 / (float)height;
604
605 coords.vertices = 4;
606 coords.vertex = &vertex[0];
607 coords.tex_coord = NULL;
608 coords.lut_tex_coord = NULL;
609 coords.color = color;
610
611 draw.x = 0;
612 draw.y = 0;
613 draw.width = width;
614 draw.height = height;
615 draw.coords = &coords;
616 draw.matrix_data = NULL;
617 draw.texture = gfx_display_white_texture;
618 draw.prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
619 draw.pipeline_id = 0;
620 draw.scale_factor = 1.0f;
621 draw.rotation = 0.0f;
622
623 if (dispctx->blend_begin)
624 dispctx->blend_begin(userdata);
625 if (dispctx->draw)
626 dispctx->draw(&draw, userdata, video_width, video_height);
627 if (dispctx->blend_end)
628 dispctx->blend_end(userdata);
629 }
630
gfx_display_draw_texture(gfx_display_t * p_disp,gfx_display_ctx_driver_t * dispctx,void * userdata,unsigned video_width,unsigned video_height,int x,int y,unsigned w,unsigned h,unsigned width,unsigned height,float * color,uintptr_t texture,gfx_display_ctx_draw_t * draw)631 static void gfx_display_draw_texture(
632 gfx_display_t *p_disp,
633 gfx_display_ctx_driver_t *dispctx,
634 void *userdata,
635 unsigned video_width,
636 unsigned video_height,
637 int x, int y, unsigned w, unsigned h,
638 unsigned width, unsigned height,
639 float *color, uintptr_t texture,
640 gfx_display_ctx_draw_t *draw
641 )
642 {
643 if (w == 0 || h == 0)
644 return;
645 if (!dispctx || !dispctx->draw)
646 return;
647
648 draw->width = w;
649 draw->height = h;
650 draw->prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
651 draw->pipeline_id = 0;
652 draw->texture = texture;
653 draw->x = x;
654 draw->y = height - y;
655
656 dispctx->draw(draw, userdata, video_width, video_height);
657 }
658
659 /* Draw the texture split into 9 sections, without scaling the corners.
660 * The middle sections will only scale in the X axis, and the side
661 * sections will only scale in the Y axis. */
gfx_display_draw_texture_slice(gfx_display_t * p_disp,void * userdata,unsigned video_width,unsigned video_height,int x,int y,unsigned w,unsigned h,unsigned new_w,unsigned new_h,unsigned width,unsigned height,float * color,unsigned offset,float scale_factor,uintptr_t texture)662 void gfx_display_draw_texture_slice(
663 gfx_display_t *p_disp,
664 void *userdata,
665 unsigned video_width,
666 unsigned video_height,
667 int x, int y, unsigned w, unsigned h,
668 unsigned new_w, unsigned new_h,
669 unsigned width, unsigned height,
670 float *color, unsigned offset, float scale_factor, uintptr_t texture)
671 {
672 gfx_display_ctx_draw_t draw;
673 gfx_display_ctx_rotate_draw_t rotate_draw;
674 struct video_coords coords;
675 math_matrix_4x4 mymat;
676 gfx_display_ctx_driver_t
677 *dispctx = p_disp->dispctx;
678 float V_BL[2], V_BR[2], V_TL[2], V_TR[2], T_BL[2], T_BR[2], T_TL[2], T_TR[2];
679 /* To prevent visible seams between the corners and
680 * middle segments of the sliced texture, the texture
681 * must be scaled such that its effective size (before
682 * expansion of the middle segments) is no greater than
683 * the requested display size.
684 * > This is consequence of the way textures are rendered
685 * in hardware...
686 * > Whenever an image is scaled, the colours at the
687 * transparent edges get interpolated, which means
688 * the colours of the transparent pixels themselves bleed
689 * into the visible area.
690 * > This effectively 'blurs' anything that gets scaled
691 * [SIDE NOTE: this causes additional issues if the transparent
692 * pixels have the wrong colour - i.e. if they are black,
693 * every edge gets a nasty dark border...]
694 * > This burring is a problem because (by design) the corners
695 * of the sliced texture are drawn at native resolution,
696 * whereas the middle segments are stretched to fit the
697 * requested dimensions. Consequently, the corners are sharp
698 * while the middle segments are blurred.
699 * > When *upscaling* the middle segments (i.e. display size
700 * greater than texture size), the visible effects of this
701 * are mostly imperceptible.
702 * > When *downscaling* them, however, the interpolation effects
703 * completely dominate the output image - creating an ugly
704 * transition between the corners and middle parts.
705 * > Since this is a property of hardware rendering, it is not
706 * practical to fix this 'properly'...
707 * > However: An effective workaround is to force downscaling of
708 * the entire texture (including corners) whenever the
709 * requested display size is less than the texture dimensions.
710 * > This blurs the corners enough that the corner/middle
711 * transitions are essentially invisible. */
712 float max_scale_w = (float)new_w / (float)w;
713 float max_scale_h = (float)new_h / (float)h;
714 /* Find the minimum of scale_factor, max_scale_w, max_scale_h */
715 float slice_scale = (scale_factor < max_scale_w) ?
716 (scale_factor < max_scale_h) ? scale_factor : max_scale_h :
717 (max_scale_w < max_scale_h) ? max_scale_w : max_scale_h;
718
719 /* need space for the coordinates of two triangles in a strip,
720 * so 8 vertices */
721 float tex_coord[8];
722 float vert_coord[8];
723 static float colors[16] = {
724 1.0f, 1.0f, 1.0f, 1.0f,
725 1.0f, 1.0f, 1.0f, 1.0f,
726 1.0f, 1.0f, 1.0f, 1.0f,
727 1.0f, 1.0f, 1.0f, 1.0f
728 };
729
730 /* normalized width/height of the amount to offset from the corners,
731 * for both the vertex and texture coordinates */
732 float vert_woff = (offset * slice_scale) / (float)width;
733 float vert_hoff = (offset * slice_scale) / (float)height;
734 float tex_woff = offset / (float)w;
735 float tex_hoff = offset / (float)h;
736
737 /* the width/height of the middle sections of both the scaled and original image */
738 float vert_scaled_mid_width = (new_w - (offset * slice_scale * 2))
739 / (float)width;
740 float vert_scaled_mid_height = (new_h - (offset * slice_scale * 2))
741 / (float)height;
742 float tex_mid_width = (w - (offset * 2)) / (float)w;
743 float tex_mid_height = (h - (offset * 2)) / (float)h;
744
745 /* normalized coordinates for the start position of the image */
746 float norm_x = x / (float)width;
747 float norm_y = (height - y) / (float)height;
748
749 if (width == 0 || height == 0)
750 return;
751 if (!dispctx || !dispctx->draw)
752 return;
753
754 /* the four vertices of the top-left corner of the image,
755 * used as a starting point for all the other sections */
756 V_BL[0] = norm_x;
757 V_BL[1] = norm_y;
758 V_BR[0] = norm_x + vert_woff;
759 V_BR[1] = norm_y;
760 V_TL[0] = norm_x;
761 V_TL[1] = norm_y + vert_hoff;
762 V_TR[0] = norm_x + vert_woff;
763 V_TR[1] = norm_y + vert_hoff;
764 T_BL[0] = 0.0f;
765 T_BL[1] = tex_hoff;
766 T_BR[0] = tex_woff;
767 T_BR[1] = tex_hoff;
768 T_TL[0] = 0.0f;
769 T_TL[1] = 0.0f;
770 T_TR[0] = tex_woff;
771 T_TR[1] = 0.0f;
772
773 rotate_draw.matrix = &mymat;
774 rotate_draw.rotation = 0.0;
775 rotate_draw.scale_x = 1.0;
776 rotate_draw.scale_y = 1.0;
777 rotate_draw.scale_z = 1;
778 rotate_draw.scale_enable = true;
779 coords.vertices = 4;
780 coords.vertex = vert_coord;
781 coords.tex_coord = tex_coord;
782 coords.lut_tex_coord = NULL;
783 draw.width = width;
784 draw.height = height;
785 draw.coords = &coords;
786 draw.matrix_data = &mymat;
787 draw.prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
788 draw.pipeline_id = 0;
789 coords.color = (const float*)(color == NULL ? colors : color);
790
791 gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
792
793 draw.texture = texture;
794 draw.x = 0;
795 draw.y = 0;
796
797 /* vertex coords are specfied bottom-up in this order: BL BR TL TR */
798 /* texture coords are specfied top-down in this order: BL BR TL TR */
799
800 /* If someone wants to change this to not draw several times, the
801 * coordinates will need to be modified because of the triangle strip usage. */
802
803 /* top-left corner */
804 vert_coord[0] = V_BL[0];
805 vert_coord[1] = V_BL[1];
806 vert_coord[2] = V_BR[0];
807 vert_coord[3] = V_BR[1];
808 vert_coord[4] = V_TL[0];
809 vert_coord[5] = V_TL[1];
810 vert_coord[6] = V_TR[0];
811 vert_coord[7] = V_TR[1];
812
813 tex_coord[0] = T_BL[0];
814 tex_coord[1] = T_BL[1];
815 tex_coord[2] = T_BR[0];
816 tex_coord[3] = T_BR[1];
817 tex_coord[4] = T_TL[0];
818 tex_coord[5] = T_TL[1];
819 tex_coord[6] = T_TR[0];
820 tex_coord[7] = T_TR[1];
821
822 dispctx->draw(&draw, userdata, video_width, video_height);
823
824 /* top-middle section */
825 vert_coord[0] = V_BL[0] + vert_woff;
826 vert_coord[1] = V_BL[1];
827 vert_coord[2] = V_BR[0] + vert_scaled_mid_width;
828 vert_coord[3] = V_BR[1];
829 vert_coord[4] = V_TL[0] + vert_woff;
830 vert_coord[5] = V_TL[1];
831 vert_coord[6] = V_TR[0] + vert_scaled_mid_width;
832 vert_coord[7] = V_TR[1];
833
834 tex_coord[0] = T_BL[0] + tex_woff;
835 tex_coord[1] = T_BL[1];
836 tex_coord[2] = T_BR[0] + tex_mid_width;
837 tex_coord[3] = T_BR[1];
838 tex_coord[4] = T_TL[0] + tex_woff;
839 tex_coord[5] = T_TL[1];
840 tex_coord[6] = T_TR[0] + tex_mid_width;
841 tex_coord[7] = T_TR[1];
842
843 dispctx->draw(&draw, userdata, video_width, video_height);
844
845 /* top-right corner */
846 vert_coord[0] = V_BL[0] + vert_woff + vert_scaled_mid_width;
847 vert_coord[1] = V_BL[1];
848 vert_coord[2] = V_BR[0] + vert_scaled_mid_width + vert_woff;
849 vert_coord[3] = V_BR[1];
850 vert_coord[4] = V_TL[0] + vert_woff + vert_scaled_mid_width;
851 vert_coord[5] = V_TL[1];
852 vert_coord[6] = V_TR[0] + vert_scaled_mid_width + vert_woff;
853 vert_coord[7] = V_TR[1];
854
855 tex_coord[0] = T_BL[0] + tex_woff + tex_mid_width;
856 tex_coord[1] = T_BL[1];
857 tex_coord[2] = T_BR[0] + tex_mid_width + tex_woff;
858 tex_coord[3] = T_BR[1];
859 tex_coord[4] = T_TL[0] + tex_woff + tex_mid_width;
860 tex_coord[5] = T_TL[1];
861 tex_coord[6] = T_TR[0] + tex_mid_width + tex_woff;
862 tex_coord[7] = T_TR[1];
863
864 dispctx->draw(&draw, userdata, video_width, video_height);
865
866 /* middle-left section */
867 vert_coord[0] = V_BL[0];
868 vert_coord[1] = V_BL[1] - vert_scaled_mid_height;
869 vert_coord[2] = V_BR[0];
870 vert_coord[3] = V_BR[1] - vert_scaled_mid_height;
871 vert_coord[4] = V_TL[0];
872 vert_coord[5] = V_TL[1] - vert_hoff;
873 vert_coord[6] = V_TR[0];
874 vert_coord[7] = V_TR[1] - vert_hoff;
875
876 tex_coord[0] = T_BL[0];
877 tex_coord[1] = T_BL[1] + tex_mid_height;
878 tex_coord[2] = T_BR[0];
879 tex_coord[3] = T_BR[1] + tex_mid_height;
880 tex_coord[4] = T_TL[0];
881 tex_coord[5] = T_TL[1] + tex_hoff;
882 tex_coord[6] = T_TR[0];
883 tex_coord[7] = T_TR[1] + tex_hoff;
884
885 dispctx->draw(&draw, userdata, video_width, video_height);
886
887 /* center section */
888 vert_coord[0] = V_BL[0] + vert_woff;
889 vert_coord[1] = V_BL[1] - vert_scaled_mid_height;
890 vert_coord[2] = V_BR[0] + vert_scaled_mid_width;
891 vert_coord[3] = V_BR[1] - vert_scaled_mid_height;
892 vert_coord[4] = V_TL[0] + vert_woff;
893 vert_coord[5] = V_TL[1] - vert_hoff;
894 vert_coord[6] = V_TR[0] + vert_scaled_mid_width;
895 vert_coord[7] = V_TR[1] - vert_hoff;
896
897 tex_coord[0] = T_BL[0] + tex_woff;
898 tex_coord[1] = T_BL[1] + tex_mid_height;
899 tex_coord[2] = T_BR[0] + tex_mid_width;
900 tex_coord[3] = T_BR[1] + tex_mid_height;
901 tex_coord[4] = T_TL[0] + tex_woff;
902 tex_coord[5] = T_TL[1] + tex_hoff;
903 tex_coord[6] = T_TR[0] + tex_mid_width;
904 tex_coord[7] = T_TR[1] + tex_hoff;
905
906 dispctx->draw(&draw, userdata, video_width, video_height);
907
908 /* middle-right section */
909 vert_coord[0] = V_BL[0] + vert_woff + vert_scaled_mid_width;
910 vert_coord[1] = V_BL[1] - vert_scaled_mid_height;
911 vert_coord[2] = V_BR[0] + vert_woff + vert_scaled_mid_width;
912 vert_coord[3] = V_BR[1] - vert_scaled_mid_height;
913 vert_coord[4] = V_TL[0] + vert_woff + vert_scaled_mid_width;
914 vert_coord[5] = V_TL[1] - vert_hoff;
915 vert_coord[6] = V_TR[0] + vert_woff + vert_scaled_mid_width;
916 vert_coord[7] = V_TR[1] - vert_hoff;
917
918 tex_coord[0] = T_BL[0] + tex_woff + tex_mid_width;
919 tex_coord[1] = T_BL[1] + tex_mid_height;
920 tex_coord[2] = T_BR[0] + tex_woff + tex_mid_width;
921 tex_coord[3] = T_BR[1] + tex_mid_height;
922 tex_coord[4] = T_TL[0] + tex_woff + tex_mid_width;
923 tex_coord[5] = T_TL[1] + tex_hoff;
924 tex_coord[6] = T_TR[0] + tex_woff + tex_mid_width;
925 tex_coord[7] = T_TR[1] + tex_hoff;
926
927 dispctx->draw(&draw, userdata, video_width, video_height);
928
929 /* bottom-left corner */
930 vert_coord[0] = V_BL[0];
931 vert_coord[1] = V_BL[1] - vert_hoff - vert_scaled_mid_height;
932 vert_coord[2] = V_BR[0];
933 vert_coord[3] = V_BR[1] - vert_hoff - vert_scaled_mid_height;
934 vert_coord[4] = V_TL[0];
935 vert_coord[5] = V_TL[1] - vert_hoff - vert_scaled_mid_height;
936 vert_coord[6] = V_TR[0];
937 vert_coord[7] = V_TR[1] - vert_hoff - vert_scaled_mid_height;
938
939 tex_coord[0] = T_BL[0];
940 tex_coord[1] = T_BL[1] + tex_hoff + tex_mid_height;
941 tex_coord[2] = T_BR[0];
942 tex_coord[3] = T_BR[1] + tex_hoff + tex_mid_height;
943 tex_coord[4] = T_TL[0];
944 tex_coord[5] = T_TL[1] + tex_hoff + tex_mid_height;
945 tex_coord[6] = T_TR[0];
946 tex_coord[7] = T_TR[1] + tex_hoff + tex_mid_height;
947
948 dispctx->draw(&draw, userdata, video_width, video_height);
949
950 /* bottom-middle section */
951 vert_coord[0] = V_BL[0] + vert_woff;
952 vert_coord[1] = V_BL[1] - vert_hoff - vert_scaled_mid_height;
953 vert_coord[2] = V_BR[0] + vert_scaled_mid_width;
954 vert_coord[3] = V_BR[1] - vert_hoff - vert_scaled_mid_height;
955 vert_coord[4] = V_TL[0] + vert_woff;
956 vert_coord[5] = V_TL[1] - vert_hoff - vert_scaled_mid_height;
957 vert_coord[6] = V_TR[0] + vert_scaled_mid_width;
958 vert_coord[7] = V_TR[1] - vert_hoff - vert_scaled_mid_height;
959
960 tex_coord[0] = T_BL[0] + tex_woff;
961 tex_coord[1] = T_BL[1] + tex_hoff + tex_mid_height;
962 tex_coord[2] = T_BR[0] + tex_mid_width;
963 tex_coord[3] = T_BR[1] + tex_hoff + tex_mid_height;
964 tex_coord[4] = T_TL[0] + tex_woff;
965 tex_coord[5] = T_TL[1] + tex_hoff + tex_mid_height;
966 tex_coord[6] = T_TR[0] + tex_mid_width;
967 tex_coord[7] = T_TR[1] + tex_hoff + tex_mid_height;
968
969 dispctx->draw(&draw, userdata, video_width, video_height);
970
971 /* bottom-right corner */
972 vert_coord[0] = V_BL[0] + vert_woff + vert_scaled_mid_width;
973 vert_coord[1] = V_BL[1] - vert_hoff - vert_scaled_mid_height;
974 vert_coord[2] = V_BR[0] + vert_scaled_mid_width + vert_woff;
975 vert_coord[3] = V_BR[1] - vert_hoff - vert_scaled_mid_height;
976 vert_coord[4] = V_TL[0] + vert_woff + vert_scaled_mid_width;
977 vert_coord[5] = V_TL[1] - vert_hoff - vert_scaled_mid_height;
978 vert_coord[6] = V_TR[0] + vert_scaled_mid_width + vert_woff;
979 vert_coord[7] = V_TR[1] - vert_hoff - vert_scaled_mid_height;
980
981 tex_coord[0] = T_BL[0] + tex_woff + tex_mid_width;
982 tex_coord[1] = T_BL[1] + tex_hoff + tex_mid_height;
983 tex_coord[2] = T_BR[0] + tex_woff + tex_mid_width;
984 tex_coord[3] = T_BR[1] + tex_hoff + tex_mid_height;
985 tex_coord[4] = T_TL[0] + tex_woff + tex_mid_width;
986 tex_coord[5] = T_TL[1] + tex_hoff + tex_mid_height;
987 tex_coord[6] = T_TR[0] + tex_woff + tex_mid_width;
988 tex_coord[7] = T_TR[1] + tex_hoff + tex_mid_height;
989
990 dispctx->draw(&draw, userdata, video_width, video_height);
991 }
992
gfx_display_rotate_z(gfx_display_t * p_disp,gfx_display_ctx_rotate_draw_t * draw,void * data)993 void gfx_display_rotate_z(gfx_display_t *p_disp,
994 gfx_display_ctx_rotate_draw_t *draw, void *data)
995 {
996 math_matrix_4x4 matrix_rotated, matrix_scaled;
997 math_matrix_4x4 *b = NULL;
998 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
999
1000 if (
1001 !draw ||
1002 !dispctx ||
1003 !dispctx->get_default_mvp ||
1004 dispctx->handles_transform
1005 )
1006 return;
1007
1008 b = (math_matrix_4x4*)dispctx->get_default_mvp(data);
1009
1010 if (!b)
1011 return;
1012
1013 matrix_4x4_rotate_z(matrix_rotated, draw->rotation);
1014 matrix_4x4_multiply(*draw->matrix, matrix_rotated, *b);
1015
1016 if (!draw->scale_enable)
1017 return;
1018
1019 matrix_4x4_scale(matrix_scaled,
1020 draw->scale_x, draw->scale_y, draw->scale_z);
1021 matrix_4x4_multiply(*draw->matrix, matrix_scaled, *draw->matrix);
1022 }
1023
1024 /*
1025 * Draw a hardware cursor on top of the screen for the mouse.
1026 */
gfx_display_draw_cursor(gfx_display_t * p_disp,void * userdata,unsigned video_width,unsigned video_height,bool cursor_visible,float * color,float cursor_size,uintptr_t texture,float x,float y,unsigned width,unsigned height)1027 void gfx_display_draw_cursor(
1028 gfx_display_t *p_disp,
1029 void *userdata,
1030 unsigned video_width,
1031 unsigned video_height,
1032 bool cursor_visible,
1033 float *color, float cursor_size, uintptr_t texture,
1034 float x, float y, unsigned width, unsigned height)
1035 {
1036 gfx_display_ctx_draw_t draw;
1037 struct video_coords coords;
1038 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
1039
1040 if (!dispctx)
1041 return;
1042
1043 coords.vertices = 4;
1044 coords.vertex = NULL;
1045 coords.tex_coord = NULL;
1046 coords.lut_tex_coord = NULL;
1047 coords.color = (const float*)color;
1048
1049 draw.x = x - (cursor_size / 2);
1050 draw.y = (int)height - y - (cursor_size / 2);
1051 draw.width = cursor_size;
1052 draw.height = cursor_size;
1053 draw.coords = &coords;
1054 draw.matrix_data = NULL;
1055 draw.texture = texture;
1056 draw.prim_type = GFX_DISPLAY_PRIM_TRIANGLESTRIP;
1057 draw.pipeline_id = 0;
1058 draw.scale_factor = 1.0f;
1059 draw.rotation = 0.0f;
1060
1061 if (dispctx->blend_begin)
1062 dispctx->blend_begin(userdata);
1063 if (dispctx->draw)
1064 dispctx->draw(&draw, userdata, video_width, video_height);
1065 if (dispctx->blend_end)
1066 dispctx->blend_end(userdata);
1067 }
1068
1069 /* Setup: Initializes the font associated
1070 * to the menu driver */
gfx_display_font(gfx_display_t * p_disp,enum application_special_type type,float menu_font_size,bool is_threaded)1071 font_data_t *gfx_display_font(
1072 gfx_display_t *p_disp,
1073 enum application_special_type type,
1074 float menu_font_size,
1075 bool is_threaded)
1076 {
1077 char fontpath[PATH_MAX_LENGTH];
1078
1079 fontpath[0] = '\0';
1080
1081 fill_pathname_application_special(
1082 fontpath, sizeof(fontpath), type);
1083
1084 return gfx_display_font_file(p_disp, fontpath, menu_font_size, is_threaded);
1085 }
1086
1087 /* Returns the OSK key at a given position */
gfx_display_osk_ptr_at_pos(void * data,int x,int y,unsigned width,unsigned height)1088 int gfx_display_osk_ptr_at_pos(void *data, int x, int y,
1089 unsigned width, unsigned height)
1090 {
1091 unsigned i;
1092 int ptr_width = width / 11;
1093 int ptr_height = height / 10;
1094
1095 if (ptr_width >= ptr_height)
1096 ptr_width = ptr_height;
1097
1098 for (i = 0; i < 44; i++)
1099 {
1100 int line_y = (i / 11)*height/10.0;
1101 int ptr_x = width/2.0 - (11*ptr_width)/2.0 + (i % 11) * ptr_width;
1102 int ptr_y = height/2.0 + ptr_height*1.5 + line_y - ptr_height;
1103
1104 if (x > ptr_x && x < ptr_x + ptr_width
1105 && y > ptr_y && y < ptr_y + ptr_height)
1106 return i;
1107 }
1108
1109 return -1;
1110 }
1111
1112 /* Get the display framebuffer's size dimensions. */
gfx_display_get_fb_size(unsigned * fb_width,unsigned * fb_height,size_t * fb_pitch)1113 void gfx_display_get_fb_size(unsigned *fb_width,
1114 unsigned *fb_height, size_t *fb_pitch)
1115 {
1116 gfx_display_t *p_disp = disp_get_ptr();
1117 *fb_width = p_disp->framebuf_width;
1118 *fb_height = p_disp->framebuf_height;
1119 *fb_pitch = p_disp->framebuf_pitch;
1120 }
1121
1122 /* Set the display framebuffer's width. */
gfx_display_set_width(unsigned width)1123 void gfx_display_set_width(unsigned width)
1124 {
1125 gfx_display_t *p_disp = disp_get_ptr();
1126 p_disp->framebuf_width = width;
1127 }
1128
1129 /* Set the display framebuffer's height. */
gfx_display_set_height(unsigned height)1130 void gfx_display_set_height(unsigned height)
1131 {
1132 gfx_display_t *p_disp = disp_get_ptr();
1133 p_disp->framebuf_height = height;
1134 }
1135
gfx_display_set_framebuffer_pitch(size_t pitch)1136 void gfx_display_set_framebuffer_pitch(size_t pitch)
1137 {
1138 gfx_display_t *p_disp = disp_get_ptr();
1139 p_disp->framebuf_pitch = pitch;
1140 }
1141
gfx_display_set_msg_force(bool state)1142 void gfx_display_set_msg_force(bool state)
1143 {
1144 gfx_display_t *p_disp = disp_get_ptr();
1145 p_disp->msg_force = state;
1146 }
1147
gfx_display_draw_keyboard(gfx_display_t * p_disp,void * userdata,unsigned video_width,unsigned video_height,uintptr_t hover_texture,const font_data_t * font,char * grid[],unsigned id,unsigned text_color)1148 void gfx_display_draw_keyboard(
1149 gfx_display_t *p_disp,
1150 void *userdata,
1151 unsigned video_width,
1152 unsigned video_height,
1153 uintptr_t hover_texture,
1154 const font_data_t *font,
1155 char *grid[], unsigned id,
1156 unsigned text_color)
1157 {
1158 unsigned i;
1159 int ptr_width, ptr_height;
1160 gfx_display_ctx_driver_t *dispctx = p_disp->dispctx;
1161
1162 static float white[16] = {
1163 1.00, 1.00, 1.00, 1.00,
1164 1.00, 1.00, 1.00, 1.00,
1165 1.00, 1.00, 1.00, 1.00,
1166 1.00, 1.00, 1.00, 1.00,
1167 };
1168 static float osk_dark[16] = {
1169 0.00, 0.00, 0.00, 0.85,
1170 0.00, 0.00, 0.00, 0.85,
1171 0.00, 0.00, 0.00, 0.85,
1172 0.00, 0.00, 0.00, 0.85,
1173 };
1174 struct video_coords coords;
1175 gfx_display_ctx_draw_t draw;
1176 math_matrix_4x4 mymat;
1177 gfx_display_ctx_rotate_draw_t rotate_draw;
1178 rotate_draw.matrix = &mymat;
1179 rotate_draw.rotation = 0.0;
1180 rotate_draw.scale_x = 1.0;
1181 rotate_draw.scale_y = 1.0;
1182 rotate_draw.scale_z = 1;
1183 rotate_draw.scale_enable = true;
1184
1185 coords.vertices = 4;
1186 coords.vertex = NULL;
1187 coords.tex_coord = NULL;
1188 coords.lut_tex_coord = NULL;
1189 coords.color = (const float*)&white[0];
1190
1191 gfx_display_draw_quad(
1192 p_disp,
1193 userdata,
1194 video_width,
1195 video_height,
1196 0,
1197 video_height / 2.0,
1198 video_width,
1199 video_height / 2.0,
1200 video_width,
1201 video_height,
1202 &osk_dark[0]);
1203
1204 ptr_width = video_width / 11;
1205 ptr_height = video_height / 10;
1206
1207 if (ptr_width >= ptr_height)
1208 ptr_width = ptr_height;
1209
1210 gfx_display_rotate_z(p_disp, &rotate_draw, userdata);
1211
1212 draw.coords = &coords;
1213 draw.matrix_data = &mymat;
1214
1215 for (i = 0; i < 44; i++)
1216 {
1217 int line_y = (i / 11) * video_height / 10.0;
1218 unsigned color = 0xffffffff;
1219
1220 if (i == id)
1221 {
1222 if (dispctx && dispctx->blend_begin)
1223 dispctx->blend_begin(userdata);
1224
1225 gfx_display_draw_texture(
1226 p_disp,
1227 dispctx,
1228 userdata,
1229 video_width,
1230 video_height,
1231 video_width / 2.0 - (11 * ptr_width) / 2.0 + (i % 11)
1232 * ptr_width,
1233 video_height / 2.0 + ptr_height * 1.5 + line_y,
1234 ptr_width, ptr_height,
1235 video_width,
1236 video_height,
1237 &white[0],
1238 hover_texture,
1239 &draw
1240 );
1241
1242 if (dispctx && dispctx->blend_end)
1243 dispctx->blend_end(userdata);
1244
1245 color = text_color;
1246 }
1247
1248 gfx_display_draw_text(font, grid[i],
1249 video_width/2.0 - (11*ptr_width)/2.0 + (i % 11)
1250 * ptr_width + ptr_width/2.0,
1251 video_height / 2.0 + ptr_height + line_y + font->size / 3,
1252 video_width,
1253 video_height,
1254 color,
1255 TEXT_ALIGN_CENTER,
1256 1.0f,
1257 false, 0, false);
1258 }
1259 }
1260
1261 /* NOTE: Reads image from file */
gfx_display_reset_textures_list(const char * texture_path,const char * iconpath,uintptr_t * item,enum texture_filter_type filter_type,unsigned * width,unsigned * height)1262 bool gfx_display_reset_textures_list(
1263 const char *texture_path, const char *iconpath,
1264 uintptr_t *item, enum texture_filter_type filter_type,
1265 unsigned *width, unsigned *height)
1266 {
1267 char texpath[PATH_MAX_LENGTH];
1268 struct texture_image ti;
1269
1270 texpath[0] = '\0';
1271
1272 ti.width = 0;
1273 ti.height = 0;
1274 ti.pixels = NULL;
1275 ti.supports_rgba = video_driver_supports_rgba();
1276
1277 if (string_is_empty(texture_path))
1278 return false;
1279
1280 fill_pathname_join(texpath, iconpath, texture_path, sizeof(texpath));
1281
1282 if (!image_texture_load(&ti, texpath))
1283 return false;
1284
1285 if (width)
1286 *width = ti.width;
1287
1288 if (height)
1289 *height = ti.height;
1290
1291 video_driver_texture_load(&ti,
1292 filter_type, item);
1293 image_texture_free(&ti);
1294
1295 return true;
1296 }
1297
1298 /* Teardown; deinitializes and frees all
1299 * fonts associated to the display driver */
gfx_display_font_free(font_data_t * font)1300 void gfx_display_font_free(font_data_t *font)
1301 {
1302 font_driver_free(font);
1303 }
1304
gfx_display_init_white_texture(uintptr_t white_texture)1305 void gfx_display_init_white_texture(uintptr_t white_texture)
1306 {
1307 struct texture_image ti;
1308 static const uint8_t white_data[] = { 0xff, 0xff, 0xff, 0xff };
1309
1310 ti.width = 1;
1311 ti.height = 1;
1312 ti.pixels = (uint32_t*)&white_data;
1313
1314 video_driver_texture_load(&ti,
1315 TEXTURE_FILTER_NEAREST, &gfx_display_white_texture);
1316 }
1317
gfx_display_free(void)1318 void gfx_display_free(void)
1319 {
1320 gfx_display_t *p_disp = disp_get_ptr();
1321 video_coord_array_free(&p_disp->dispca);
1322
1323 p_disp->msg_force = false;
1324 p_disp->header_height = 0;
1325 p_disp->framebuf_width = 0;
1326 p_disp->framebuf_height = 0;
1327 p_disp->framebuf_pitch = 0;
1328 p_disp->has_windowed = false;
1329 p_disp->dispctx = NULL;
1330 }
1331
gfx_display_init(void)1332 void gfx_display_init(void)
1333 {
1334 gfx_display_t *p_disp = disp_get_ptr();
1335 video_coord_array_t *p_dispca = &p_disp->dispca;
1336
1337 p_disp->has_windowed = video_driver_has_windowed();
1338 p_dispca->allocated = 0;
1339 }
1340
gfx_display_driver_exists(const char * s)1341 bool gfx_display_driver_exists(const char *s)
1342 {
1343 unsigned i;
1344 for (i = 0; i < ARRAY_SIZE(gfx_display_ctx_drivers); i++)
1345 {
1346 if (string_is_equal(s, gfx_display_ctx_drivers[i]->ident))
1347 return true;
1348 }
1349
1350 return false;
1351 }
1352
gfx_display_init_first_driver(gfx_display_t * p_disp,bool video_is_threaded)1353 bool gfx_display_init_first_driver(gfx_display_t *p_disp,
1354 bool video_is_threaded)
1355 {
1356 unsigned i;
1357
1358 for (i = 0; gfx_display_ctx_drivers[i]; i++)
1359 {
1360 if (!gfx_display_check_compatibility(
1361 gfx_display_ctx_drivers[i]->type,
1362 video_is_threaded))
1363 continue;
1364
1365 RARCH_LOG("[Display]: Found display driver: \"%s\".\n",
1366 gfx_display_ctx_drivers[i]->ident);
1367 p_disp->dispctx = gfx_display_ctx_drivers[i];
1368 return true;
1369 }
1370 return false;
1371 }
1372