diff --git a/Makefile.common b/Makefile.common index aff67b3485..b71a3b3b29 100644 --- a/Makefile.common +++ b/Makefile.common @@ -840,7 +840,8 @@ endif OBJ += input/input_osk.o ifeq ($(HAVE_GFX_WIDGETS), 1) - OBJ += gfx/gfx_widgets.o + OBJ += gfx/gfx_widgets.o \ + gfx/widgets/gfx_widget_screenshot.o endif ifeq ($(HAVE_OVERLAY), 1) diff --git a/gfx/font_driver.h b/gfx/font_driver.h index 417ab1cad6..9449889e98 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -24,6 +24,8 @@ #include "../retroarch.h" +#include "video_defines.h" + RETRO_BEGIN_DECLS /* All coordinates and offsets are top-left oriented. diff --git a/gfx/gfx_widgets.c b/gfx/gfx_widgets.c index 100929c7ed..580d2df6ea 100644 --- a/gfx/gfx_widgets.c +++ b/gfx/gfx_widgets.c @@ -1,7 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2014-2017 - Jean-André Santoni * Copyright (C) 2015-2018 - Andre Leiradella - * Copyright (C) 2018-2019 - natinusala + * Copyright (C) 2018-2020 - natinusala * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -35,7 +35,6 @@ #include "gfx_widgets.h" -#include "gfx_animation.h" #include "gfx_display.h" #include "font_driver.h" @@ -61,13 +60,6 @@ static float msg_queue_task_progress_2[16] = COLOR_HEX_TO_FLOAT(0x317198, 1.0f); static float color_task_progress_bar[16] = COLOR_HEX_TO_FLOAT(0x22B14C, 1.0f); #endif -#define TEXT_COLOR_INFO 0xD8EEFFFF -#if 0 -#define TEXT_COLOR_SUCCESS 0x22B14CFF -#define TEXT_COLOR_ERROR 0xC23B22FF -#endif -#define TEXT_COLOR_FAINT 0x878787FF - static float volume_bar_background[16] = COLOR_HEX_TO_FLOAT(0x1A1A1A, 1.0f); static float volume_bar_normal[16] = COLOR_HEX_TO_FLOAT(0x198AC6, 1.0f); static float volume_bar_loud[16] = COLOR_HEX_TO_FLOAT(0xF5DD19, 1.0f); @@ -79,6 +71,16 @@ static uint64_t gfx_widgets_frame_count = 0; static font_data_t *font_regular = NULL; static font_data_t *font_bold = NULL; +font_data_t* gfx_widgets_get_font_regular() +{ + return font_regular; +} + +font_data_t* gfx_widgets_get_font_bold() +{ + return font_bold; +} + static video_font_raster_block_t font_raster_regular; static video_font_raster_block_t font_raster_bold; @@ -89,6 +91,11 @@ static float gfx_widgets_pure_white[16] = { 1.00, 1.00, 1.00, 1.00, }; +float* gfx_widgets_get_pure_white(void) +{ + return gfx_widgets_pure_white; +} + /* FPS */ static char gfx_widgets_fps_text[255] = {0}; @@ -150,6 +157,11 @@ static float gfx_widgets_backdrop_orig[16] = { 0.00, 0.00, 0.00, 0.75, }; +float* gfx_widgets_get_backdrop_orig(void) +{ + return gfx_widgets_backdrop_orig; +} + static float gfx_widgets_backdrop[16] = { 0.00, 0.00, 0.00, 0.75, 0.00, 0.00, 0.00, 0.75, @@ -216,8 +228,12 @@ static uintptr_t msg_queue_icon_outline = 0; static uintptr_t msg_queue_icon_rect = 0; static bool msg_queue_has_icons = false; -extern gfx_animation_ctx_tag -gfx_widgets_generic_tag; +extern gfx_animation_ctx_tag gfx_widgets_generic_tag; + +gfx_animation_ctx_tag gfx_widgets_get_generic_tag(void) +{ + return gfx_widgets_generic_tag; +} /* There can only be one message animation at a time to * avoid confusing users */ @@ -279,25 +295,6 @@ static gfx_animation_ctx_tag volume_tag = (uintptr_t) &volume_alpha; static bool volume_mute = false; -/* Screenshot */ -static float screenshot_alpha = 0.0f; -static uintptr_t screenshot_texture = 0; -static unsigned screenshot_texture_width = 0; -static unsigned screenshot_texture_height = 0; -static char screenshot_shotname[256] = {0}; -static char screenshot_filename[256] = {0}; -static bool screenshot_loaded = false; - -static float screenshot_scale_factor = 0.0f; -static float screenshot_y = 0.0f; -static unsigned screenshot_height = 0; -static unsigned screenshot_width = 0; -static unsigned screenshot_thumbnail_width = 0; -static unsigned screenshot_thumbnail_height = 0; -static gfx_timer_t screenshot_timer; - -static unsigned screenshot_shotname_length = 0; - #ifdef HAVE_TRANSLATE /* AI Service Overlay */ static int ai_service_overlay_state = 0; @@ -325,10 +322,30 @@ static float last_scale_factor = 0.0f; static float msg_queue_text_scale_factor = 0.0f; static float widget_font_size = 0.0f; +float gfx_widgets_get_font_size(void) +{ + return widget_font_size; +} + static unsigned simple_widget_padding = 0; static unsigned simple_widget_height = 0; static unsigned glyph_width = 0; +unsigned gfx_widgets_get_padding(void) +{ + return simple_widget_padding; +} + +unsigned gfx_widgets_get_height(void) +{ + return simple_widget_height; +} + +unsigned gfx_widgets_get_glyph_width(void) +{ + return glyph_width; +} + static unsigned libretro_message_width = 0; static unsigned msg_queue_height; @@ -361,6 +378,13 @@ static unsigned divider_width_1px = 1; static unsigned last_video_width = 0; static unsigned last_video_height = 0; +/* Widgets list */ +const static gfx_widget_t* const widgets[] = { + &gfx_widget_screenshot +}; + +static const size_t widgets_len = sizeof(widgets) / sizeof(widgets[0]); + static void msg_widget_msg_transition_animation_done(void *userdata) { menu_widget_msg_t *msg = (menu_widget_msg_t*)userdata; @@ -734,7 +758,7 @@ static void gfx_widgets_msg_queue_kill(unsigned idx) gfx_widgets_msg_queue_move(); } -static void gfx_widgets_draw_icon( +void gfx_widgets_draw_icon( void *userdata, unsigned video_width, unsigned video_height, @@ -838,7 +862,7 @@ static void gfx_widgets_draw_icon_blend( } #endif -static float gfx_widgets_get_thumbnail_scale_factor( +float gfx_widgets_get_thumbnail_scale_factor( const float dst_width, const float dst_height, const float image_width, const float image_height) { @@ -850,28 +874,6 @@ static float gfx_widgets_get_thumbnail_scale_factor( return (dst_width / image_width); } -static void gfx_widgets_screenshot_dispose(void *userdata) -{ - screenshot_loaded = false; - video_driver_texture_unload(&screenshot_texture); - screenshot_texture = 0; -} - -static void gfx_widgets_screenshot_end(void *userdata) -{ - gfx_animation_ctx_entry_t entry; - - entry.cb = gfx_widgets_screenshot_dispose; - entry.duration = MSG_QUEUE_ANIMATION_DURATION; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &screenshot_y; - entry.tag = gfx_widgets_generic_tag; - entry.target_value = -((float)screenshot_height); - entry.userdata = NULL; - - gfx_animation_push(&entry); -} - static void gfx_widgets_start_msg_expiration_timer(menu_widget_msg_t *msg_widget, unsigned duration) { gfx_timer_ctx_entry_t timer; @@ -955,10 +957,18 @@ void gfx_widgets_iterate( video_driver_monitor_reset(); } + for (i = 0; i < widgets_len; i++) + { + const gfx_widget_t* widget = widgets[i]; + + if (widget->iterate) + widget->iterate(width, height, fullscreen, dir_assets, font_path, is_threaded); + } + /* Messages queue */ /* Consume one message if available */ - if ((fifo_read_avail(msg_queue) > 0) + if ((fifo_read_avail(msg_queue) > 0) && !widgets_moving && (current_msgs->size < MSG_QUEUE_ONSCREEN_MAX)) { @@ -1032,44 +1042,6 @@ void gfx_widgets_iterate( break; } } - - /* Load screenshot and start its animation */ - if (screenshot_filename[0] != '\0') - { - gfx_timer_ctx_entry_t timer; - - video_driver_texture_unload(&screenshot_texture); - - screenshot_texture = 0; - - gfx_display_reset_textures_list(screenshot_filename, - "", &screenshot_texture, TEXTURE_FILTER_MIPMAP_LINEAR, - &screenshot_texture_width, &screenshot_texture_height); - - screenshot_height = widget_font_size * 4; - screenshot_width = width; - - screenshot_scale_factor = gfx_widgets_get_thumbnail_scale_factor( - width, screenshot_height, - screenshot_texture_width, screenshot_texture_height - ); - - screenshot_thumbnail_width = screenshot_texture_width * screenshot_scale_factor; - screenshot_thumbnail_height = screenshot_texture_height * screenshot_scale_factor; - - screenshot_shotname_length = (width - screenshot_thumbnail_width - simple_widget_padding*2) / glyph_width; - - screenshot_y = 0.0f; - - timer.cb = gfx_widgets_screenshot_end; - timer.duration = SCREENSHOT_NOTIFICATION_DURATION; - timer.userdata = NULL; - - gfx_timer_start(&screenshot_timer, &timer); - - screenshot_loaded = true; - screenshot_filename[0] = '\0'; - } } static int gfx_widgets_draw_indicator( @@ -1630,62 +1602,6 @@ void gfx_widgets_frame(void *data) 1, false, 0, false); } - /* Screenshot */ - if (screenshot_loaded) - { - char shotname[256]; - gfx_animation_ctx_ticker_t ticker; - - gfx_display_set_alpha(gfx_widgets_backdrop_orig, DEFAULT_BACKDROP); - - gfx_display_draw_quad(userdata, - video_width, video_height, - 0, screenshot_y, - screenshot_width, screenshot_height, - video_width, video_height, - gfx_widgets_backdrop_orig - ); - - gfx_display_set_alpha(gfx_widgets_pure_white, 1.0f); - gfx_widgets_draw_icon( - userdata, - video_width, - video_height, - screenshot_thumbnail_width, - screenshot_thumbnail_height, - screenshot_texture, - 0, screenshot_y, - video_width, video_height, - 0, 1, gfx_widgets_pure_white - ); - - gfx_display_draw_text(font_regular, - msg_hash_to_str(MSG_SCREENSHOT_SAVED), - screenshot_thumbnail_width + simple_widget_padding, widget_font_size * 1.9f + screenshot_y, - video_width, video_height, - TEXT_COLOR_FAINT, - TEXT_ALIGN_LEFT, - 1, false, 0, true - ); - - ticker.idx = gfx_animation_get_ticker_idx(); - ticker.len = screenshot_shotname_length; - ticker.s = shotname; - ticker.selected = true; - ticker.str = screenshot_shotname; - - gfx_animation_ticker(&ticker); - - gfx_display_draw_text(font_regular, - shotname, - screenshot_thumbnail_width + simple_widget_padding, widget_font_size * 2.9f + screenshot_y, - video_width, video_height, - TEXT_COLOR_INFO, - TEXT_ALIGN_LEFT, - 1, false, 0, true - ); - } - #ifdef HAVE_CHEEVOS /* Achievement notification */ if (cheevo_popup_queue_read_index >= 0 && cheevo_popup_queue[cheevo_popup_queue_read_index].title) @@ -2032,18 +1948,12 @@ void gfx_widgets_frame(void *data) gfx_widgets_icons_textures[MENU_WIDGETS_ICON_SLOW_MOTION], (fps_show ? simple_widget_height : 0), top_right_x_advance, MSG_SLOW_MOTION); - /* Screenshot */ - if (screenshot_alpha > 0.0f) + for (i = 0; i < widgets_len; i++) { - gfx_display_set_alpha(gfx_widgets_pure_white, screenshot_alpha); - gfx_display_draw_quad(userdata, - video_width, - video_height, - 0, 0, - video_width, video_height, - video_width, video_height, - gfx_widgets_pure_white - ); + const gfx_widget_t* widget = widgets[i]; + + if (widget->frame) + widget->frame(data); } #ifdef HAVE_MENU @@ -2066,11 +1976,21 @@ void gfx_widgets_frame(void *data) bool gfx_widgets_init(bool video_is_threaded, bool fullscreen) { + size_t i; + if (!gfx_display_init_first_driver(video_is_threaded)) goto error; gfx_widgets_frame_count = 0; + for (i = 0; i < widgets_len; i++) + { + const gfx_widget_t* widget = widgets[i]; + + if (widget->init) + widget->init(video_is_threaded, fullscreen); + } + msg_queue = fifo_new(MSG_QUEUE_PENDING_MAX * sizeof(menu_widget_msg_t*)); if (!msg_queue) @@ -2103,6 +2023,7 @@ error: static void gfx_widgets_layout( bool is_threaded, const char *dir_assets, char *font_path) { + size_t i; int font_height = 0; /* Base font size must be determined first @@ -2225,13 +2146,21 @@ static void gfx_widgets_layout( divider_width_1px = 1; if (last_scale_factor > 1.0f) divider_width_1px = (unsigned)(last_scale_factor + 0.5f); + + for (i = 0; i < widgets_len; i++) + { + const gfx_widget_t* widget = widgets[i]; + + if (widget->layout) + widget->layout(is_threaded, dir_assets, font_path); + } } void gfx_widgets_context_reset(bool is_threaded, unsigned width, unsigned height, bool fullscreen, const char *dir_assets, char *font_path) { - int i; + size_t i; char xmb_path[PATH_MAX_LENGTH]; char monochrome_png_path[PATH_MAX_LENGTH]; char gfx_widgets_path[PATH_MAX_LENGTH]; @@ -2286,6 +2215,14 @@ void gfx_widgets_context_reset(bool is_threaded, msg_queue_has_icons = msg_queue_icon && msg_queue_icon_outline && msg_queue_icon_rect; + for (i = 0; i < widgets_len; i++) + { + const gfx_widget_t* widget = widgets[i]; + + if (widget->context_reset) + widget->context_reset(is_threaded, width, height, fullscreen, dir_assets, font_path); + } + /* Update scaling/dimensions */ last_video_width = width; last_video_height = height; @@ -2299,7 +2236,15 @@ void gfx_widgets_context_reset(bool is_threaded, static void gfx_widgets_context_destroy(void) { - unsigned i; + size_t i; + + for (i = 0; i < widgets_len; i++) + { + const gfx_widget_t* widget = widgets[i]; + + if (widget->context_destroy) + widget->context_destroy(); + } /* TODO: Dismiss onscreen notifications that have been freed */ @@ -2364,6 +2309,14 @@ void gfx_widgets_free(void) gfx_widgets_context_destroy(); + for (i = 0; i < widgets_len; i++) + { + const gfx_widget_t* widget = widgets[i]; + + if (widget->free) + widget->free(); + } + /* Kill any pending animation */ gfx_animation_kill_by_tag(&volume_tag); gfx_animation_kill_by_tag(&gfx_widgets_generic_tag); @@ -2435,10 +2388,6 @@ void gfx_widgets_free(void) /* Volume */ volume_alpha = 0.0f; - - /* Screenshot */ - screenshot_alpha = 0.0f; - gfx_widgets_screenshot_dispose(NULL); } static void gfx_widgets_volume_timer_end(void *userdata) @@ -2527,43 +2476,6 @@ void gfx_widgets_ai_service_overlay_unload(void) } #endif -static void gfx_widgets_screenshot_fadeout(void *userdata) -{ - gfx_animation_ctx_entry_t entry; - - entry.cb = NULL; - entry.duration = SCREENSHOT_DURATION_OUT; - entry.easing_enum = EASING_OUT_QUAD; - entry.subject = &screenshot_alpha; - entry.tag = gfx_widgets_generic_tag; - entry.target_value = 0.0f; - entry.userdata = NULL; - - gfx_animation_push(&entry); -} - -static void gfx_widgets_play_screenshot_flash(void) -{ - gfx_animation_ctx_entry_t entry; - - entry.cb = gfx_widgets_screenshot_fadeout; - entry.duration = SCREENSHOT_DURATION_IN; - entry.easing_enum = EASING_IN_QUAD; - entry.subject = &screenshot_alpha; - entry.tag = gfx_widgets_generic_tag; - entry.target_value = 1.0f; - entry.userdata = NULL; - - gfx_animation_push(&entry); -} - -void gfx_widgets_screenshot_taken(const char *shotname, const char *filename) -{ - gfx_widgets_play_screenshot_flash(); - strlcpy(screenshot_filename, filename, sizeof(screenshot_filename)); - strlcpy(screenshot_shotname, shotname, sizeof(screenshot_shotname)); -} - static void gfx_widgets_end_load_content_animation(void *userdata) { #if 0 @@ -2870,7 +2782,7 @@ void gfx_widgets_set_libretro_message(const char *msg, unsigned duration) gfx_animation_ctx_tag tag = (uintptr_t) &libretro_message_timer; strlcpy(libretro_message, msg, sizeof(libretro_message)); - + libretro_message_alpha = DEFAULT_BACKDROP; /* Kill and restart the timer / animation */ diff --git a/gfx/gfx_widgets.h b/gfx/gfx_widgets.h index 6470c10cc2..1478fc924a 100644 --- a/gfx/gfx_widgets.h +++ b/gfx/gfx_widgets.h @@ -24,6 +24,8 @@ #include #include +#include "gfx_animation.h" + #define DEFAULT_BACKDROP 0.75f #define MSG_QUEUE_PENDING_MAX 32 @@ -31,15 +33,88 @@ #define MSG_QUEUE_ANIMATION_DURATION 330 #define VOLUME_DURATION 3000 -#define SCREENSHOT_DURATION_IN 66 -#define SCREENSHOT_DURATION_OUT SCREENSHOT_DURATION_IN*10 -#define SCREENSHOT_NOTIFICATION_DURATION 6000 #define CHEEVO_NOTIFICATION_DURATION 4000 #define TASK_FINISHED_DURATION 3000 #define HOURGLASS_INTERVAL 5000 #define HOURGLASS_DURATION 1000 #define GENERIC_MESSAGE_DURATION 3000 +#define TEXT_COLOR_INFO 0xD8EEFFFF +#if 0 +#define TEXT_COLOR_SUCCESS 0x22B14CFF +#define TEXT_COLOR_ERROR 0xC23B22FF +#endif +#define TEXT_COLOR_FAINT 0x878787FF + +/* A widget */ +/* TODO: cleanup all unused parameters */ +struct gfx_widget +{ + /* called when the widgets system is initialized + * -> initialize the widget here */ + bool (*init)(bool video_is_threaded, bool fullscreen); + + /* called when the widgets system is freed + * -> free the widget here */ + void (*free)(void); + + /* called when the graphics context is reset + * -> (re)load the textures here */ + void (*context_reset)(bool is_threaded, + unsigned width, unsigned height, bool fullscreen, + const char *dir_assets, char *font_path); + + /* called when the graphics context is destroyed + * -> release the textures here */ + void (*context_destroy)(void); + + /* called when the window resolution changes + * -> (re)layout the widget here */ + void (*layout)(bool is_threaded, const char *dir_assets, char *font_path); + + /* called every frame on the main thread + * -> update the widget logic here */ + void (*iterate)( + unsigned width, unsigned height, bool fullscreen, + const char *dir_assets, char *font_path, + bool is_threaded); + + /* called every frame + * (on the video thread if threaded video is on) + * -> draw the widget here */ + void (*frame)(void* data); +}; + +gfx_animation_ctx_tag gfx_widgets_get_generic_tag(void); +float* gfx_widgets_get_pure_white(void); +unsigned gfx_widgets_get_padding(void); +unsigned gfx_widgets_get_height(void); +unsigned gfx_widgets_get_glyph_width(void); +float gfx_widgets_get_font_size(void); +font_data_t* gfx_widgets_get_font_regular(void); +font_data_t* gfx_widgets_get_font_bold(void); +float* gfx_widgets_get_backdrop_orig(void); + +float gfx_widgets_get_thumbnail_scale_factor( + const float dst_width, const float dst_height, + const float image_width, const float image_height); + +void gfx_widgets_draw_icon( + void *userdata, + unsigned video_width, + unsigned video_height, + unsigned icon_width, + unsigned icon_height, + uintptr_t texture, + float x, float y, + unsigned width, unsigned height, + float rotation, float scale_factor, + float *color); + +typedef struct gfx_widget gfx_widget_t; + +extern const gfx_widget_t gfx_widget_screenshot; + bool gfx_widgets_init(bool video_is_threaded, bool fullscreen); void gfx_widgets_free(void); diff --git a/gfx/widgets/gfx_widget_screenshot.c b/gfx/widgets/gfx_widget_screenshot.c new file mode 100644 index 0000000000..08261e8f0b --- /dev/null +++ b/gfx/widgets/gfx_widget_screenshot.c @@ -0,0 +1,290 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2015-2018 - Andre Leiradella + * Copyright (C) 2018-2020 - natinusala + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "../gfx_widgets.h" +#include "../gfx_animation.h" +#include "../gfx_display.h" +#include "../../retroarch.h" + +#define SCREENSHOT_DURATION_IN 66 +#define SCREENSHOT_DURATION_OUT SCREENSHOT_DURATION_IN*10 +#define SCREENSHOT_NOTIFICATION_DURATION 6000 + +struct gfx_widget_screenshot_state +{ + float alpha; + uintptr_t texture; + unsigned texture_width; + unsigned texture_height; + char shotname[256]; + char filename[256]; + bool loaded; + + float scale_factor; + float y; + unsigned height; + unsigned width; + unsigned thumbnail_width; + unsigned thumbnail_height; + gfx_timer_t timer; + + unsigned shotname_length; +}; + +typedef struct gfx_widget_screenshot_state gfx_widget_screenshot_state_t; + +static gfx_widget_screenshot_state_t p_state = { + 0.0f, + 0, + 0, + 0, + {0}, + {0}, + false, + + 0.0f, + 0.0f, + 0, + 0, + 0, + 0, + 0.0f, + + 0 +}; + +static gfx_widget_screenshot_state_t* gfx_widget_screenshot_get_ptr(void) +{ + return &p_state; +} + +static void gfx_widgets_screenshot_fadeout(void *userdata) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + gfx_animation_ctx_entry_t entry; + + entry.cb = NULL; + entry.duration = SCREENSHOT_DURATION_OUT; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &state->alpha; + entry.tag = gfx_widgets_get_generic_tag(); + entry.target_value = 0.0f; + entry.userdata = NULL; + + gfx_animation_push(&entry); +} + +static void gfx_widgets_play_screenshot_flash(void) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + gfx_animation_ctx_entry_t entry; + + entry.cb = gfx_widgets_screenshot_fadeout; + entry.duration = SCREENSHOT_DURATION_IN; + entry.easing_enum = EASING_IN_QUAD; + entry.subject = &state->alpha; + entry.tag = gfx_widgets_get_generic_tag(); + entry.target_value = 1.0f; + entry.userdata = NULL; + + gfx_animation_push(&entry); +} + +void gfx_widgets_screenshot_taken(const char *shotname, const char *filename) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + gfx_widgets_play_screenshot_flash(); + strlcpy(state->filename, filename, sizeof(state->filename)); + strlcpy(state->shotname, shotname, sizeof(state->shotname)); +} + +static void gfx_widgets_screenshot_dispose(void *userdata) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + state->loaded = false; + video_driver_texture_unload(&state->texture); + state->texture = 0; +} + +static void gfx_widgets_screenshot_end(void *userdata) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + gfx_animation_ctx_entry_t entry; + + entry.cb = gfx_widgets_screenshot_dispose; + entry.duration = MSG_QUEUE_ANIMATION_DURATION; + entry.easing_enum = EASING_OUT_QUAD; + entry.subject = &state->y; + entry.tag = gfx_widgets_get_generic_tag(); + entry.target_value = -((float)state->height); + entry.userdata = NULL; + + gfx_animation_push(&entry); +} + +static void gfx_widget_screenshot_free(void) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + state->alpha = 0.0f; + gfx_widgets_screenshot_dispose(NULL); +} + +static void gfx_widget_screenshot_frame(void* data) +{ + video_frame_info_t *video_info = (video_frame_info_t*)data; + void *userdata = video_info->userdata; + unsigned video_width = video_info->width; + unsigned video_height = video_info->height; + + unsigned padding = gfx_widgets_get_padding(); + float font_size = gfx_widgets_get_font_size(); + + font_data_t* font_regular = gfx_widgets_get_font_regular(); + + float* pure_white = gfx_widgets_get_pure_white(); + + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + + /* Screenshot */ + if (state->loaded) + { + char shotname[256]; + gfx_animation_ctx_ticker_t ticker; + + gfx_display_set_alpha(gfx_widgets_get_backdrop_orig(), DEFAULT_BACKDROP); + + gfx_display_draw_quad(userdata, + video_width, video_height, + 0, state->y, + state->width, state->height, + video_width, video_height, + gfx_widgets_get_backdrop_orig() + ); + + gfx_display_set_alpha(pure_white, 1.0f); + gfx_widgets_draw_icon( + userdata, + video_width, + video_height, + state->thumbnail_width, + state->thumbnail_height, + state->texture, + 0, state->y, + video_width, video_height, + 0, 1, pure_white + ); + + gfx_display_draw_text(font_regular, + msg_hash_to_str(MSG_SCREENSHOT_SAVED), + state->thumbnail_width + padding, font_size * 1.9f + state->y, + video_width, video_height, + TEXT_COLOR_FAINT, + TEXT_ALIGN_LEFT, + 1, false, 0, true + ); + + ticker.idx = gfx_animation_get_ticker_idx(); + ticker.len = state->shotname_length; + ticker.s = shotname; + ticker.selected = true; + ticker.str = state->shotname; + + gfx_animation_ticker(&ticker); + + gfx_display_draw_text(font_regular, + shotname, + state->thumbnail_width + padding, font_size * 2.9f + state->y, + video_width, video_height, + TEXT_COLOR_INFO, + TEXT_ALIGN_LEFT, + 1, false, 0, true + ); + } + + /* Flash effect */ + if (state->alpha > 0.0f) + { + gfx_display_set_alpha(pure_white, state->alpha); + gfx_display_draw_quad(userdata, + video_width, + video_height, + 0, 0, + video_width, video_height, + video_width, video_height, + pure_white + ); + } +} + +static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool fullscreen, + const char *dir_assets, char *font_path, + bool is_threaded) +{ + gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + + float font_size = gfx_widgets_get_font_size(); + unsigned padding = gfx_widgets_get_padding(); + unsigned glyph_width = gfx_widgets_get_glyph_width(); + + /* Load screenshot and start its animation */ + if (state->filename[0] != '\0') + { + gfx_timer_ctx_entry_t timer; + + video_driver_texture_unload(&state->texture); + + state->texture = 0; + + gfx_display_reset_textures_list(state->filename, + "", &state->texture, TEXTURE_FILTER_MIPMAP_LINEAR, + &state->texture_width, &state->texture_height); + + state->height = font_size * 4; + state->width = width; + + state->scale_factor = gfx_widgets_get_thumbnail_scale_factor( + width, state->height, + state->texture_width, state->texture_height + ); + + state->thumbnail_width = state->texture_width * state->scale_factor; + state->thumbnail_height = state->texture_height * state->scale_factor; + + state->shotname_length = (width - state->thumbnail_width - padding*2) / glyph_width; + + state->y = 0.0f; + + timer.cb = gfx_widgets_screenshot_end; + timer.duration = SCREENSHOT_NOTIFICATION_DURATION; + timer.userdata = NULL; + + gfx_timer_start(&state->timer, &timer); + + state->loaded = true; + state->filename[0] = '\0'; + } +} + +const gfx_widget_t gfx_widget_screenshot = { + NULL, /* init */ + gfx_widget_screenshot_free, + NULL, /* context_reset*/ + NULL, /* context_destroy */ + NULL, /* layout */ + gfx_widget_screenshot_iterate, + gfx_widget_screenshot_frame +}; diff --git a/griffin/griffin.c b/griffin/griffin.c index 0617ae19cd..cd2d112dbe 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1261,6 +1261,7 @@ MENU #ifdef HAVE_GFX_WIDGETS #include "../gfx/gfx_widgets.c" +#include "../gfx/widgets/gfx_widget_screenshot.c" #endif #include "../input/input_osk.c"