diff --git a/profiler/src/main.cpp b/profiler/src/main.cpp index 71a7ea79..f1e9c8e7 100644 --- a/profiler/src/main.cpp +++ b/profiler/src/main.cpp @@ -121,6 +121,7 @@ static bool s_isElevated = false; static size_t s_totalMem = tracy::GetPhysicalMemorySize(); tracy::Config s_config; tracy::AchievementsMgr s_achievements; +static const tracy::data::AchievementItem* s_achievementItem = nullptr; static float smoothstep( float x ) { @@ -574,6 +575,45 @@ static void TextComment( const char* str ) ImGui::PopFont(); } +static void DrawAchievements( tracy::data::AchievementItem** items ) +{ + while( *items ) + { + auto& it = *items++; + if( it->unlockTime > 0 ) + { + if( it->doneTime > 0 ) ImGui::PushStyleColor( ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled] ); + bool isSelected = s_achievementItem == it; + if( isSelected ) + { + if( !it->hideNew ) it->hideNew = true; + if( !it->hideCompleted && it->doneTime > 0 ) it->hideCompleted = true; + } + if( ImGui::Selectable( it->name, isSelected ) ) + { + s_achievementItem = it; + } + if( it->doneTime > 0 ) ImGui::PopStyleColor(); + if( !it->hideNew ) + { + ImGui::SameLine(); + tracy::TextColoredUnformatted( 0xFF4488FF, ICON_FA_CIRCLE_EXCLAMATION ); + } + if( !it->hideCompleted && it->doneTime > 0 ) + { + ImGui::SameLine(); + tracy::TextColoredUnformatted( 0xFF44FF44, ICON_FA_CIRCLE_CHECK ); + } + if( it->items ) + { + ImGui::Indent(); + DrawAchievements( it->items ); + ImGui::Unindent(); + } + } + } +} + static void DrawContents() { static bool reconnect = false; @@ -1284,33 +1324,43 @@ static void DrawContents() static int animStage = 0; static float animProgress = 0; static bool showAchievements = false; + static float openTimeLeft = 0; float aSize = 0; - const auto aName = s_achievements.GetNextQueue(); - if( aName ) + const auto aItem = s_achievements.GetNextQueue(); + + if( aItem ) { - aSize = ImGui::CalcTextSize( aName->c_str() ).x + ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().WindowPadding.x * 0.5f; + aSize = ImGui::CalcTextSize( aItem->name ).x + ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().WindowPadding.x * 0.5f; if( animStage == 0 ) { animStage = 1; } } - if( animStage == 1 ) + if( animStage > 0 ) { - animProgress = std::min( animProgress + ImGui::GetIO().DeltaTime / 0.3f, 1.f ); - if( animProgress == 1 ) animStage = 2; tracy::s_wasActive = true; - } - else if( animStage == 3 ) - { - animProgress = std::max( animProgress - ImGui::GetIO().DeltaTime / 0.3f, 0.f ); - if( animProgress == 0 ) + + if( animStage == 1 ) { - s_achievements.PopQueue(); - animStage = 0; + animProgress = std::min( animProgress + ImGui::GetIO().DeltaTime / 0.3f, 1.f ); + if( animProgress == 1 ) + { + animStage = 2; + openTimeLeft = 8; + } + tracy::s_wasActive = true; + } + else if( animStage == 3 ) + { + animProgress = std::max( animProgress - ImGui::GetIO().DeltaTime / 0.3f, 0.f ); + if( animProgress == 0 ) + { + s_achievements.PopQueue(); + animStage = 0; + } } - tracy::s_wasActive = true; } ImGui::SetNextWindowPos( ImVec2( display_w - starSize.x - ImGui::GetStyle().WindowPadding.x * 1.5f - aSize * smoothstep( animProgress ), display_h - starSize.y * 2 - ImGui::GetStyle().WindowPadding.y * 2 ) ); @@ -1323,26 +1373,48 @@ static void DrawContents() if( ( animStage == 0 || animStage == 2 ) && ImGui::IsMouseHoveringRect( cursorScreen - ImVec2( dpiScale * 2, dpiScale * 2 ), cursorScreen + starSize + ImVec2( dpiScale * 4, dpiScale * 4 ) ) ) { color = 0xFFFFFFFF; - if( ImGui::IsMouseClicked( 0 ) ) showAchievements = !showAchievements; + if( ImGui::IsMouseClicked( 0 ) ) + { + if( animStage == 0 ) + { + showAchievements = !showAchievements; + } + else + { + showAchievements = true; + animStage = 3; + s_achievementItem = aItem; + } + } } ImGui::PushFont( s_bigFont ); tracy::TextColoredUnformatted( color, ICON_FA_STAR ); ImGui::PopFont(); - if( aName ) + if( aItem ) { ImGui::SameLine(); const auto dismiss = ImGui::GetCursorScreenPos(); const auto th = ImGui::GetTextLineHeight(); ImGui::SetCursorPosY( cursor.y - th * 0.175f ); - ImGui::TextUnformatted( aName->c_str() ); + ImGui::TextUnformatted( aItem->name ); ImGui::PushFont( s_smallFont ); ImGui::SetCursorPos( cursor + ImVec2( starSize.x + ImGui::GetStyle().ItemSpacing.x, th ) ); - tracy::TextDisabledUnformatted( "Click to dismiss" ); + tracy::TextDisabledUnformatted( "Click to open" ); ImGui::PopFont(); - if( animStage == 2 && ImGui::IsMouseHoveringRect( dismiss - ImVec2( 0, dpiScale * 6 ), dismiss + ImVec2( aSize, th * 1.5f + dpiScale * 4 ) ) && ImGui::IsMouseClicked( 0 ) ) + if( animStage == 2 ) { - animStage = 3; + if( ImGui::IsMouseHoveringRect( dismiss - ImVec2( 0, dpiScale * 6 ), dismiss + ImVec2( aSize, th * 1.5f + dpiScale * 4 ) ) && ImGui::IsMouseClicked( 0 ) ) + { + s_achievementItem = aItem; + showAchievements = true; + animStage = 3; + } + if( !aItem->keepOpen ) + { + openTimeLeft -= ImGui::GetIO().DeltaTime; + if( openTimeLeft < 0 ) animStage = 3; + } } } @@ -1353,6 +1425,29 @@ static void DrawContents() { ImGui::SetNextWindowSize( ImVec2( 600 * dpiScale, 400 * dpiScale ), ImGuiCond_FirstUseEver ); ImGui::Begin( "Achievements List", &showAchievements, ImGuiWindowFlags_NoDocking ); + ImGui::BeginTabBar( "###categories" ); + auto categories = s_achievements.GetCategories(); + while( *categories ) + { + auto& c = *categories++; + if( c->unlockTime > 0 ) + { + if( ImGui::BeginTabItem( c->name ) ) + { + ImGui::Columns( 2 ); + DrawAchievements( c->items ); + ImGui::NextColumn(); + if( s_achievementItem ) + { + const tracy::data::ctx ctx = { s_bigFont, s_smallFont, s_fixedWidth }; + s_achievementItem->description( ctx ); + } + ImGui::EndColumns(); + ImGui::EndTabItem(); + } + } + } + ImGui::EndTabBar(); ImGui::End(); } } diff --git a/profiler/src/profiler/TracyAchievements.cpp b/profiler/src/profiler/TracyAchievements.cpp index f18204d2..7129ca97 100644 --- a/profiler/src/profiler/TracyAchievements.cpp +++ b/profiler/src/profiler/TracyAchievements.cpp @@ -1,21 +1,50 @@ #include +#include #include "TracyAchievements.hpp" namespace tracy { +namespace data { extern AchievementCategory* AchievementCategories[]; } + AchievementsMgr::AchievementsMgr() { - m_queue.emplace_back( "Discover achievements!" ); - m_queue.emplace_back( "Achievements are fun!" ); - m_queue.emplace_back( "The new beginnings are always the best!" ); + auto cat = data::AchievementCategories; + while( *cat ) + { + FillMap( (*cat)->items, *cat ); + cat++; + } } -const std::string* AchievementsMgr::GetNextQueue() +void AchievementsMgr::Achieve( const char* id ) +{ + auto it = m_map.find( id ); + assert( it != m_map.end() ); + if( it->second.item->doneTime > 0 ) return; + + const auto t = uint64_t( time( nullptr ) ); + + it->second.item->doneTime = uint64_t( t ); + m_queue.push_back( it->second.item ); + + auto c = it->second.item->items; + if( c ) + { + while( *c ) (*c++)->unlockTime = t; + } +} + +data::AchievementCategory** AchievementsMgr::GetCategories() const +{ + return data::AchievementCategories; +} + +data::AchievementItem* AchievementsMgr::GetNextQueue() { if( m_queue.empty() ) return nullptr; - return &m_queue.front(); + return m_queue.front(); } void AchievementsMgr::PopQueue() @@ -29,4 +58,14 @@ bool AchievementsMgr::NeedsUpdates() const return false; } +void AchievementsMgr::FillMap( data::AchievementItem** items, data::AchievementCategory* category ) +{ + while( *items ) + { + m_map.emplace( (*items)->id, AchievementPair { *items, category } ); + if( (*items)->items) FillMap( (*items)->items, category ); + items++; + } +} + } diff --git a/profiler/src/profiler/TracyAchievements.hpp b/profiler/src/profiler/TracyAchievements.hpp index 83961c5b..90aef461 100644 --- a/profiler/src/profiler/TracyAchievements.hpp +++ b/profiler/src/profiler/TracyAchievements.hpp @@ -5,6 +5,11 @@ #include #include +#include "imgui.h" + +#include "TracyCharUtil.hpp" +#include "tracy_robin_hood.h" + namespace tracy { @@ -43,16 +48,28 @@ struct AchievementCategory class AchievementsMgr { + struct AchievementPair + { + data::AchievementItem* item; + data::AchievementCategory* category; + }; + public: AchievementsMgr(); - const std::string* GetNextQueue(); + void Achieve( const char* id ); + data::AchievementCategory** GetCategories() const; + + data::AchievementItem* GetNextQueue(); void PopQueue(); bool NeedsUpdates() const; private: - std::vector m_queue; + void FillMap( data::AchievementItem** items, data::AchievementCategory* category ); + + std::vector m_queue; + tracy::unordered_flat_map m_map; }; }