diff --git a/samples/golf/src/golf/StatsState.cpp b/samples/golf/src/golf/StatsState.cpp index a3488b67f..c6e5ff9a6 100644 --- a/samples/golf/src/golf/StatsState.cpp +++ b/samples/golf/src/golf/StatsState.cpp @@ -461,7 +461,7 @@ void StatsState::parseCourseData() if (auto* prop = cfg.findProperty("title"); prop != nullptr) { const auto courseTitle = prop->getValue(); - m_courseStrings.emplace_back(cro::String::fromUtf8(courseTitle.begin(), courseTitle.end())); + m_courseStrings.emplace_back(std::make_pair(dir, cro::String::fromUtf8(courseTitle.begin(), courseTitle.end()))); } } } @@ -497,6 +497,7 @@ void StatsState::createClubStatsTab(cro::Entity parent, const cro::SpriteSheet& cro::Colour(0x6eb39dff), //blue cro::Colour(0xf2cf5cff), //yellow cro::Colour(0xec773dff), //orange + //CD32::Colours[CD32::OrangeDirt] }; struct ColourID final { @@ -581,14 +582,14 @@ void StatsState::createClubStatsTab(cro::Entity parent, const cro::SpriteSheet& { label += "|\n"; } - label += "Top/Side"; + //label += "Top/Side"; labelEnt = m_scene.createEntity(); labelEnt.addComponent().setPosition({ 4.f, -11.f, 0.3f }); labelEnt.addComponent(); labelEnt.addComponent(font).setString(label); labelEnt.getComponent().setCharacterSize(InfoTextSize); - labelEnt.getComponent().setFillColour(LeaderboardTextDark); + labelEnt.getComponent().setFillColour(CD32::Colours[CD32::BlueLight]); labelEnt.getComponent().setVerticalSpacing(-1.f); statNode.getComponent().addChild(labelEnt.getComponent()); @@ -716,17 +717,25 @@ void StatsState::createHistoryTab(cro::Entity parent) //TODO call for a global refresh when opening menu //TODO add message handler to refresh the pie charts when new data received - //pie charts - left side number of times personally played a course - //right side aggregated stats from steam of course plays + //pie charts - number of times personally played a course + //and aggregated stats from steam of course plays + for (std::int32_t i = StatID::Course01Complete; i < StatID::Course10Complete + 1; ++i) + { + m_pieCharts[0].addValue(Achievements::getStat(StatStrings[i])->value); + m_pieCharts[1].addValue(Achievements::getGlobalStat(StatStrings[i])->value); + } const auto& font = m_sharedData.sharedResources->fonts.get(FontID::Info); + const auto& labelFont = m_sharedData.sharedResources->fonts.get(FontID::Label); + //our pie auto entity = m_scene.createEntity(); - entity.addComponent().setPosition({ 120.f, 230.f, 0.2f }); + entity.addComponent().setPosition({ 116.f, 230.f, 0.2f }); entity.addComponent().setPrimitiveType(GL_TRIANGLES); m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); m_pieCharts[0].setEntity(entity); + //our pie title auto pie = entity; entity = m_scene.createEntity(); entity.addComponent().setPosition({ 0.f, PieRadius + 12.f, 0.1f }); @@ -739,12 +748,27 @@ void StatsState::createHistoryTab(cro::Entity parent) centreText(entity); pie.getComponent().addChild(entity.getComponent()); + //our pie total entity = m_scene.createEntity(); - entity.addComponent().setPosition({ 120.f, 100.f, 0.2f }); + entity.addComponent().setPosition({ -(PieRadius + 28.f), 10.f, 0.1f }); + entity.addComponent(); + entity.addComponent(labelFont).setString(std::to_string(static_cast(m_pieCharts[0].getTotal())) + "\nRounds"); + entity.getComponent().setCharacterSize(LabelTextSize); + entity.getComponent().setFillColour(TextNormalColour); + entity.getComponent().setShadowColour(LeaderboardTextDark); + entity.getComponent().setShadowOffset({ 1.f, -1.f }); + entity.getComponent().setAlignment(cro::Text::Alignment::Centre); + pie.getComponent().addChild(entity.getComponent()); + + + //global pie + entity = m_scene.createEntity(); + entity.addComponent().setPosition({ 116.f, 100.f, 0.2f }); entity.addComponent().setPrimitiveType(GL_TRIANGLES); m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); m_pieCharts[1].setEntity(entity); + //global pie title pie = entity; entity = m_scene.createEntity(); entity.addComponent().setPosition({ 0.f, PieRadius + 12.f, 0.1f }); @@ -757,12 +781,17 @@ void StatsState::createHistoryTab(cro::Entity parent) centreText(entity); pie.getComponent().addChild(entity.getComponent()); - - for (std::int32_t i = StatID::Course01Complete; i < StatID::Course10Complete + 1; ++i) - { - m_pieCharts[0].addValue(Achievements::getStat(StatStrings[i])->value); - m_pieCharts[1].addValue(Achievements::getGlobalStat(StatStrings[i])->value); - } + //global pie total + entity = m_scene.createEntity(); + entity.addComponent().setPosition({ -(PieRadius + 28.f), 10.f, 0.1f }); + entity.addComponent(); + entity.addComponent(labelFont).setString(std::to_string(static_cast(m_pieCharts[1].getTotal())) + "\nRounds"); + entity.getComponent().setCharacterSize(LabelTextSize); + entity.getComponent().setFillColour(TextNormalColour); + entity.getComponent().setShadowColour(LeaderboardTextDark); + entity.getComponent().setShadowOffset({ 1.f, -1.f }); + entity.getComponent().setAlignment(cro::Text::Alignment::Centre); + pie.getComponent().addChild(entity.getComponent()); m_pieCharts[0].updateVerts(); m_pieCharts[1].updateVerts(); @@ -785,6 +814,7 @@ void StatsState::createHistoryTab(cro::Entity parent) //are not easily refreshable... cro::String nameList; + cro::String countList; std::vector verts; const float VerticalSpacing = -17.f; glm::vec2 vertPos = glm::vec2(0.f); @@ -793,13 +823,13 @@ void StatsState::createHistoryTab(cro::Entity parent) for (auto i = 0u; i < m_courseStrings.size(); ++i) { - /*std::stringstream ss; - ss.precision(1); - ss << m_pieCharts[0].getPercentage(i) << "% - "; - ss.precision(1); - ss << m_pieCharts[1].getPercentage(1) << "% "; - nameList += ss.str() + m_courseStrings[i] + "\n";*/ - nameList += m_courseStrings[i] + "\n"; + m_playTimeChart.addBar(Achievements::getAvgStat(m_courseStrings[i].first)); + + std::stringstream ss; + ss << std::int32_t(m_pieCharts[0].getValue(i)) << "|" << std::int32_t(m_pieCharts[1].getValue(i)); + countList += ss.str() + "\n"; + + nameList += m_courseStrings[i].second + "\n"; verts.emplace_back(glm::vec2(-ColourSize.x, ColourSize.y) + vertPos, CD32::Colours[colourIndex]); verts.emplace_back(-ColourSize + vertPos, CD32::Colours[colourIndex]); @@ -813,9 +843,9 @@ void StatsState::createHistoryTab(cro::Entity parent) colourIndex++; } - const auto& labelFont = m_sharedData.sharedResources->fonts.get(FontID::Label); + //course name list entity = m_scene.createEntity(); - entity.addComponent().setPosition({ 230.f, 264.f, 0.1f }); + entity.addComponent().setPosition({ 248.f, 282.f, 0.1f }); entity.addComponent(); entity.addComponent(labelFont).setString(nameList); entity.getComponent().setCharacterSize(LabelTextSize); @@ -825,12 +855,75 @@ void StatsState::createHistoryTab(cro::Entity parent) entity.getComponent().setVerticalSpacing(4.f); m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); + //colours auto strEnt = entity; entity = m_scene.createEntity(); - entity.addComponent().setPosition({ -12.f, -5.f, 0.f }); + entity.addComponent().setPosition({ -11.f, -5.f, 0.f }); entity.addComponent().setPrimitiveType(GL_TRIANGLES); entity.getComponent().setVertexData(verts); strEnt.getComponent().addChild(entity.getComponent()); + + + //play count list + entity = m_scene.createEntity(); + entity.addComponent().setPosition({ 223.f, 282.f, 0.1f }); + entity.addComponent(); + entity.addComponent(labelFont).setString(countList); + entity.getComponent().setCharacterSize(LabelTextSize); + entity.getComponent().setFillColour(TextNormalColour); + entity.getComponent().setShadowColour(LeaderboardTextDark); + entity.getComponent().setShadowOffset({ 1.f, -1.f }); + entity.getComponent().setVerticalSpacing(4.f); + entity.getComponent().setAlignment(cro::Text::Alignment::Right); + m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); + + + + + + //bar chart for play time + entity = m_scene.createEntity(); + entity.addComponent().setPosition({ 224.f, 98.f, 0.1f }); + entity.addComponent(); + entity.addComponent(largeFont).setString("Your Average Play Duration"); + entity.getComponent().setCharacterSize(UITextSize); + entity.getComponent().setFillColour(TextNormalColour); + entity.getComponent().setShadowColour(LeaderboardTextDark); + entity.getComponent().setShadowOffset({ 1.f, -1.f }); + m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); + + entity = m_scene.createEntity(); + entity.addComponent().setPosition({ 242.f, 40.f, 0.1f }); + entity.addComponent().setPrimitiveType(GL_TRIANGLES); + m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); + + m_playTimeChart.setEntity(entity); + m_playTimeChart.updateVerts(); + + cro::String timeString; + const float playTime = m_playTimeChart.getMaxValue(); + if (playTime > 60.f) + { + auto secs = static_cast(playTime); + auto mins = secs / 60; + secs %= 60; + + timeString = std::to_string(mins) + "m " + std::to_string(secs) + "s"; + } + else + { + timeString = std::to_string(static_cast(playTime)) + "s"; + } + timeString += "\n|\n|\n0s"; + + entity = m_scene.createEntity(); + entity.addComponent().setPosition({ 390.f, 84.f, 0.1f }); + entity.addComponent(); + entity.addComponent(labelFont).setString(timeString); + entity.getComponent().setCharacterSize(LabelTextSize); + entity.getComponent().setFillColour(TextNormalColour); + entity.getComponent().setShadowColour(LeaderboardTextDark); + m_tabNodes[TabID::History].getComponent().addChild(entity.getComponent()); } void StatsState::createAwardsTab(cro::Entity parent) @@ -969,4 +1062,60 @@ float PieChart::getPercentage(std::uint32_t index) const return (m_values[index] / m_total) * 100.f; } return 0.f; +} + + +/////-----------------///// + + +BarChart::BarChart() + : m_maxValue(0.f) +{ + +} + +//public +void BarChart::addBar(float value) +{ + m_maxValue = std::max(value, m_maxValue); + m_values.push_back(value); +} + +void BarChart::updateVerts() +{ + if (m_maxValue != 0 + && m_entity.isValid() + && m_entity.hasComponent()) + { + constexpr float BarWidth = 12.f; + constexpr float Stride = BarWidth + 1.f; + std::int32_t colourIndex = PieBaseColour; + + std::vector verts; + + float xPos = 0.f; + for (auto v : m_values) + { + const float barHeight = std::round(MaxHeight * (v / m_maxValue)) + 1.f; + + verts.emplace_back(glm::vec2(xPos + BarWidth, barHeight), CD32::Colours[colourIndex]); + verts.emplace_back(glm::vec2(xPos, barHeight), CD32::Colours[colourIndex]); + verts.emplace_back(glm::vec2(xPos, 0.f), CD32::Colours[colourIndex]); + + verts.emplace_back(glm::vec2(xPos, 0.f), CD32::Colours[colourIndex]); + verts.emplace_back(glm::vec2(xPos + BarWidth, 0.f), CD32::Colours[colourIndex]); + verts.emplace_back(glm::vec2(xPos + BarWidth, barHeight), CD32::Colours[colourIndex]); + + xPos += Stride; + colourIndex++; + } + + + m_entity.getComponent().setVertexData(verts); + } +} + +void BarChart::setEntity(cro::Entity e) +{ + m_entity = e; } \ No newline at end of file diff --git a/samples/golf/src/golf/StatsState.hpp b/samples/golf/src/golf/StatsState.hpp index cbcdee390..9f9fd3524 100644 --- a/samples/golf/src/golf/StatsState.hpp +++ b/samples/golf/src/golf/StatsState.hpp @@ -53,6 +53,8 @@ class PieChart final void setEntity(cro::Entity); //entity with drawable to update float getPercentage(std::uint32_t) const; + float getTotal() const { return m_total; } + float getValue(std::uint32_t i) { return m_values[i]; } private: float m_total; @@ -60,6 +62,23 @@ class PieChart final cro::Entity m_entity; }; +class BarChart final +{ +public: + BarChart(); + + void addBar(float); + void updateVerts(); + void setEntity(cro::Entity); + float getMaxValue() const { return m_maxValue; } + +private: + float m_maxValue; + std::vector m_values; + cro::Entity m_entity; + static constexpr float MaxHeight = 36.f; +}; + class StatsState final : public cro::State { public: @@ -112,8 +131,8 @@ class StatsState final : public cro::State bool m_imperialMeasurements; std::array m_pieCharts = {}; - - std::vector m_courseStrings; + BarChart m_playTimeChart; + std::vector> m_courseStrings; void buildScene(); void parseCourseData();