Implement more OSD types (challenge, progress indicators). Not really tested.

This commit is contained in:
Henrik Rydgård 2023-07-03 14:39:49 +02:00
parent 0889e7cf3e
commit 9e4387c529
7 changed files with 226 additions and 83 deletions

View File

@ -134,6 +134,54 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, float duration_
sideEntries_.insert(sideEntries_.begin(), entry);
}
void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) {
double now = time_now_d();
for (auto &entry : sideEntries_) {
if (entry.numericID == achievementID && entry.type == OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR && !show) {
// Hide and eventually delete it.
entry.endTime = now + (double)FadeoutTime();
// Found it, we're done.
return;
}
}
// OK, let's make a new side-entry.
Entry entry;
entry.numericID = achievementID;
entry.type = OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR;
entry.startTime = now;
entry.endTime = now + 10000000.0; // Don't auto-fadeout.
sideEntries_.insert(sideEntries_.begin(), entry);
}
void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const char *trackerText, bool show) { // show=true is used both for create and update.
double now = time_now_d();
for (auto &entry : sideEntries_) {
if (entry.numericID == leaderboardTrackerID && entry.type == OSDType::LEADERBOARD_TRACKER) {
if (show) {
// Just an update.
entry.text = trackerText;
} else {
// Keep the current text, hide and eventually delete it.
entry.endTime = now + (double)FadeoutTime();
}
// Found it, we're done.
return;
}
}
// OK, let's make a new side-entry.
Entry entry;
entry.numericID = leaderboardTrackerID;
entry.type = OSDType::LEADERBOARD_TRACKER;
entry.startTime = now;
entry.endTime = now + 10000000.0; // Don't auto-fadeout
entry.text = trackerText;
sideEntries_.insert(sideEntries_.begin(), entry);
}
void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) {
// TODO: translate "on" and "off"? Or just get rid of this whole thing?
Show(OSDType::MESSAGE_INFO, message + ": " + (on ? "on" : "off"), duration_s);
@ -164,12 +212,12 @@ void OnScreenDisplay::SetProgressBar(std::string id, std::string &&message, int
bars_.push_back(bar);
}
void OnScreenDisplay::RemoveProgressBar(std::string id, float fadeout_s) {
void OnScreenDisplay::RemoveProgressBar(std::string id) {
std::lock_guard<std::mutex> guard(mutex_);
for (auto iter = bars_.begin(); iter != bars_.end(); iter++) {
if (iter->id == id) {
iter->progress = iter->maxValue;
iter->endTime = time_now_d() + (double)fadeout_s;
iter->endTime = time_now_d() + FadeoutTime();
break;
}
}

View File

@ -17,11 +17,9 @@ enum class OSDType {
ACHIEVEMENT_UNLOCKED,
// Side entries
ACHIEVEMENT_PROGRESS,
ACHIEVEMENT_CHALLENGE_INDICATOR,
// PROGRESS_BAR,
// PROGRESS_INDETERMINATE,
ACHIEVEMENT_PROGRESS, // Achievement icon + "measured_progress" text, auto-hide after 2s
ACHIEVEMENT_CHALLENGE_INDICATOR, // Achievement icon ONLY, no auto-hide
LEADERBOARD_TRACKER,
};
// Data holder for on-screen messages.
@ -35,9 +33,6 @@ public:
Show(type, text, text2, "", duration_s, id);
}
void Show(OSDType type, const std::string &text, const std::string &text2, const std::string &icon, float duration_s = 0.0f, const char *id = nullptr);
void ShowAchievementUnlocked(int achievementID);
void ShowAchievementProgress(int achievementID, float duration_s);
void ShowOnOff(const std::string &message, bool on, float duration_s = 0.0f);
@ -46,10 +41,17 @@ public:
// Call this every frame, cleans up old entries.
void Update();
// Specialized achievement-related types. These go to the side notifications, not the top-middle.
void ShowAchievementUnlocked(int achievementID);
void ShowAchievementProgress(int achievementID, float duration_s);
void ShowChallengeIndicator(int achievementID, bool show); // call with show=false to hide.
void ShowLeaderboardTracker(int leaderboardTrackerID, const char *trackerText, bool show); // show=true is used both for create and update.
// Progress bar controls
// Set is both create and update.
// Set is both create and update. If you set maxValue <= minValue, you'll create an "indeterminate" progress
// bar that doesn't show a specific amount of progress.
void SetProgressBar(std::string id, std::string &&message, int minValue, int maxValue, int progress);
void RemoveProgressBar(std::string id, float fadeout_s);
void RemoveProgressBar(std::string id);
struct Entry {
OSDType type;
@ -75,6 +77,8 @@ public:
std::vector<Entry> SideEntries();
std::vector<ProgressBar> ProgressBars();
static float FadeoutTime() { return 0.25f; }
private:
std::vector<Entry> entries_;
std::vector<Entry> sideEntries_;

View File

@ -50,10 +50,6 @@
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/RetroAchievements.h"
void OSDAddNotification(float duration_s, const std::string &title, const std::string &summary, const std::string &iconImageData) {
g_OSD.Show(OSDType::MESSAGE_INFO, title, summary, iconImageData, 5.0f);
}
void OSDOpenBackgroundProgressDialog(const char *str_id, std::string message, s32 min, s32 max, s32 value) {
NOTICE_LOG(ACHIEVEMENTS, "Progress dialog opened: %s %s", str_id, message.c_str());
g_OSD.SetProgressBar(str_id, std::move(message), min, max, value);
@ -66,17 +62,7 @@ void OSDUpdateBackgroundProgressDialog(const char *str_id, std::string message,
void OSDCloseBackgroundProgressDialog(const char *str_id) {
NOTICE_LOG(ACHIEVEMENTS, "Progress dialog closed: %s", str_id);
g_OSD.RemoveProgressBar(str_id, 0.25f);
}
void OSDAddErrorMessage(const char *str_id, std::string message, float duration) {
g_OSD.Show(OSDType::MESSAGE_ERROR, message);
NOTICE_LOG(ACHIEVEMENTS, "Keyed message: %s %s (%0.1f s)", str_id, message.c_str(), duration);
}
void OSDShowServerError(const rc_client_event_t *event) {
// TODO: Enable translation here.
g_OSD.Show(OSDType::MESSAGE_ERROR, "Server error");
g_OSD.RemoveProgressBar(str_id);
}
void OnAchievementsLoginStateChange() {
@ -88,10 +74,6 @@ namespace Achievements {
// It's the name of the secret, not a secret name - the value is not secret :)
static const char *RA_TOKEN_SECRET_NAME = "retroachievements";
static void SubmitLeaderboard(u32 leaderboard_id, int value);
static void DisplayAchievementSummary();
static void DisplayMasteredNotification();
static void SetChallengeMode(bool enabled);
static u32 GetGameID();
static Achievements::Statistics g_stats;
@ -244,36 +226,57 @@ static void login_token_callback(int result, const char *error_message, rc_clien
// For detailed documentation, see https://github.com/RetroAchievements/rcheevos/wiki/rc_client_set_event_handler.
static void event_handler_callback(const rc_client_event_t *event, rc_client_t *client) {
NOTICE_LOG(ACHIEVEMENTS, "rc_client event: %d", event->type);
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
switch (event->type) {
case RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED:
// An achievement was earned by the player. The handler should notify the player that the achievement was earned.
g_OSD.ShowAchievementUnlocked(event->achievement->id);
INFO_LOG(ACHIEVEMENTS, "Achievement unlocked: '%s' (%d)", event->achievement->title, event->achievement->id);
break;
case RC_CLIENT_EVENT_GAME_COMPLETED:
{
// All achievements for the game have been earned. The handler should notify the player that the game was completed or mastered, depending on challenge mode.
DisplayMasteredNotification();
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
const rc_client_game_t *gameInfo = rc_client_get_game_info(g_rcClient);
// TODO: Translation?
std::string title = ReplaceAll(ac->T("Mastered %1"), "%1", gameInfo->title);
rc_client_user_game_summary_t summary;
rc_client_get_user_game_summary(g_rcClient, &summary);
std::string message = StringFromFormat(ac->T("%d achievements"), summary.num_unlocked_achievements);
g_OSD.Show(OSDType::MESSAGE_INFO, title, message, gameInfo->badge_name, 10.0f);
INFO_LOG(ACHIEVEMENTS, "%s", message.c_str());
break;
}
case RC_CLIENT_EVENT_LEADERBOARD_STARTED:
// A leaderboard attempt has started. The handler may show a message with the leaderboard title and /or description indicating the attempt started.
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard attempt started: %s", event->leaderboard->title);
INFO_LOG(ACHIEVEMENTS, "Leaderboard attempt started: %s", event->leaderboard->title);
g_OSD.Show(OSDType::MESSAGE_INFO, ReplaceAll(ac->T("%1: Leaderboard attempt started"), "%1", event->leaderboard->title), event->leaderboard->description, 3.0f);
break;
case RC_CLIENT_EVENT_LEADERBOARD_FAILED:
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard attempt failed: %s", event->leaderboard->title);
g_OSD.Show(OSDType::MESSAGE_INFO, ReplaceAll(ac->T("%1: Failed"), "%1", event->leaderboard->title), 3.0f);
// A leaderboard attempt has failed.
break;
case RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED:
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard result submitted: %s", event->leaderboard->title);
g_OSD.Show(OSDType::MESSAGE_SUCCESS, ReplaceAll(ac->T("%1: Submitting successful score!"), "%1", event->leaderboard->title), event->leaderboard->description, 3.0f);
// A leaderboard attempt was completed.The handler may show a message with the leaderboard title and /or description indicating the final value being submitted to the server.
break;
case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW:
NOTICE_LOG(ACHIEVEMENTS, "Challenge indicator show: %s", event->achievement->title);
g_OSD.ShowChallengeIndicator(event->achievement->id, true);
// A challenge achievement has become active. The handler should show a small version of the achievement icon
// to indicate the challenge is active.
break;
case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE:
NOTICE_LOG(ACHIEVEMENTS, "Challenge indicator hide: %s", event->achievement->title);
// A challenge achievement has become inactive.
g_OSD.ShowChallengeIndicator(event->achievement->id, false);
// The handler should hide the small version of the achievement icon that was shown by the corresponding RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW event.
break;
case RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW:
@ -290,22 +293,26 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t *
// Multiple active leaderboards may share a single tracker if they have the same definition and value.
// As such, the leaderboard tracker IDs are unique amongst the leaderboard trackers, and have no correlation to the active leaderboard(s).
// Use event->leaderboard_tracker->id for uniqueness checks, and display event->leaderboard_tracker->display (string)
g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, event->leaderboard_tracker->display, true);
break;
case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE:
// A leaderboard_tracker has become inactive.The handler should hide the tracker text from the screen.
// A leaderboard_tracker has become inactive. The handler should hide the tracker text from the screen.
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker hide: %s", event->leaderboard_tracker->display);
g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, nullptr, false);
break;
case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE:
// A leaderboard_tracker value has been updated. The handler should update the tracker text on the screen.
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker update: %s", event->leaderboard_tracker->display);
g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, event->leaderboard_tracker->display, false);
break;
case RC_CLIENT_EVENT_RESET:
WARN_LOG(ACHIEVEMENTS, "Resetting game due to achievement setting change!");
// Challenge mode was enabled, or something else that forces a game reset.
System_PostUIMessage("reset", "");
break;
case RC_CLIENT_EVENT_SERVER_ERROR:
ERROR_LOG(ACHIEVEMENTS, "Server error: %s: %s", event->server_error->api, event->server_error->error_message);
OSDShowServerError(event);
g_OSD.Show(OSDType::MESSAGE_ERROR, "Server error");
break;
default:
WARN_LOG(ACHIEVEMENTS, "Unhandled rc_client event %d, ignoring", event->type);
@ -528,22 +535,6 @@ std::string GetGameAchievementSummary() {
return summaryString;
}
void DisplayMasteredNotification() {
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
const rc_client_game_t *gameInfo = rc_client_get_game_info(g_rcClient);
// TODO: Translation?
std::string title = ReplaceAll(ac->T("Mastered %1"), "%1", gameInfo->title);
rc_client_user_game_summary_t summary;
rc_client_get_user_game_summary(g_rcClient, &summary);
std::string message = StringFromFormat(ac->T("%d achievements"), summary.num_unlocked_achievements);
OSDAddNotification(20.0f, title, message, gameInfo->badge_name);
NOTICE_LOG(ACHIEVEMENTS, "%s", message.c_str());
}
void identify_and_load_callback(int result, const char *error_message, rc_client_t *client, void *userdata) {
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
@ -562,7 +553,7 @@ void identify_and_load_callback(int result, const char *error_message, rc_client
if (RC_OK == rc_client_game_get_image_url(gameInfo, temp, sizeof(temp))) {
Achievements::DownloadImageIfMissing(cacheId, std::move(std::string(temp)));
}
OSDAddNotification(10.0f, std::string(gameInfo->title), GetGameAchievementSummary(), cacheId);
g_OSD.Show(OSDType::MESSAGE_INFO, std::string(gameInfo->title), GetGameAchievementSummary(), cacheId, 5.0f);
break;
}
case RC_NO_GAME_LOADED:

View File

@ -830,7 +830,20 @@ void SystemInfoScreen::CreateTabs() {
return UI::EVENT_DONE;
});
internals->Add(new Choice(si->T("Clear")))->OnClick.Add([&](UI::EventParams &) {
g_OSD.RemoveProgressBar("testprogress", 0.25f);
g_OSD.RemoveProgressBar("testprogress");
return UI::EVENT_DONE;
});
internals->Add(new ItemHeader(si->T("Achievement tests")));
internals->Add(new Choice(si->T("Leaderboard tracker: Show")))->OnClick.Add([=](UI::EventParams &) {
g_OSD.ShowLeaderboardTracker(1, "My leaderboard tracker", true);
return UI::EVENT_DONE;
});
internals->Add(new Choice(si->T("Leaderboard tracker: Update")))->OnClick.Add([=](UI::EventParams &) {
g_OSD.ShowLeaderboardTracker(1, "Updated tracker", true);
return UI::EVENT_DONE;
});
internals->Add(new Choice(si->T("Leaderboard tracker: Hide")))->OnClick.Add([=](UI::EventParams &) {
g_OSD.ShowLeaderboardTracker(1, nullptr, false);
return UI::EVENT_DONE;
});
#if PPSSPP_PLATFORM(ANDROID)

View File

@ -102,7 +102,6 @@ static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLeve
uint32_t foreGround = whiteAlpha(alpha);
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
dc.FillRect(background, bounds);
ImageID iconID = GetOSDIcon(level);
@ -161,9 +160,7 @@ static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::Pr
static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressBar &entry, Bounds bounds, int align, float alpha) {
uint32_t foreGround = whiteAlpha(alpha);
Bounds shadowBounds = bounds.Expand(10.0f);
dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid, shadowBounds.x, shadowBounds.y + 4.0f, shadowBounds.x2(), shadowBounds.y2(), alphaMul(0xFF000000, 0.9f * alpha), 1.0f);
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
uint32_t backgroundColor = colorAlpha(0x806050, alpha);
uint32_t progressBackgroundColor = colorAlpha(0xa08070, alpha);
@ -199,6 +196,23 @@ static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressB
dc.DrawTextShadowRect(entry.message.c_str(), bounds, colorAlpha(0xFFFFFFFF, alpha), (align & FLAG_DYNAMIC_ASCII) | ALIGN_CENTER);
}
static void MeasureLeaderboardTracker(UIContext &dc, const std::string &text, float *width, float *height) {
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text.c_str(), width, height);
*width += 10.0f;
*height += 10.0f;
}
static void RenderLeaderboardTracker(UIContext &dc, const Bounds &bounds, const std::string &text, float alpha) {
// TODO: Awful color.
uint32_t backgroundColor = colorAlpha(0x806050, alpha);
UI::Drawable background = UI::Drawable(backgroundColor);
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
dc.FillRect(background, bounds);
dc.SetFontStyle(dc.theme->uiFont);
dc.SetFontScale(1.0f, 1.0f);
dc.DrawTextShadowRect(text.c_str(), bounds.Inset(5.0f, 5.0f), colorAlpha(0xFFFFFFFF, alpha), ALIGN_VCENTER | ALIGN_LEFT);
}
void OnScreenMessagesView::Draw(UIContext &dc) {
if (!g_Config.bShowOnScreenMessages) {
return;
@ -210,29 +224,63 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
float y = 10.0f;
const float fadeoutCoef = 1.0f / OnScreenDisplay::FadeoutTime();
// Draw side entries. Top entries should apply on top of them if there's a collision, so drawing
// these first makes sense.
const std::vector<OnScreenDisplay::Entry> sideEntries = g_OSD.SideEntries();
for (auto &entry : sideEntries) {
float tw, th;
AchievementRenderStyle style = AchievementRenderStyle::PROGRESS_INDICATOR;
const rc_client_achievement_t *achievement = nullptr;
AchievementRenderStyle style;
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
{
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
style = AchievementRenderStyle::PROGRESS_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
style = AchievementRenderStyle::CHALLENGE_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::LEADERBOARD_TRACKER:
{
MeasureLeaderboardTracker(dc, entry.text, &tw, &th);
break;
}
default:
continue;
}
Bounds b(10.0f, y, tw, th);
float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f);
float alpha = Clamp((float)(entry.endTime - now) * fadeoutCoef, 0.0f, 1.0f);
// OK, render the thing.
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
RenderAchievement(dc, achievement, style, b, alpha, entry.startTime, now);
break;
}
case OSDType::LEADERBOARD_TRACKER:
RenderLeaderboardTracker(dc, b, entry.text, alpha);
break;
default:
continue;
}
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
}
// Get height

View File

@ -288,8 +288,15 @@ void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achi
*w = 0.0f;
switch (style) {
case AchievementRenderStyle::PROGRESS_INDICATOR:
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, achievement->measured_progress, w, h);
*w += 36.0f + 4.0f * 3.0f;
*h = 36.0f;
break;
case AchievementRenderStyle::CHALLENGE_INDICATOR:
// ONLY the icon.
*w = 60.0f;
*h = 60.0f;
break;
default:
*h = 72.0f;
break;
@ -331,41 +338,63 @@ void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement
background.color = colorBlend(0xFFE0FFFF, background.color, mixWhite);
}
float iconSpace = 64.0f;
float padding = 4.0f;
float iconSpace = bounds.h - padding * 2.0f;
dc.Flush();
dc.RebindTexture();
dc.Begin();
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
dc.FillRect(background, bounds);
dc.Flush();
dc.Begin();
dc.SetFontStyle(dc.theme->uiFont);
dc.SetFontScale(1.0f, 1.0f);
dc.DrawTextRect(achievement->title, bounds.Inset(iconSpace + 12.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
dc.SetFontScale(0.66f, 0.66f);
dc.DrawTextRect(achievement->description, bounds.Inset(iconSpace + 12.0f, 39.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
// TODO: Draw measured_progress / measured_percent in a cute way
char temp[512];
snprintf(temp, sizeof(temp), "%d", achievement->points);
dc.SetFontScale(1.5f, 1.5f);
dc.DrawTextRect(temp, bounds.Expand(-5.0f, -5.0f), fgColor, ALIGN_RIGHT | ALIGN_VCENTER);
switch (style) {
case AchievementRenderStyle::LISTED:
case AchievementRenderStyle::UNLOCKED:
{
dc.SetFontScale(1.0f, 1.0f);
dc.DrawTextRect(achievement->title, bounds.Inset(iconSpace + 12.0f, 2.0f, padding, padding), fgColor, ALIGN_TOPLEFT);
dc.SetFontScale(1.0f, 1.0f);
dc.Flush();
dc.SetFontScale(0.66f, 0.66f);
dc.DrawTextRect(achievement->description, bounds.Inset(iconSpace + 12.0f, 39.0f, padding, padding), fgColor, ALIGN_TOPLEFT);
// TODO: Draw measured_progress / measured_percent in a cute way
snprintf(temp, sizeof(temp), "%d", achievement->points);
dc.SetFontScale(1.5f, 1.5f);
dc.DrawTextRect(temp, bounds.Expand(-5.0f, -5.0f), fgColor, ALIGN_RIGHT | ALIGN_VCENTER);
dc.SetFontScale(1.0f, 1.0f);
dc.Flush();
break;
}
case AchievementRenderStyle::PROGRESS_INDICATOR:
// TODO: Also render a progress bar.
dc.SetFontScale(1.0f, 1.0f);
dc.DrawTextRect(achievement->measured_progress, bounds.Inset(iconSpace + padding * 2.0f, padding, padding, padding), fgColor, ALIGN_TOPLEFT);
break;
case AchievementRenderStyle::CHALLENGE_INDICATOR:
// Nothing but the icon.
break;
}
// Download and display the image.
if (RC_OK == rc_client_achievement_get_image_url(achievement, achievement->state, temp, sizeof(temp))) {
Achievements::DownloadImageIfMissing(achievement->badge_name, std::move(std::string(temp)));
if (g_iconCache.BindIconTexture(&dc, achievement->badge_name)) {
dc.Draw()->DrawTexRect(Bounds(bounds.x + 4.0f, bounds.y + 4.0f, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
dc.Draw()->DrawTexRect(Bounds(bounds.x + padding, bounds.y + padding, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
}
dc.Flush();
dc.RebindTexture();
}
dc.Flush();
dc.RebindTexture();
}
void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, float alpha) {
@ -504,7 +533,16 @@ void AchievementView::GetContentDimensions(const UIContext &dc, float &w, float
void AchievementView::Click() {
// In debug builds, clicking achievements will show them being unlocked (which may be a lie).
#ifdef _DEBUG
g_OSD.ShowAchievementUnlocked(achievement_->id);
static int type = 0;
type++;
type = type % 4;
switch (type) {
case 0: g_OSD.ShowAchievementUnlocked(achievement_->id); break;
case 1: g_OSD.ShowAchievementProgress(achievement_->id, 2.0f); break;
case 2: g_OSD.ShowChallengeIndicator(achievement_->id, true); break;
case 3: g_OSD.ShowChallengeIndicator(achievement_->id, false); break;
}
#endif
}

View File

@ -81,6 +81,7 @@ enum class AchievementRenderStyle {
LISTED,
UNLOCKED,
PROGRESS_INDICATOR,
CHALLENGE_INDICATOR,
};
void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h);