1
0
mirror of synced 2024-11-14 18:47:41 +01:00

Density Graph WIP again

This commit is contained in:
Stepland 2020-02-18 01:44:21 +01:00
parent 8bea6a4226
commit 9bbcff7cf5
18 changed files with 343 additions and 257 deletions

View File

@ -24,40 +24,40 @@ sources = [
'include/imgui/imgui_draw.cpp',
'include/imgui/imgui_widgets.cpp',
'include/imgui-sfml/imgui-SFML.cpp',
'src/Main.cpp',
'src/Data/Buttons.hpp',
'src/Data/Buttons.cpp',
'src/Data/Chart.cpp',
'src/Data/Chart.hpp',
'src/Data/KeyMapping.hpp',
'src/Data/KeyMapping.cpp',
'src/Data/Note.hpp',
'src/Data/Preferences.hpp',
'src/Data/Score.hpp',
'src/Data/SongList.hpp',
'src/Data/SongList.cpp',
# 'src/Screens/Gameplay.hpp',
'src/Screens/MusicSelect/ButtonHighlight.hpp',
'src/Screens/MusicSelect/ButtonHighlight.cpp',
# 'src/Screens/MusicSelect/DensityGraph.hpp',
# 'src/Screens/MusicSelect/DensityGraph.cpp',
'src/Screens/MusicSelect/MusicSelect.hpp',
'src/Screens/MusicSelect/MusicSelect.cpp',
'src/Screens/MusicSelect/Panel.hpp',
'src/Screens/MusicSelect/Panel.cpp',
'src/Screens/MusicSelect/SharedResources.hpp',
'src/Screens/MusicSelect/SharedResources.cpp',
'src/Screens/MusicSelect/SongInfo.hpp',
'src/Screens/MusicSelect/SongInfo.cpp',
'src/Screens/MusicSelect/Ribbon.hpp',
'src/Screens/MusicSelect/Ribbon.cpp',
# 'src/Screens/Result.hpp',
'src/Data/Song.hpp',
'src/Data/Song.cpp',
'src/Resources/TextureCache.cpp',
'src/Resources/TextureCache.hpp',
# 'src/Resources/CoverAtlas.hpp',
# 'src/Resources/CoverAtlas.cpp',
# 'src/Screens/Gameplay.hpp',
'src/Screens/MusicSelect/ButtonHighlight.hpp',
'src/Screens/MusicSelect/ButtonHighlight.cpp',
'src/Screens/MusicSelect/DensityGraph.hpp',
'src/Screens/MusicSelect/DensityGraph.cpp',
'src/Screens/MusicSelect/MusicSelect.hpp',
'src/Screens/MusicSelect/MusicSelect.cpp',
'src/Screens/MusicSelect/Panel.hpp',
'src/Screens/MusicSelect/Panel.cpp',
'src/Screens/MusicSelect/Ribbon.hpp',
'src/Screens/MusicSelect/Ribbon.cpp',
'src/Screens/MusicSelect/SharedResources.hpp',
'src/Screens/MusicSelect/SharedResources.cpp',
'src/Screens/MusicSelect/SongInfo.hpp',
'src/Screens/MusicSelect/SongInfo.cpp',
# 'src/Screens/Result.hpp',
'src/Toolkit/AffineTransform.hpp',
'src/Toolkit/Debuggable.hpp',
'src/Toolkit/Cache.hpp',
'src/Toolkit/Debuggable.hpp',
'src/Toolkit/EasingFunctions.hpp',
'src/Toolkit/EasingFunctions.cpp',
'src/Toolkit/HSL.hpp',
@ -65,6 +65,7 @@ sources = [
'src/Toolkit/NormalizedOrigin.hpp',
'src/Toolkit/QuickRNG.hpp',
'src/Toolkit/QuickRNG.cpp',
'src/Main.cpp',
]
executable(

View File

@ -5,24 +5,28 @@
#include "Buttons.hpp"
namespace Data {
Chart::Chart(const stepland::memon& memon, const std::string& chart_name) {
auto it = memon.charts.find(chart_name);
Chart::Chart(const stepland::memon& memon, const std::string& difficulty) {
auto it = memon.charts.find(difficulty);
if (it == memon.charts.end()) {
throw std::invalid_argument("Memon file has no "+chart_name+" chart");
throw std::invalid_argument("Memon file has no "+difficulty+" chart");
}
auto [_, chart] = *it;
level = static_cast<unsigned int>(chart.level);
level = chart.level;
resolution = static_cast<std::size_t>(chart.resolution);
Toolkit::AffineTransform<float> memon_timing_to_300Hz(
0.f, static_cast<float>(chart.resolution),
-memon.offset*300.f, (-memon.offset+60.f/memon.BPM)*300.f
);
Toolkit::AffineTransform<float> memon_timing_to_300Hz_proportional(
0.f, static_cast<float>(chart.resolution),
0.f, (60.f/memon.BPM)*300.f
);
for (auto &&note : chart.notes) {
auto timing = static_cast<std::size_t>(memon_timing_to_300Hz.transform(note.get_timing()));
auto position = static_cast<Button>(note.get_pos());
auto length = static_cast<std::size_t>(note.get_length());
auto length = static_cast<std::size_t>(memon_timing_to_300Hz_proportional.transform(note.get_length()));
auto tail = convert_memon_tail(position, note.get_tail_pos());
notes.emplace(timing, position, length, tail);
notes.insert({timing, position, length, tail});
}
}

View File

@ -10,8 +10,8 @@
namespace Data {
struct Chart {
explicit Chart(const stepland::memon& memon, const std::string& chart);
unsigned int level;
Chart(const stepland::memon& memon, const std::string& difficulty);
int level;
std::set<Note> notes;
std::size_t resolution;
};

View File

@ -4,10 +4,10 @@
namespace Data {
struct Note {
// Timing is stored as ticks on a 300Hz clock
std::size_t timing;
// Timing is stored as ticks on a 300Hz clock starting at the begging of the audio
long int timing;
Button position;
// zero is standard note
// zero length means it's a standard note
std::size_t length;
Button tail;

133
src/Data/Song.cpp Normal file
View File

@ -0,0 +1,133 @@
#include "Song.hpp"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <list>
#include <memon.hpp>
namespace fs = ghc::filesystem;
namespace Data {
bool cmp_dif_name::operator()(const std::string &a, const std::string &b) const {
if (dif_names.find(a) != dif_names.end()) {
if (dif_names.find(b) != dif_names.end()) {
return dif_names.find(a)->second < dif_names.find(b)->second;
} else {
return true;
}
} else {
if (dif_names.find(b) != dif_names.end()) {
return false;
} else {
return a < b;
}
}
}
std::optional<fs::path> Song::full_cover_path() const {
if (cover) {
return folder/cover.value();
} else {
return {};
}
}
std::optional<fs::path> Song::full_audio_path() const {
if (audio) {
return folder/audio.value();
} else {
return {};
}
}
SongList::SongList() :
songs()
{
fs::path song_folder = "songs/";
if (fs::exists(song_folder) and fs::is_directory(song_folder)) {
for (const auto& dir_item : fs::directory_iterator("songs/")) {
if (dir_item.is_directory()) {
songs.splice(songs.end(), recursiveSongSearch(dir_item.path()));
}
}
}
std::cout << "Loaded Data::SongList, found " << songs.size() << " songs" << std::endl;
}
std::list<std::shared_ptr<Song>> recursiveSongSearch(fs::path song_or_pack) {
std::list<std::shared_ptr<Song>> res;
// First try : any .memo file in the folder ?
fs::directory_iterator folder_memo{song_or_pack};
if (
std::any_of(
fs::begin(folder_memo),
fs::end(folder_memo),
[](const fs::directory_entry& de) {return de.path().extension() == ".memo";}
)
) {
throw std::invalid_argument("jujube does not support .memo files for now ...");
}
// Second try : any .memon file in the folder ?
// if yes get the first one
fs::directory_iterator folder_memon{song_or_pack};
auto memon_path = std::find_if(
fs::begin(folder_memon),
fs::end(folder_memon),
[](const fs::directory_entry& de) {return de.path().extension() == ".memon";}
);
if (memon_path != fs::end(folder_memon)) {
res.push_back(std::make_shared<MemonSong>(memon_path->path()));
return res;
}
// Nothing found : recurse in subfolders
for (auto& p : fs::directory_iterator(song_or_pack)) {
if (p.is_directory()) {
res.splice(res.end(), recursiveSongSearch(p));
}
}
return res;
}
MemonSong::MemonSong(const fs::path& t_memon_path) :
memon_path(t_memon_path)
{
auto song_folder = t_memon_path.parent_path();
folder = song_folder;
stepland::memon m;
{
std::ifstream file(t_memon_path);
file >> m;
}
this->title = m.song_title;
this->artist = m.artist;
if (not m.album_cover_path.empty()) {
this->cover.emplace(m.album_cover_path);
}
if (not m.music_path.empty()) {
this->audio.emplace(m.music_path);
}
for (const auto& [difficulty, chart] : m.charts) {
this->chart_levels[difficulty] = chart.level;
}
}
std::optional<Chart> MemonSong::get_chart(const std::string& difficulty) const {
stepland::memon m;
{
std::ifstream file(memon_path);
file >> m;
}
auto chart = m.charts.find(difficulty);
if (chart == m.charts.end()) {
return {};
} else {
return Chart(m, difficulty);
}
}
}

View File

@ -4,9 +4,13 @@
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <variant>
#include <unordered_map>
#include "Chart.hpp"
namespace fs = ghc::filesystem;
@ -22,8 +26,6 @@ namespace Data {
// Basic metadata about a song
struct Song {
Song() = default;
explicit Song(fs::path song_folder);
fs::path folder;
std::string title;
std::string artist;
@ -35,24 +37,39 @@ namespace Data {
std::map<std::string, unsigned int, cmp_dif_name> chart_levels;
std::optional<fs::path> full_cover_path() const;
std::optional<fs::path> full_audio_path() const;
virtual std::optional<Chart> get_chart(const std::string& difficulty) const = 0;
static bool sort_by_title(const Data::Song& a, const Data::Song& b) {
return a.title < b.title;
}
virtual ~Song() = default;
};
struct MemonSong : public Song {
explicit MemonSong(const fs::path& memon_path);
std::optional<Chart> get_chart(const std::string& difficulty) const;
private:
fs::path memon_path;
};
/*
struct MemoSong : public Song {
explicit MemoSong(const std::unordered_map<std::string, fs::path>& memo_paths);
private:
std::unordered_map<std::string, fs::path> memo_paths;
};
*/
// Class holding all the necessary song data to run the Music Select screen
class SongList {
public:
SongList();
std::vector<Song> songs;
std::list<std::shared_ptr<Song>> songs;
};
// Returns the folders conscidered to contain a valid song
// classic memo files should have the .memo extension
// .memon files also accepted
const std::vector<fs::path> getSongFolders();
std::list<fs::path> recursiveSongSearch(fs::path song_or_pack);
const std::vector<fs::path> getMemoFiles(fs::path song_folder);
const std::vector<fs::path> getMemonFiles(fs::path song_folder);
std::list<std::shared_ptr<Song>> recursiveSongSearch(fs::path song_or_pack);
}

View File

@ -1,152 +0,0 @@
#include "SongList.hpp"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <list>
#include <memon.hpp>
namespace fs = ghc::filesystem;
namespace Data {
bool cmp_dif_name::operator()(const std::string &a, const std::string &b) const {
if (dif_names.find(a) != dif_names.end()) {
if (dif_names.find(b) != dif_names.end()) {
return dif_names.find(a)->second < dif_names.find(b)->second;
} else {
return true;
}
} else {
if (dif_names.find(b) != dif_names.end()) {
return false;
} else {
return a < b;
}
}
}
std::optional<fs::path> Song::full_cover_path() const {
if (cover) {
return folder/cover.value();
} else {
return {};
}
}
SongList::SongList::SongList() {
// Loading all song metadata
for (const auto& folder : getSongFolders()) {
try {
songs.emplace_back(folder);
} catch (const std::exception& e) {
std::cerr << "Exception while parsing song folder "
<< folder.string() << " : " << e.what() << '\n';
continue;
}
}
}
const std::vector<fs::path> getSongFolders() {
std::vector<fs::path> potential_song_folders;
fs::path song_folder = "songs/";
if (fs::exists(song_folder) and fs::is_directory(song_folder)) {
for (const auto& dir_item : fs::directory_iterator("songs/")) {
if (dir_item.is_directory()) {
for (auto& path : recursiveSongSearch(dir_item.path())) {
potential_song_folders.push_back(path);
}
}
}
}
return potential_song_folders;
}
std::list<fs::path> recursiveSongSearch(fs::path song_or_pack) {
std::list<fs::path> res;
fs::directory_iterator folder{song_or_pack};
if (
std::any_of(
fs::begin(folder),
fs::end(folder),
[](const fs::directory_entry& de) {
return de.path().extension() == ".memo" or
de.path().extension() == ".memon";
}
)
) {
res.push_back(song_or_pack);
return res;
} else {
for (auto& p : fs::directory_iterator(song_or_pack)) {
if (p.is_directory()) {
res.splice(res.end(), recursiveSongSearch(p));
}
}
return res;
}
}
Song::Song(fs::path song_folder) :
folder(song_folder)
{
// .memon ?
auto memon_files = getMemonFiles(song_folder);
if (not memon_files.empty()) {
if (memon_files.size() > 1) {
throw std::invalid_argument("Multiple .memon files");
} else {
stepland::memon m;
std::ifstream file(memon_files.back());
file >> m;
this->title = m.song_title;
this->artist = m.artist;
if (not m.album_cover_path.empty()) {
this->cover.emplace(m.album_cover_path);
}
if (not m.music_path.empty()) {
this->audio.emplace(m.music_path);
}
for (const auto& [difficulty, chart] : m.charts) {
this->chart_levels[difficulty] = chart.level;
}
}
} else {
// .memo ?
auto memo_files = getMemoFiles(song_folder);
if (not memo_files.empty()) {
throw std::invalid_argument("jujube does not support .memo files for now ...");
} else {
throw std::invalid_argument("No valid file found in song folder");
}
}
}
const std::vector<fs::path> getMemoFiles(fs::path song_folder) {
std::vector<fs::path> res;
for (const auto& p : fs::directory_iterator(song_folder)) {
if (p.path().extension() == ".memo") {
res.push_back(p.path());
}
}
return res;
}
const std::vector<fs::path> getMemonFiles(fs::path song_folder) {
std::vector<fs::path> res;
for (const auto& p : fs::directory_iterator(song_folder)) {
if (p.path().extension() == ".memon") {
res.push_back(p.path());
}
}
return res;
}
}

View File

@ -4,7 +4,7 @@
#include <SFML/Graphics.hpp>
#include <cereal/archives/json.hpp>
#include "Data/SongList.hpp"
#include "Data/Song.hpp"
#include "Data/Preferences.hpp"
// #include "Data/Chart.hpp"
// #include "Data/Score.hpp"

View File

@ -0,0 +1,49 @@
#include "DensityGraph.hpp"
#include <algorithm>
#include <functional>
#include <SFML/Audio.hpp>
namespace Data {
DensityGraph compute_density_graph_1(const SongDifficulty& sd) {
return compute_density_graph_2(sd.song, sd.difficulty);
}
DensityGraph compute_density_graph_2(const Song& song, const std::string& difficulty) {
auto c = song.get_chart(difficulty);
if (not c.has_value()) {
throw std::invalid_argument("Song "+song.title+" has no "+difficulty+" chart");
}
if (not song.audio.has_value()) {
return compute_density_graph_3(*c, c->notes.begin()->timing, c->notes.rbegin()->timing);
}
sf::Music m;
if (not m.openFromFile(*song.full_audio_path())) {
return compute_density_graph_3(*c, c->notes.begin()->timing, c->notes.rbegin()->timing);
}
return compute_density_graph_3(
*c,
std::min(0L, c->notes.begin()->timing),
std::max(c->notes.rbegin()->timing, static_cast<long>(m.getDuration().asMilliseconds()*3/10))
);
}
DensityGraph compute_density_graph_3(const Chart& chart, long start, long end) {
DensityGraph d{};
if (start != end) {
for (auto &&note : chart.notes) {
auto index = (note.timing-start)*115/(end-start);
d.at(index) += 1;
}
std::replace_if(
d.begin(),
d.end(),
std::bind(std::greater<unsigned int>(), std::placeholders::_1, 8),
8
);
}
return d;
}
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <array>
#include <tuple>
#include "../../Data/Chart.hpp"
#include "../../Data/Song.hpp"
#include "../../Toolkit/Cache.hpp"
namespace Data {
using DensityGraph = std::array<unsigned int, 115>;
struct SongDifficulty {
const Song& song;
const std::string& difficulty;
bool operator==(const SongDifficulty &other) const {
return (
song.folder == other.song.folder and
difficulty == other.difficulty
);
}
};
DensityGraph compute_density_graph_1(const SongDifficulty& sd);
DensityGraph compute_density_graph_2(const Song& song, const std::string& difficulty);
DensityGraph compute_density_graph_3(const Chart& chart, long start, long end);
using DensityGraphCache = Toolkit::Cache<SongDifficulty, DensityGraph, &compute_density_graph_1>;
}
namespace std {
template <>
struct hash<Data::SongDifficulty> {
std::size_t operator()(const Data::SongDifficulty& sd) const {
auto song_hash = std::hash<std::string>()(sd.song.folder.string());
song_hash ^= std::hash<std::string>()(sd.difficulty) + 0x9e3779b9 + (song_hash<<6) + (song_hash>>2);
return song_hash;
}
};
}

View File

@ -4,7 +4,7 @@
#include <SFML/Window.hpp>
#include "../../Data/SongList.hpp"
#include "../../Data/Song.hpp"
#include "../../Data/Chart.hpp"
#include "../../Data/KeyMapping.hpp"
#include "../../Toolkit/AffineTransform.hpp"

View File

@ -69,22 +69,22 @@ namespace MusicSelect {
void SongPanel::click(Ribbon& ribbon, std::size_t from_button_index) {
if (selected_chart.has_value()) {
// The song was already selected : look for the next chart in order
auto it = m_song.chart_levels.upper_bound(*selected_chart);
if (it != m_song.chart_levels.cend()) {
auto it = m_song->chart_levels.upper_bound(*selected_chart);
if (it != m_song->chart_levels.cend()) {
selected_chart = it->first;
} else {
selected_chart = m_song.chart_levels.cbegin()->first;
selected_chart = m_song->chart_levels.cbegin()->first;
}
m_resources.selected_panel->last_click.restart();
m_resources.selected_panel->is_first_click = false;
} else {
// Look for the first chart with dif greater or equal to the last select one
// or else select the first chart
auto it = m_song.chart_levels.lower_bound(m_resources.get_last_selected_chart());
if (it != m_song.chart_levels.cend()) {
auto it = m_song->chart_levels.lower_bound(m_resources.get_last_selected_difficulty());
if (it != m_song->chart_levels.cend()) {
selected_chart = it->first;
} else {
selected_chart = m_song.chart_levels.cbegin()->first;
selected_chart = m_song->chart_levels.cbegin()->first;
}
// The song was not selected before : first unselect the last one
if (m_resources.selected_panel.has_value()) {
@ -100,7 +100,7 @@ namespace MusicSelect {
std::optional<ChartSelection> SongPanel::get_selected_chart() const {
if (selected_chart) {
return ChartSelection{m_song, *selected_chart};
return ChartSelection{*m_song, *selected_chart};
} else {
return {};
}
@ -108,11 +108,11 @@ namespace MusicSelect {
void SongPanel::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
auto last_selected_chart = m_resources.get_last_selected_chart();
auto last_selected_chart = m_resources.get_last_selected_difficulty();
// We should gray out the panel if the currently selected difficulty doesn't exist for this song
bool should_be_grayed_out = m_song.chart_levels.find(last_selected_chart) == m_song.chart_levels.end();
if (m_song.cover) {
auto loaded_texture = m_resources.covers.async_get(m_song.folder/m_song.cover.value());
bool should_be_grayed_out = m_song->chart_levels.find(last_selected_chart) == m_song->chart_levels.end();
if (m_song->cover) {
auto loaded_texture = m_resources.covers.async_get(m_song->folder/m_song->cover.value());
if (loaded_texture) {
sf::Sprite cover{*(loaded_texture->texture)};
auto alpha = static_cast<std::uint8_t>(
@ -140,7 +140,7 @@ namespace MusicSelect {
}
target.draw(chart_dif_badge, states);
if (not should_be_grayed_out) {
auto dif = m_song.chart_levels.at(last_selected_chart);
auto dif = m_song->chart_levels.at(last_selected_chart);
sf::Text dif_label{
std::to_string(dif),
m_resources.noto_sans_medium,
@ -153,7 +153,7 @@ namespace MusicSelect {
}
sf::Text song_title;
song_title.setFont(m_resources.noto_sans_medium);
song_title.setString(m_song.title);
song_title.setString(m_song->title);
song_title.setCharacterSize(static_cast<unsigned int>(0.06875f*get_size()));
song_title.setFillColor(sf::Color::White);
auto song_title_bounds = song_title.getLocalBounds();

View File

@ -6,7 +6,7 @@
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include "../../Data/SongList.hpp"
#include "../../Data/Song.hpp"
#include "../../Toolkit/AffineTransform.hpp"
#include "SharedResources.hpp"
@ -64,7 +64,7 @@ namespace MusicSelect {
struct ChartSelection {
const Data::Song& song;
const std::string& chart;
const std::string& difficulty;
};
class SelectablePanel : public Panel {
@ -77,13 +77,13 @@ namespace MusicSelect {
class SongPanel final : public SelectablePanel {
public:
explicit SongPanel(SharedResources& resources, const Data::Song& t_song) : SelectablePanel(resources), m_song(t_song) {};
explicit SongPanel(SharedResources& resources, const std::shared_ptr<const Data::Song>& t_song) : SelectablePanel(resources), m_song(t_song) {};
void click(Ribbon& ribbon, std::size_t from_button_index) override;
void unselect() override;
std::optional<ChartSelection> get_selected_chart() const override;
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
const Data::Song& m_song;
std::shared_ptr<const Data::Song> m_song;
const Toolkit::AffineTransform<float> m_seconds_to_alpha{0.0f, 0.15f, 0.f, 255.f};
std::optional<std::string> selected_chart;
};

View File

@ -10,7 +10,7 @@
#include <vector>
#include "Panel.hpp"
#include "../../Data/SongList.hpp"
#include "../../Data/Song.hpp"
#include "../../Toolkit/QuickRNG.hpp"
@ -69,15 +69,19 @@ namespace MusicSelect {
}
void Ribbon::title_sort(const Data::SongList &song_list) {
std::vector<std::reference_wrapper<const Data::Song>> songs;
std::vector<std::shared_ptr<const Data::Song>> songs;
for (auto &&song : song_list.songs) {
songs.push_back(std::cref(song));
songs.push_back(song);
}
std::sort(songs.begin(), songs.end(), Data::Song::sort_by_title);
std::sort(
songs.begin(),
songs.end(),
[](std::shared_ptr<const Data::Song> a, std::shared_ptr<const Data::Song> b){return Data::Song::sort_by_title(*a, *b);}
);
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
for (const auto &song : songs) {
if (song.get().title.size() > 0) {
char letter = song.get().title[0];
if (song->title.size() > 0) {
char letter = song->title[0];
if ('A' <= letter and letter <= 'Z') {
categories
[std::string(1, letter)]
@ -140,21 +144,6 @@ namespace MusicSelect {
layout_from_category_map(categories);
}
void Ribbon::test_song_cover_sort() {
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
Toolkit::UniformIntRNG category_size_generator{1, 10};
for (auto &&letter : alphabet) {
auto category_size = category_size_generator.generate();
for (int i = 0; i < category_size; i++) {
categories[std::string(1, letter)].push_back(
std::make_shared<SongPanel>(m_resources, this->empty_song)
);
}
}
layout_from_category_map(categories);
}
std::size_t Ribbon::get_layout_column(const std::size_t& button_index) const {
return (m_position + (button_index % 4)) % m_layout.size();

View File

@ -6,7 +6,7 @@
#include <SFML/Graphics/Transformable.hpp>
#include "../../Data/Preferences.hpp"
#include "../../Data/SongList.hpp"
#include "../../Data/Song.hpp"
#include "../../Toolkit/AffineTransform.hpp"
#include "../../Toolkit/Debuggable.hpp"
#include "../../Toolkit/EasingFunctions.hpp"
@ -59,6 +59,5 @@ namespace MusicSelect {
std::size_t m_position = 0;
mutable std::optional<MoveAnimation> m_move_animation;
float m_time_factor = 1.f;
Data::Song empty_song;
};
}

View File

@ -22,11 +22,11 @@ namespace MusicSelect {
std::cout << "Loaded MusicSelect::SharedResources" << std::endl;
}
std::string SharedResources::get_last_selected_chart() {
return get_selected_chart().value_or("BSC");
std::string SharedResources::get_last_selected_difficulty() {
return get_selected_difficulty().value_or("BSC");
}
std::optional<std::string> SharedResources::get_selected_chart() {
std::optional<std::string> SharedResources::get_selected_difficulty() {
if (not selected_panel.has_value()) {
return {};
}
@ -34,7 +34,7 @@ namespace MusicSelect {
if (not chart_selection.has_value()) {
return {};
}
return chart_selection->chart;
return chart_selection->difficulty;
}
std::optional<std::reference_wrapper<const Data::Song>> MusicSelect::SharedResources::get_selected_song() {

View File

@ -8,7 +8,9 @@
#include "../../Resources/TextureCache.hpp"
#include "../../Data/Preferences.hpp"
#include "../../Data/SongList.hpp"
#include "../../Data/Song.hpp"
#include "DensityGraph.hpp"
namespace MusicSelect {
@ -32,9 +34,11 @@ namespace MusicSelect {
sf::Font noto_sans_medium;
Data::DensityGraphCache density_graphs;
std::optional<TimedSelectedPanel> selected_panel;
std::string get_last_selected_chart();
std::optional<std::string> get_selected_chart();
std::string get_last_selected_difficulty();
std::optional<std::string> get_selected_difficulty();
std::optional<std::reference_wrapper<const Data::Song>> get_selected_song();
sf::Color BSC_color = sf::Color{34,216,92};

View File

@ -52,9 +52,10 @@ namespace MusicSelect {
target.draw(cover, states);
}
SongInfo::SongInfo(SharedResources& resources) : HoldsSharedResources(resources), m_big_cover(resources) {
}
SongInfo::SongInfo(SharedResources& resources) :
HoldsSharedResources(resources),
m_big_cover(resources)
{}
void SongInfo::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
@ -142,7 +143,7 @@ namespace MusicSelect {
target.draw(level_label, states);
sf::Text level_number_label{
std::to_string(selected_chart->song.chart_levels.at(selected_chart->chart)),
std::to_string(selected_chart->song.chart_levels.at(selected_chart->difficulty)),
m_resources.noto_sans_medium,
static_cast<unsigned int>(130.f/768.f*get_screen_width())
};
@ -151,23 +152,23 @@ namespace MusicSelect {
level_number_label.setFillColor(sf::Color::White);
target.draw(level_number_label, states);
std::string full_chart_name = selected_chart->chart;
if (selected_chart->chart == "BSC") {
full_chart_name = "BASIC";
} else if (selected_chart->chart == "ADV") {
full_chart_name = "ADVANCED";
} else if (selected_chart->chart == "EXT") {
full_chart_name = "EXTREME";
std::string full_difficulty = selected_chart->difficulty;
if (selected_chart->difficulty == "BSC") {
full_difficulty = "BASIC";
} else if (selected_chart->difficulty == "ADV") {
full_difficulty = "ADVANCED";
} else if (selected_chart->difficulty == "EXT") {
full_difficulty = "EXTREME";
}
sf::Text chart_label{
full_chart_name,
full_difficulty,
m_resources.noto_sans_medium,
static_cast<unsigned int>(20.f/768.f*get_screen_width())
};
Toolkit::set_origin_normalized_no_position(chart_label, 0.5f, 0.f);
chart_label.setPosition(get_big_level_x(), get_big_level_y()+(145.f/768.f*get_screen_width()));
chart_label.setFillColor(m_resources.get_chart_color(selected_chart->chart));
chart_label.setFillColor(m_resources.get_chart_color(selected_chart->difficulty));
target.draw(chart_label, states);
}
@ -185,13 +186,13 @@ namespace MusicSelect {
auto dif_badge_y = 40.f/768.f*get_screen_width();
auto dif_badge_step = 3.f*dif_badge_radius;
std::size_t dif_index = 0;
for (auto &&[chart_name, level] : selected_chart->song.chart_levels) {
for (auto &&[difficulty, level] : selected_chart->song.chart_levels) {
sf::CircleShape dif_badge{dif_badge_radius};
Toolkit::set_origin_normalized(dif_badge, 0.5f, 0.5f);
dif_badge.setFillColor(m_resources.get_chart_color(chart_name));
dif_badge.setFillColor(m_resources.get_chart_color(difficulty));
dif_badge.setPosition(dif_badge_x+dif_index*dif_badge_step, dif_badge_y);
target.draw(dif_badge, states);
if (chart_name == selected_chart->chart) {
if (difficulty == selected_chart->difficulty) {
sf::CircleShape select_triangle(dif_badge_radius, 3);
Toolkit::set_origin_normalized(select_triangle, 0.5f, 0.5f);
select_triangle.rotate(180.f);