1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2018      - natinusala
3  *
4  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
5  *  of the GNU General Public License as published by the Free Software Found-
6  *  ation, either version 3 of the License, or (at your option) any later version.
7  *
8  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10  *  PURPOSE.  See the GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License along with RetroArch.
13  *  If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 #ifndef _GFX_WIDGETS_H
17 #define _GFX_WIDGETS_H
18 
19 #ifdef HAVE_CONFIG_H
20 #include "../config.h"
21 #endif
22 
23 #include <formats/image.h>
24 #include <queues/task_queue.h>
25 #include <queues/message_queue.h>
26 #include <queues/fifo_queue.h>
27 
28 #ifdef HAVE_THREADS
29 #include <rthreads/rthreads.h>
30 #endif
31 
32 #include "gfx_animation.h"
33 #include "gfx_display.h"
34 
35 #define DEFAULT_BACKDROP               0.75f
36 
37 #define MSG_QUEUE_PENDING_MAX          32
38 #define MSG_QUEUE_ONSCREEN_MAX         4
39 
40 #define MSG_QUEUE_ANIMATION_DURATION      330
41 #define TASK_FINISHED_DURATION            3000
42 #define HOURGLASS_INTERVAL                5000
43 #define HOURGLASS_DURATION                1000
44 
45 /* TODO: Colors for warning, error and success */
46 
47 #define TEXT_COLOR_INFO 0xD8EEFFFF
48 #if 0
49 #define TEXT_COLOR_SUCCESS 0x22B14CFF
50 #define TEXT_COLOR_ERROR 0xC23B22FF
51 #endif
52 #define TEXT_COLOR_FAINT 0x878787FF
53 
54 enum gfx_widgets_icon
55 {
56    MENU_WIDGETS_ICON_PAUSED = 0,
57    MENU_WIDGETS_ICON_FAST_FORWARD,
58    MENU_WIDGETS_ICON_REWIND,
59    MENU_WIDGETS_ICON_SLOW_MOTION,
60 
61    MENU_WIDGETS_ICON_HOURGLASS,
62    MENU_WIDGETS_ICON_CHECK,
63 
64    MENU_WIDGETS_ICON_INFO,
65 
66    MENU_WIDGETS_ICON_ACHIEVEMENT,
67 
68    MENU_WIDGETS_ICON_LAST
69 };
70 
71 enum notification_show_screenshot_duration
72 {
73    NOTIFICATION_SHOW_SCREENSHOT_DURATION_NORMAL = 0,
74    NOTIFICATION_SHOW_SCREENSHOT_DURATION_FAST,
75    NOTIFICATION_SHOW_SCREENSHOT_DURATION_VERY_FAST,
76    NOTIFICATION_SHOW_SCREENSHOT_DURATION_INSTANT,
77    NOTIFICATION_SHOW_SCREENSHOT_DURATION_LAST
78 };
79 
80 enum notification_show_screenshot_flash
81 {
82    NOTIFICATION_SHOW_SCREENSHOT_FLASH_NORMAL = 0,
83    NOTIFICATION_SHOW_SCREENSHOT_FLASH_FAST,
84    NOTIFICATION_SHOW_SCREENSHOT_FLASH_OFF,
85    NOTIFICATION_SHOW_SCREENSHOT_FLASH_LAST
86 };
87 
88 /* This structure holds all objects + metadata
89  * corresponding to a particular font */
90 typedef struct
91 {
92    font_data_t *font;
93    video_font_raster_block_t raster_block; /* ptr alignment */
94    size_t usage_count;
95    unsigned glyph_width;
96    float line_height;
97    float line_ascender;
98    float line_descender;
99    float line_centre_offset;
100 } gfx_widget_font_data_t;
101 
102 /* Font data */
103 typedef struct
104 {
105    gfx_widget_font_data_t regular;
106    gfx_widget_font_data_t bold;
107    gfx_widget_font_data_t msg_queue;
108 } gfx_widget_fonts_t;
109 
110 typedef struct cheevo_popup
111 {
112    char* title;
113    uintptr_t badge;
114 } cheevo_popup;
115 
116 typedef struct disp_widget_msg
117 {
118    char *msg;
119    char *msg_new;
120    retro_task_t *task_ptr;
121    /* Used to detect title change */
122    char *task_title_ptr;
123 
124    uint32_t task_ident;
125    unsigned msg_len;
126    unsigned duration;
127    unsigned text_height;
128    unsigned width;
129 
130    float msg_transition_animation;
131    float offset_y;
132    float alpha;
133    float unfold;
134    float hourglass_rotation;
135    gfx_timer_t hourglass_timer; /* float alignment */
136    gfx_timer_t expiration_timer; /* float alignment */
137 
138    int8_t task_progress;
139    /* How many tasks have used this notification? */
140    uint8_t task_count;
141 
142    bool task_finished;
143    bool task_error;
144    bool task_cancelled;
145    bool expiration_timer_started;
146    /* Is it currently doing the fade out animation ? */
147    bool dying;
148    /* Has the timer expired ? if so, should be set to dying */
149    bool expired;
150    /* Unfold animation */
151    bool unfolded;
152    bool unfolding;
153 } disp_widget_msg_t;
154 
155 typedef struct dispgfx_widget
156 {
157    uint64_t gfx_widgets_frame_count;
158 
159 #ifdef HAVE_THREADS
160    slock_t* current_msgs_lock;
161 #endif
162    fifo_buffer_t msg_queue;
163    disp_widget_msg_t* current_msgs[MSG_QUEUE_ONSCREEN_MAX];
164    gfx_widget_fonts_t gfx_widget_fonts; /* ptr alignment */
165 
166 #ifdef HAVE_TRANSLATE
167    uintptr_t ai_service_overlay_texture;
168 #endif
169    uintptr_t msg_queue_icon;
170    uintptr_t msg_queue_icon_outline;
171    uintptr_t msg_queue_icon_rect;
172    uintptr_t gfx_widgets_icons_textures[
173    MENU_WIDGETS_ICON_LAST];
174    uintptr_t gfx_widgets_generic_tag;
175 
176    size_t current_msgs_size;
177 
178 #ifdef HAVE_TRANSLATE
179    int ai_service_overlay_state;
180 #endif
181 
182    unsigned last_video_width;
183    unsigned last_video_height;
184    unsigned msg_queue_kill;
185    /* Count of messages bound to a task in current_msgs */
186    unsigned msg_queue_tasks_count;
187 
188    unsigned simple_widget_padding;
189    unsigned simple_widget_height;
190 
191    /* Used for both generic and libretro messages */
192    unsigned generic_message_height;
193 
194    unsigned msg_queue_height;
195    unsigned msg_queue_spacing;
196    unsigned msg_queue_rect_start_x;
197    unsigned msg_queue_internal_icon_size;
198    unsigned msg_queue_internal_icon_offset;
199    unsigned msg_queue_icon_size_x;
200    unsigned msg_queue_icon_size_y;
201    unsigned msg_queue_icon_offset_y;
202    unsigned msg_queue_scissor_start_x;
203    unsigned msg_queue_default_rect_width_menu_alive;
204    unsigned msg_queue_default_rect_width;
205    unsigned msg_queue_regular_padding_x;
206    unsigned msg_queue_regular_text_start;
207    unsigned msg_queue_task_text_start_x;
208    unsigned msg_queue_task_rect_start_x;
209    unsigned msg_queue_task_hourglass_x;
210    unsigned divider_width_1px;
211 
212    float last_scale_factor;
213    float backdrop_orig[16];
214    float msg_queue_bg[16];
215    float pure_white[16];
216 #ifdef HAVE_TRANSLATE
217    unsigned ai_service_overlay_width;
218    unsigned ai_service_overlay_height;
219 #endif
220 
221    char gfx_widgets_status_text[255];
222 
223    /* There can only be one message animation at a time to
224     * avoid confusing users */
225    bool widgets_moving;
226    bool widgets_inited;
227    bool msg_queue_has_icons;
228 } dispgfx_widget_t;
229 
230 
231 /* A widget */
232 /* TODO: cleanup all unused parameters */
233 struct gfx_widget
234 {
235    /* called when the widgets system is initialized
236     * -> initialize the widget here */
237    bool (*init)(gfx_display_t *p_disp,
238          gfx_animation_t *p_anim,
239          bool video_is_threaded, bool fullscreen);
240 
241    /* called when the widgets system is freed
242     * -> free the widget here */
243    void (*free)(void);
244 
245    /* called when the graphics context is reset
246     * -> (re)load the textures here */
247    void (*context_reset)(bool is_threaded,
248       unsigned width, unsigned height, bool fullscreen,
249       const char *dir_assets, char *font_path,
250       char* menu_png_path,
251       char* widgets_png_path);
252 
253    /* called when the graphics context is destroyed
254     * -> release the textures here */
255    void (*context_destroy)(void);
256 
257    /* called when the window resolution changes
258     * -> (re)layout the widget here */
259    void (*layout)(void *data,
260          bool is_threaded, const char *dir_assets, char *font_path);
261 
262    /* called every frame on the main thread
263     * -> update the widget logic here */
264    void (*iterate)(void *user_data,
265       unsigned width, unsigned height, bool fullscreen,
266       const char *dir_assets, char *font_path,
267       bool is_threaded);
268 
269    /* called every frame
270     * (on the video thread if threaded video is on)
271     * -- data is a video_frame_info_t
272     * -- userdata is a dispgfx_widget_t
273     * -> draw the widget here */
274    void (*frame)(void* data, void *userdata);
275 };
276 
277 float gfx_widgets_get_thumbnail_scale_factor(
278       const float dst_width, const float dst_height,
279       const float image_width, const float image_height);
280 
281 void gfx_widgets_draw_icon(
282       void *userdata,
283       void *data_disp,
284       unsigned video_width,
285       unsigned video_height,
286       unsigned icon_width,
287       unsigned icon_height,
288       uintptr_t texture,
289       float x, float y,
290       float rotation, float scale_factor,
291       float *color);
292 
293 void gfx_widgets_draw_text(
294       gfx_widget_font_data_t* font_data,
295       const char *text,
296       float x, float y,
297       int width, int height,
298       uint32_t color,
299       enum text_alignment text_align,
300       bool draw_outside);
301 
302 void gfx_widgets_flush_text(
303       unsigned video_width, unsigned video_height,
304       gfx_widget_font_data_t* font_data);
305 
306 typedef struct gfx_widget gfx_widget_t;
307 
308 bool gfx_widgets_init(
309       void *data,
310       void *data_disp,
311       void *data_anim,
312       void *settings_data,
313       uintptr_t widgets_active_ptr,
314       bool video_is_threaded,
315       unsigned width, unsigned height, bool fullscreen,
316       const char *dir_assets, char *font_path);
317 
318 void gfx_widgets_deinit(void *data, bool widgets_persisting);
319 
320 void gfx_widgets_msg_queue_push(
321       void *data,
322       retro_task_t *task, const char *msg,
323       unsigned duration,
324       char *title,
325       enum message_queue_icon icon,
326       enum message_queue_category category,
327       unsigned prio, bool flush,
328       bool menu_is_alive);
329 
330 void gfx_widget_volume_update_and_show(float new_volume,
331       bool mute);
332 
333 void gfx_widgets_iterate(
334       void *data,
335       void *data_disp,
336       void *settings_data,
337       unsigned width, unsigned height, bool fullscreen,
338       const char *dir_assets, char *font_path,
339       bool is_threaded);
340 
341 void gfx_widget_screenshot_taken(void *data,
342       const char *shotname, const char *filename);
343 
344 /* AI Service functions */
345 #ifdef HAVE_TRANSLATE
346 bool gfx_widgets_ai_service_overlay_load(
347       dispgfx_widget_t *p_dispwidget,
348       char* buffer, unsigned buffer_len,
349       enum image_type_enum image_type);
350 
351 void gfx_widgets_ai_service_overlay_unload(dispgfx_widget_t *p_dispwidget);
352 #endif
353 
354 #ifdef HAVE_CHEEVOS
355 void gfx_widgets_push_achievement(const char *title, const char *badge);
356 void gfx_widgets_set_leaderboard_display(unsigned id, const char* value);
357 void gfx_widgets_set_challenge_display(unsigned id, const char* badge);
358 #endif
359 
360 /* Warning: not thread safe! */
361 void gfx_widget_set_generic_message(
362       void *data,
363       const char *message, unsigned duration);
364 
365 /* Warning: not thread safe! */
366 void gfx_widget_set_libretro_message(
367       void *data,
368       const char *message, unsigned duration);
369 
370 /* Warning: not thread safe! */
371 void gfx_widget_set_progress_message(void *data,
372       const char *message, unsigned duration,
373       unsigned priority, int8_t progress);
374 
375 /* Warning: not thread safe! */
376 bool gfx_widget_start_load_content_animation(void);
377 
378 /* All the functions below should be called in
379  * the video driver - once they are all added, set
380  * enable_menu_widgets to true for that driver */
381 void gfx_widgets_frame(void *data);
382 
383 void *dispwidget_get_ptr(void);
384 
385 extern const gfx_widget_t gfx_widget_screenshot;
386 extern const gfx_widget_t gfx_widget_volume;
387 extern const gfx_widget_t gfx_widget_generic_message;
388 extern const gfx_widget_t gfx_widget_libretro_message;
389 extern const gfx_widget_t gfx_widget_progress_message;
390 extern const gfx_widget_t gfx_widget_load_content_animation;
391 
392 #ifdef HAVE_CHEEVOS
393 extern const gfx_widget_t gfx_widget_achievement_popup;
394 extern const gfx_widget_t gfx_widget_leaderboard_display;
395 #endif
396 
397 #endif
398