diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 48e748dabd..129bec8196 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -100,6 +100,8 @@ static rcheevos_locals_t rcheevos_locals = #endif #ifdef HAVE_GFX_WIDGETS 0, /* active_lboard_trackers */ + NULL, /* tracker_achievement */ + 0.0, /* tracker_progress */ #endif {RCHEEVOS_LOAD_STATE_NONE, 0, 0 }, /* load_info */ false,/* hardcore_active */ @@ -641,6 +643,30 @@ static void rcheevos_challenge_ended( gfx_widgets_set_challenge_display(cheevo->id, NULL); } +static void rcheevos_progress_updated(rcheevos_locals_t* locals, + rcheevos_racheevo_t* cheevo, int value, + bool widgets_ready) +{ + settings_t* settings = config_get_ptr(); + + if ( cheevo + && widgets_ready + && settings->bools.cheevos_visibility_progress_tracker + && rcheevos_is_player_active()) + { + unsigned measured_value, measured_target; + if (rc_runtime_get_achievement_measured(&locals->runtime, cheevo->id, &measured_value, &measured_target)) + { + const float progress = ((float)measured_value / (float)measured_target); + if (progress > locals->tracker_progress) + { + locals->tracker_progress = progress; + locals->tracker_achievement = cheevo; + } + } + } +} + #endif int rcheevos_get_richpresence(char *s, size_t len) @@ -705,6 +731,8 @@ void rcheevos_reset_game(bool widgets_ready) for (i = 0; i < rcheevos_locals.game.achievement_count; ++i, ++cheevo) gfx_widgets_set_challenge_display(cheevo->id, NULL); + + gfx_widget_set_achievement_progress(NULL, NULL); } #endif @@ -1206,6 +1234,12 @@ static void rcheevos_runtime_event_handler( rcheevos_find_cheevo(runtime_event->id), runtime_event->value, widgets_ready); break; + + case RC_RUNTIME_EVENT_ACHIEVEMENT_PROGRESS_UPDATED: + rcheevos_progress_updated(&rcheevos_locals, + rcheevos_find_cheevo(runtime_event->id), + runtime_event->value, widgets_ready); + break; #endif case RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED: @@ -1336,6 +1370,19 @@ void rcheevos_test(void) rcheevos_locals.assign_new_trackers = false; } + + if (rcheevos_locals.tracker_achievement != NULL) + { + char buffer[32] = ""; + if (rc_runtime_format_achievement_measured(&rcheevos_locals.runtime, + rcheevos_locals.tracker_achievement->id, buffer, sizeof(buffer))) + { + gfx_widget_set_achievement_progress(rcheevos_locals.tracker_achievement->badge, buffer); + } + + rcheevos_locals.tracker_achievement = NULL; + rcheevos_locals.tracker_progress = 0.0; + } #endif } @@ -1390,6 +1437,9 @@ bool rcheevos_set_serialized_data(void* buffer) } } } + + if (settings->bools.cheevos_visibility_progress_tracker) + gfx_widget_set_achievement_progress(NULL, NULL); } #endif @@ -2162,6 +2212,9 @@ bool rcheevos_load(const void *data) rcheevos_locals.game.mastery_placard_shown = false; #ifdef HAVE_THREADS rcheevos_locals.queued_command = CMD_EVENT_NONE; +#endif +#ifdef HAVE_GFX_WIDGETS + rcheevos_locals.tracker_progress = 0.0; #endif rc_runtime_init(&rcheevos_locals.runtime); diff --git a/cheevos/cheevos_locals.h b/cheevos/cheevos_locals.h index 8825439794..3ca72ef073 100644 --- a/cheevos/cheevos_locals.h +++ b/cheevos/cheevos_locals.h @@ -188,6 +188,8 @@ typedef struct rcheevos_locals_t #ifdef HAVE_GFX_WIDGETS unsigned active_lboard_trackers; /* bit mask of active leaderboard tracker ids */ + rcheevos_racheevo_t* tracker_achievement; + float tracker_progress; #endif rcheevos_load_info_t load_info; /* load info */ diff --git a/gfx/gfx_widgets.h b/gfx/gfx_widgets.h index a10d199c3e..18ece45014 100644 --- a/gfx/gfx_widgets.h +++ b/gfx/gfx_widgets.h @@ -380,6 +380,7 @@ void gfx_widgets_update_cheevos_appearance(void); void gfx_widgets_push_achievement(const char *title, const char* subtitle, const char *badge); void gfx_widgets_set_leaderboard_display(unsigned id, const char* value); void gfx_widgets_set_challenge_display(unsigned id, const char* badge); +void gfx_widget_set_achievement_progress(const char* badge, const char* progress); #endif /* TODO/FIXME/WARNING: Not thread safe! */ diff --git a/gfx/widgets/gfx_widget_leaderboard_display.c b/gfx/widgets/gfx_widget_leaderboard_display.c index cdeb4c1580..6671ecac30 100644 --- a/gfx/widgets/gfx_widget_leaderboard_display.c +++ b/gfx/widgets/gfx_widget_leaderboard_display.c @@ -19,12 +19,15 @@ #include "../gfx_widgets.h" #include "../cheevos/cheevos.h" +#include #define CHEEVO_LBOARD_ARRAY_SIZE 4 #define CHEEVO_CHALLENGE_ARRAY_SIZE 8 #define CHEEVO_LBOARD_DISPLAY_PADDING 3 +#define CHEEVO_PROGRESS_TRACKER_DURATION 2000 + struct leaderboard_display_info { unsigned id; @@ -38,6 +41,14 @@ struct challenge_display_info uintptr_t image; }; +struct progress_tracker_info +{ + uintptr_t image; + unsigned width; + char display[32]; + retro_time_t show_until; +}; + #define CHEEVO_LBOARD_FIRST_FIXED_CHAR 0x2D /* -./0123456789: */ #define CHEEVO_LBOARD_LAST_FIXED_CHAR 0x3A struct gfx_widget_leaderboard_display_state @@ -48,6 +59,7 @@ struct gfx_widget_leaderboard_display_state const dispgfx_widget_t *dispwidget_ptr; struct leaderboard_display_info tracker_info[CHEEVO_LBOARD_ARRAY_SIZE]; struct challenge_display_info challenge_info[CHEEVO_CHALLENGE_ARRAY_SIZE]; + struct progress_tracker_info progress_tracker; unsigned tracker_count; unsigned challenge_count; uint16_t char_width[CHEEVO_LBOARD_LAST_FIXED_CHAR - CHEEVO_LBOARD_FIRST_FIXED_CHAR + 1]; @@ -97,7 +109,7 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata) gfx_widget_leaderboard_display_state_t *state = &p_w_leaderboard_display_st; /* if there's nothing to display, just bail */ - if (state->tracker_count == 0 && state->challenge_count == 0) + if (state->tracker_count == 0 && state->challenge_count == 0 && state->progress_tracker.show_until == 0) return; #ifdef HAVE_THREADS @@ -237,6 +249,92 @@ static void gfx_widget_leaderboard_display_frame(void* data, void* userdata) } } } + + if (state->progress_tracker.show_until) + { + retro_time_t now = cpu_features_get_time_usec(); + if (now >= state->progress_tracker.show_until) + { + gfx_widget_set_achievement_progress(NULL, NULL); + } + else + { + const unsigned image_size = spacing * 4; + const unsigned tracker_height = image_size + spacing; + const unsigned tracker_width = state->progress_tracker.width + image_size + spacing * 2; + x = video_width - tracker_width - spacing; + y -= (tracker_height + spacing); + + /* Backdrop */ + gfx_display_draw_quad( + p_disp, + video_info->userdata, + video_width, video_height, + (int)x, (int)y, tracker_width, tracker_height, + video_width, video_height, + p_dispwidget->backdrop_orig, + NULL); + + x += spacing / 2; + y += spacing / 2; + + if (!state->progress_tracker.image) + { + /* default icon */ + if (p_dispwidget->gfx_widgets_icons_textures[ + MENU_WIDGETS_ICON_ACHIEVEMENT]) + { + gfx_display_ctx_driver_t* dispctx = p_disp->dispctx; + if (dispctx && dispctx->blend_begin) + dispctx->blend_begin(video_info->userdata); + + gfx_widgets_draw_icon( + video_info->userdata, + p_disp, + video_width, + video_height, + image_size, + image_size, + p_dispwidget->gfx_widgets_icons_textures[ + MENU_WIDGETS_ICON_ACHIEVEMENT], + x, + y, + 0.0f, /* rad */ + 1.0f, /* cos(rad) = cos(0) = 1.0f */ + 0.0f, /* sine(rad) = sine(0) = 0.0f */ + pure_white); + + if (dispctx && dispctx->blend_end) + dispctx->blend_end(video_info->userdata); + } + } + else + { + /* achievement badge */ + gfx_widgets_draw_icon( + video_info->userdata, + p_disp, + video_width, + video_height, + image_size, + image_size, + state->progress_tracker.image, + x, + y, + 0.0f, /* rad */ + 1.0f, /* cos(rad) = cos(0) = 1.0f */ + 0.0f, /* sine(rad) = sine(0) = 0.0f */ + pure_white); + } + + x += image_size + spacing; + y = (float)y + image_size / 2 + p_dispwidget->gfx_widget_fonts.regular.line_height / 2 - p_dispwidget->gfx_widget_fonts.regular.line_descender; + gfx_widgets_draw_text(&p_dispwidget->gfx_widget_fonts.regular, + state->progress_tracker.display, x, y, + video_width, video_height, + TEXT_COLOR_INFO, TEXT_ALIGN_LEFT, true); + } + } } #ifdef HAVE_THREADS @@ -387,6 +485,33 @@ void gfx_widgets_set_challenge_display(unsigned id, const char* badge) video_driver_texture_unload(&old_badge_id); } +void gfx_widget_set_achievement_progress(const char* badge, const char* progress) +{ + gfx_widget_leaderboard_display_state_t* state = &p_w_leaderboard_display_st; + uintptr_t old_badge_id = state->progress_tracker.image; + + if (badge == NULL) + { + /* hide indicator */ + state->progress_tracker.image = 0; + state->progress_tracker.show_until = 0; + } + else + { + /* show indicator */ + state->progress_tracker.show_until = cpu_features_get_time_usec() + CHEEVO_PROGRESS_TRACKER_DURATION * 1000; + state->progress_tracker.image = rcheevos_get_badge_texture(badge, 1); + + snprintf(state->progress_tracker.display, sizeof(state->progress_tracker.display), "%s", progress); + state->progress_tracker.width = (uint16_t)font_driver_get_message_width( + state->dispwidget_ptr->gfx_widget_fonts.regular.font, + progress, 0, 1); + } + + if (old_badge_id) + video_driver_texture_unload(&old_badge_id); +} + const gfx_widget_t gfx_widget_leaderboard_display = { &gfx_widget_leaderboard_display_init, &gfx_widget_leaderboard_display_free,