Density Graph WIP again
This commit is contained in:
parent
8bea6a4226
commit
9bbcff7cf5
41
meson.build
41
meson.build
@ -24,40 +24,40 @@ sources = [
|
|||||||
'include/imgui/imgui_draw.cpp',
|
'include/imgui/imgui_draw.cpp',
|
||||||
'include/imgui/imgui_widgets.cpp',
|
'include/imgui/imgui_widgets.cpp',
|
||||||
'include/imgui-sfml/imgui-SFML.cpp',
|
'include/imgui-sfml/imgui-SFML.cpp',
|
||||||
'src/Main.cpp',
|
|
||||||
'src/Data/Buttons.hpp',
|
'src/Data/Buttons.hpp',
|
||||||
'src/Data/Buttons.cpp',
|
'src/Data/Buttons.cpp',
|
||||||
|
'src/Data/Chart.cpp',
|
||||||
'src/Data/Chart.hpp',
|
'src/Data/Chart.hpp',
|
||||||
'src/Data/KeyMapping.hpp',
|
'src/Data/KeyMapping.hpp',
|
||||||
'src/Data/KeyMapping.cpp',
|
'src/Data/KeyMapping.cpp',
|
||||||
'src/Data/Note.hpp',
|
'src/Data/Note.hpp',
|
||||||
'src/Data/Preferences.hpp',
|
'src/Data/Preferences.hpp',
|
||||||
'src/Data/Score.hpp',
|
'src/Data/Score.hpp',
|
||||||
'src/Data/SongList.hpp',
|
'src/Data/Song.hpp',
|
||||||
'src/Data/SongList.cpp',
|
'src/Data/Song.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/Resources/TextureCache.cpp',
|
'src/Resources/TextureCache.cpp',
|
||||||
'src/Resources/TextureCache.hpp',
|
'src/Resources/TextureCache.hpp',
|
||||||
# 'src/Resources/CoverAtlas.hpp',
|
# 'src/Resources/CoverAtlas.hpp',
|
||||||
# 'src/Resources/CoverAtlas.cpp',
|
# '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/AffineTransform.hpp',
|
||||||
'src/Toolkit/Debuggable.hpp',
|
|
||||||
'src/Toolkit/Cache.hpp',
|
'src/Toolkit/Cache.hpp',
|
||||||
|
'src/Toolkit/Debuggable.hpp',
|
||||||
'src/Toolkit/EasingFunctions.hpp',
|
'src/Toolkit/EasingFunctions.hpp',
|
||||||
'src/Toolkit/EasingFunctions.cpp',
|
'src/Toolkit/EasingFunctions.cpp',
|
||||||
'src/Toolkit/HSL.hpp',
|
'src/Toolkit/HSL.hpp',
|
||||||
@ -65,6 +65,7 @@ sources = [
|
|||||||
'src/Toolkit/NormalizedOrigin.hpp',
|
'src/Toolkit/NormalizedOrigin.hpp',
|
||||||
'src/Toolkit/QuickRNG.hpp',
|
'src/Toolkit/QuickRNG.hpp',
|
||||||
'src/Toolkit/QuickRNG.cpp',
|
'src/Toolkit/QuickRNG.cpp',
|
||||||
|
'src/Main.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
|
@ -5,24 +5,28 @@
|
|||||||
#include "Buttons.hpp"
|
#include "Buttons.hpp"
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
Chart::Chart(const stepland::memon& memon, const std::string& chart_name) {
|
Chart::Chart(const stepland::memon& memon, const std::string& difficulty) {
|
||||||
auto it = memon.charts.find(chart_name);
|
auto it = memon.charts.find(difficulty);
|
||||||
if (it == memon.charts.end()) {
|
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;
|
auto [_, chart] = *it;
|
||||||
level = static_cast<unsigned int>(chart.level);
|
level = chart.level;
|
||||||
resolution = static_cast<std::size_t>(chart.resolution);
|
resolution = static_cast<std::size_t>(chart.resolution);
|
||||||
Toolkit::AffineTransform<float> memon_timing_to_300Hz(
|
Toolkit::AffineTransform<float> memon_timing_to_300Hz(
|
||||||
0.f, static_cast<float>(chart.resolution),
|
0.f, static_cast<float>(chart.resolution),
|
||||||
-memon.offset*300.f, (-memon.offset+60.f/memon.BPM)*300.f
|
-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 &¬e : chart.notes) {
|
for (auto &¬e : chart.notes) {
|
||||||
auto timing = static_cast<std::size_t>(memon_timing_to_300Hz.transform(note.get_timing()));
|
auto timing = static_cast<std::size_t>(memon_timing_to_300Hz.transform(note.get_timing()));
|
||||||
auto position = static_cast<Button>(note.get_pos());
|
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());
|
auto tail = convert_memon_tail(position, note.get_tail_pos());
|
||||||
notes.emplace(timing, position, length, tail);
|
notes.insert({timing, position, length, tail});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
struct Chart {
|
struct Chart {
|
||||||
explicit Chart(const stepland::memon& memon, const std::string& chart);
|
Chart(const stepland::memon& memon, const std::string& difficulty);
|
||||||
unsigned int level;
|
int level;
|
||||||
std::set<Note> notes;
|
std::set<Note> notes;
|
||||||
std::size_t resolution;
|
std::size_t resolution;
|
||||||
};
|
};
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
struct Note {
|
struct Note {
|
||||||
// Timing is stored as ticks on a 300Hz clock
|
// Timing is stored as ticks on a 300Hz clock starting at the begging of the audio
|
||||||
std::size_t timing;
|
long int timing;
|
||||||
Button position;
|
Button position;
|
||||||
// zero is standard note
|
// zero length means it's a standard note
|
||||||
std::size_t length;
|
std::size_t length;
|
||||||
Button tail;
|
Button tail;
|
||||||
|
|
||||||
|
133
src/Data/Song.cpp
Normal file
133
src/Data/Song.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,13 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <variant>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "Chart.hpp"
|
||||||
|
|
||||||
namespace fs = ghc::filesystem;
|
namespace fs = ghc::filesystem;
|
||||||
|
|
||||||
@ -22,8 +26,6 @@ namespace Data {
|
|||||||
|
|
||||||
// Basic metadata about a song
|
// Basic metadata about a song
|
||||||
struct Song {
|
struct Song {
|
||||||
Song() = default;
|
|
||||||
explicit Song(fs::path song_folder);
|
|
||||||
fs::path folder;
|
fs::path folder;
|
||||||
std::string title;
|
std::string title;
|
||||||
std::string artist;
|
std::string artist;
|
||||||
@ -35,24 +37,39 @@ namespace Data {
|
|||||||
std::map<std::string, unsigned int, cmp_dif_name> chart_levels;
|
std::map<std::string, unsigned int, cmp_dif_name> chart_levels;
|
||||||
|
|
||||||
std::optional<fs::path> full_cover_path() const;
|
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) {
|
static bool sort_by_title(const Data::Song& a, const Data::Song& b) {
|
||||||
return a.title < b.title;
|
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 holding all the necessary song data to run the Music Select screen
|
||||||
class SongList {
|
class SongList {
|
||||||
public:
|
public:
|
||||||
SongList();
|
SongList();
|
||||||
std::vector<Song> songs;
|
std::list<std::shared_ptr<Song>> songs;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the folders conscidered to contain a valid song
|
// Returns the folders conscidered to contain a valid song
|
||||||
// classic memo files should have the .memo extension
|
// classic memo files should have the .memo extension
|
||||||
// .memon files also accepted
|
std::list<std::shared_ptr<Song>> recursiveSongSearch(fs::path song_or_pack);
|
||||||
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);
|
|
||||||
}
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -4,7 +4,7 @@
|
|||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
#include <cereal/archives/json.hpp>
|
#include <cereal/archives/json.hpp>
|
||||||
|
|
||||||
#include "Data/SongList.hpp"
|
#include "Data/Song.hpp"
|
||||||
#include "Data/Preferences.hpp"
|
#include "Data/Preferences.hpp"
|
||||||
// #include "Data/Chart.hpp"
|
// #include "Data/Chart.hpp"
|
||||||
// #include "Data/Score.hpp"
|
// #include "Data/Score.hpp"
|
||||||
|
49
src/Screens/MusicSelect/DensityGraph.cpp
Normal file
49
src/Screens/MusicSelect/DensityGraph.cpp
Normal 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 &¬e : 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;
|
||||||
|
}
|
||||||
|
}
|
41
src/Screens/MusicSelect/DensityGraph.hpp
Normal file
41
src/Screens/MusicSelect/DensityGraph.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
|
|
||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/Song.hpp"
|
||||||
#include "../../Data/Chart.hpp"
|
#include "../../Data/Chart.hpp"
|
||||||
#include "../../Data/KeyMapping.hpp"
|
#include "../../Data/KeyMapping.hpp"
|
||||||
#include "../../Toolkit/AffineTransform.hpp"
|
#include "../../Toolkit/AffineTransform.hpp"
|
||||||
|
@ -69,22 +69,22 @@ namespace MusicSelect {
|
|||||||
void SongPanel::click(Ribbon& ribbon, std::size_t from_button_index) {
|
void SongPanel::click(Ribbon& ribbon, std::size_t from_button_index) {
|
||||||
if (selected_chart.has_value()) {
|
if (selected_chart.has_value()) {
|
||||||
// The song was already selected : look for the next chart in order
|
// The song was already selected : look for the next chart in order
|
||||||
auto it = m_song.chart_levels.upper_bound(*selected_chart);
|
auto it = m_song->chart_levels.upper_bound(*selected_chart);
|
||||||
if (it != m_song.chart_levels.cend()) {
|
if (it != m_song->chart_levels.cend()) {
|
||||||
selected_chart = it->first;
|
selected_chart = it->first;
|
||||||
} else {
|
} 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->last_click.restart();
|
||||||
m_resources.selected_panel->is_first_click = false;
|
m_resources.selected_panel->is_first_click = false;
|
||||||
} else {
|
} else {
|
||||||
// Look for the first chart with dif greater or equal to the last select one
|
// Look for the first chart with dif greater or equal to the last select one
|
||||||
// or else select the first chart
|
// or else select the first chart
|
||||||
auto it = m_song.chart_levels.lower_bound(m_resources.get_last_selected_chart());
|
auto it = m_song->chart_levels.lower_bound(m_resources.get_last_selected_difficulty());
|
||||||
if (it != m_song.chart_levels.cend()) {
|
if (it != m_song->chart_levels.cend()) {
|
||||||
selected_chart = it->first;
|
selected_chart = it->first;
|
||||||
} else {
|
} 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
|
// The song was not selected before : first unselect the last one
|
||||||
if (m_resources.selected_panel.has_value()) {
|
if (m_resources.selected_panel.has_value()) {
|
||||||
@ -100,7 +100,7 @@ namespace MusicSelect {
|
|||||||
|
|
||||||
std::optional<ChartSelection> SongPanel::get_selected_chart() const {
|
std::optional<ChartSelection> SongPanel::get_selected_chart() const {
|
||||||
if (selected_chart) {
|
if (selected_chart) {
|
||||||
return ChartSelection{m_song, *selected_chart};
|
return ChartSelection{*m_song, *selected_chart};
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -108,11 +108,11 @@ namespace MusicSelect {
|
|||||||
|
|
||||||
void SongPanel::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
void SongPanel::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
||||||
states.transform *= getTransform();
|
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
|
// 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();
|
bool should_be_grayed_out = m_song->chart_levels.find(last_selected_chart) == m_song->chart_levels.end();
|
||||||
if (m_song.cover) {
|
if (m_song->cover) {
|
||||||
auto loaded_texture = m_resources.covers.async_get(m_song.folder/m_song.cover.value());
|
auto loaded_texture = m_resources.covers.async_get(m_song->folder/m_song->cover.value());
|
||||||
if (loaded_texture) {
|
if (loaded_texture) {
|
||||||
sf::Sprite cover{*(loaded_texture->texture)};
|
sf::Sprite cover{*(loaded_texture->texture)};
|
||||||
auto alpha = static_cast<std::uint8_t>(
|
auto alpha = static_cast<std::uint8_t>(
|
||||||
@ -140,7 +140,7 @@ namespace MusicSelect {
|
|||||||
}
|
}
|
||||||
target.draw(chart_dif_badge, states);
|
target.draw(chart_dif_badge, states);
|
||||||
if (not should_be_grayed_out) {
|
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{
|
sf::Text dif_label{
|
||||||
std::to_string(dif),
|
std::to_string(dif),
|
||||||
m_resources.noto_sans_medium,
|
m_resources.noto_sans_medium,
|
||||||
@ -153,7 +153,7 @@ namespace MusicSelect {
|
|||||||
}
|
}
|
||||||
sf::Text song_title;
|
sf::Text song_title;
|
||||||
song_title.setFont(m_resources.noto_sans_medium);
|
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.setCharacterSize(static_cast<unsigned int>(0.06875f*get_size()));
|
||||||
song_title.setFillColor(sf::Color::White);
|
song_title.setFillColor(sf::Color::White);
|
||||||
auto song_title_bounds = song_title.getLocalBounds();
|
auto song_title_bounds = song_title.getLocalBounds();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
|
|
||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/Song.hpp"
|
||||||
#include "../../Toolkit/AffineTransform.hpp"
|
#include "../../Toolkit/AffineTransform.hpp"
|
||||||
#include "SharedResources.hpp"
|
#include "SharedResources.hpp"
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ namespace MusicSelect {
|
|||||||
|
|
||||||
struct ChartSelection {
|
struct ChartSelection {
|
||||||
const Data::Song& song;
|
const Data::Song& song;
|
||||||
const std::string& chart;
|
const std::string& difficulty;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SelectablePanel : public Panel {
|
class SelectablePanel : public Panel {
|
||||||
@ -77,13 +77,13 @@ namespace MusicSelect {
|
|||||||
|
|
||||||
class SongPanel final : public SelectablePanel {
|
class SongPanel final : public SelectablePanel {
|
||||||
public:
|
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 click(Ribbon& ribbon, std::size_t from_button_index) override;
|
||||||
void unselect() override;
|
void unselect() override;
|
||||||
std::optional<ChartSelection> get_selected_chart() const override;
|
std::optional<ChartSelection> get_selected_chart() const override;
|
||||||
private:
|
private:
|
||||||
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
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};
|
const Toolkit::AffineTransform<float> m_seconds_to_alpha{0.0f, 0.15f, 0.f, 255.f};
|
||||||
std::optional<std::string> selected_chart;
|
std::optional<std::string> selected_chart;
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Panel.hpp"
|
#include "Panel.hpp"
|
||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/Song.hpp"
|
||||||
#include "../../Toolkit/QuickRNG.hpp"
|
#include "../../Toolkit/QuickRNG.hpp"
|
||||||
|
|
||||||
|
|
||||||
@ -69,15 +69,19 @@ namespace MusicSelect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Ribbon::title_sort(const Data::SongList &song_list) {
|
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) {
|
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;
|
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
|
||||||
for (const auto &song : songs) {
|
for (const auto &song : songs) {
|
||||||
if (song.get().title.size() > 0) {
|
if (song->title.size() > 0) {
|
||||||
char letter = song.get().title[0];
|
char letter = song->title[0];
|
||||||
if ('A' <= letter and letter <= 'Z') {
|
if ('A' <= letter and letter <= 'Z') {
|
||||||
categories
|
categories
|
||||||
[std::string(1, letter)]
|
[std::string(1, letter)]
|
||||||
@ -140,21 +144,6 @@ namespace MusicSelect {
|
|||||||
layout_from_category_map(categories);
|
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 {
|
std::size_t Ribbon::get_layout_column(const std::size_t& button_index) const {
|
||||||
return (m_position + (button_index % 4)) % m_layout.size();
|
return (m_position + (button_index % 4)) % m_layout.size();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <SFML/Graphics/Transformable.hpp>
|
#include <SFML/Graphics/Transformable.hpp>
|
||||||
|
|
||||||
#include "../../Data/Preferences.hpp"
|
#include "../../Data/Preferences.hpp"
|
||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/Song.hpp"
|
||||||
#include "../../Toolkit/AffineTransform.hpp"
|
#include "../../Toolkit/AffineTransform.hpp"
|
||||||
#include "../../Toolkit/Debuggable.hpp"
|
#include "../../Toolkit/Debuggable.hpp"
|
||||||
#include "../../Toolkit/EasingFunctions.hpp"
|
#include "../../Toolkit/EasingFunctions.hpp"
|
||||||
@ -59,6 +59,5 @@ namespace MusicSelect {
|
|||||||
std::size_t m_position = 0;
|
std::size_t m_position = 0;
|
||||||
mutable std::optional<MoveAnimation> m_move_animation;
|
mutable std::optional<MoveAnimation> m_move_animation;
|
||||||
float m_time_factor = 1.f;
|
float m_time_factor = 1.f;
|
||||||
Data::Song empty_song;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -22,11 +22,11 @@ namespace MusicSelect {
|
|||||||
std::cout << "Loaded MusicSelect::SharedResources" << std::endl;
|
std::cout << "Loaded MusicSelect::SharedResources" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SharedResources::get_last_selected_chart() {
|
std::string SharedResources::get_last_selected_difficulty() {
|
||||||
return get_selected_chart().value_or("BSC");
|
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()) {
|
if (not selected_panel.has_value()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ namespace MusicSelect {
|
|||||||
if (not chart_selection.has_value()) {
|
if (not chart_selection.has_value()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return chart_selection->chart;
|
return chart_selection->difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::reference_wrapper<const Data::Song>> MusicSelect::SharedResources::get_selected_song() {
|
std::optional<std::reference_wrapper<const Data::Song>> MusicSelect::SharedResources::get_selected_song() {
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
#include "../../Resources/TextureCache.hpp"
|
#include "../../Resources/TextureCache.hpp"
|
||||||
#include "../../Data/Preferences.hpp"
|
#include "../../Data/Preferences.hpp"
|
||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/Song.hpp"
|
||||||
|
|
||||||
|
#include "DensityGraph.hpp"
|
||||||
|
|
||||||
namespace MusicSelect {
|
namespace MusicSelect {
|
||||||
|
|
||||||
@ -32,9 +34,11 @@ namespace MusicSelect {
|
|||||||
|
|
||||||
sf::Font noto_sans_medium;
|
sf::Font noto_sans_medium;
|
||||||
|
|
||||||
|
Data::DensityGraphCache density_graphs;
|
||||||
|
|
||||||
std::optional<TimedSelectedPanel> selected_panel;
|
std::optional<TimedSelectedPanel> selected_panel;
|
||||||
std::string get_last_selected_chart();
|
std::string get_last_selected_difficulty();
|
||||||
std::optional<std::string> get_selected_chart();
|
std::optional<std::string> get_selected_difficulty();
|
||||||
std::optional<std::reference_wrapper<const Data::Song>> get_selected_song();
|
std::optional<std::reference_wrapper<const Data::Song>> get_selected_song();
|
||||||
|
|
||||||
sf::Color BSC_color = sf::Color{34,216,92};
|
sf::Color BSC_color = sf::Color{34,216,92};
|
||||||
|
@ -52,9 +52,10 @@ namespace MusicSelect {
|
|||||||
target.draw(cover, states);
|
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 {
|
void SongInfo::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
||||||
states.transform *= getTransform();
|
states.transform *= getTransform();
|
||||||
@ -142,7 +143,7 @@ namespace MusicSelect {
|
|||||||
target.draw(level_label, states);
|
target.draw(level_label, states);
|
||||||
|
|
||||||
sf::Text level_number_label{
|
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,
|
m_resources.noto_sans_medium,
|
||||||
static_cast<unsigned int>(130.f/768.f*get_screen_width())
|
static_cast<unsigned int>(130.f/768.f*get_screen_width())
|
||||||
};
|
};
|
||||||
@ -151,23 +152,23 @@ namespace MusicSelect {
|
|||||||
level_number_label.setFillColor(sf::Color::White);
|
level_number_label.setFillColor(sf::Color::White);
|
||||||
target.draw(level_number_label, states);
|
target.draw(level_number_label, states);
|
||||||
|
|
||||||
std::string full_chart_name = selected_chart->chart;
|
std::string full_difficulty = selected_chart->difficulty;
|
||||||
if (selected_chart->chart == "BSC") {
|
if (selected_chart->difficulty == "BSC") {
|
||||||
full_chart_name = "BASIC";
|
full_difficulty = "BASIC";
|
||||||
} else if (selected_chart->chart == "ADV") {
|
} else if (selected_chart->difficulty == "ADV") {
|
||||||
full_chart_name = "ADVANCED";
|
full_difficulty = "ADVANCED";
|
||||||
} else if (selected_chart->chart == "EXT") {
|
} else if (selected_chart->difficulty == "EXT") {
|
||||||
full_chart_name = "EXTREME";
|
full_difficulty = "EXTREME";
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::Text chart_label{
|
sf::Text chart_label{
|
||||||
full_chart_name,
|
full_difficulty,
|
||||||
m_resources.noto_sans_medium,
|
m_resources.noto_sans_medium,
|
||||||
static_cast<unsigned int>(20.f/768.f*get_screen_width())
|
static_cast<unsigned int>(20.f/768.f*get_screen_width())
|
||||||
};
|
};
|
||||||
Toolkit::set_origin_normalized_no_position(chart_label, 0.5f, 0.f);
|
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.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);
|
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_y = 40.f/768.f*get_screen_width();
|
||||||
auto dif_badge_step = 3.f*dif_badge_radius;
|
auto dif_badge_step = 3.f*dif_badge_radius;
|
||||||
std::size_t dif_index = 0;
|
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};
|
sf::CircleShape dif_badge{dif_badge_radius};
|
||||||
Toolkit::set_origin_normalized(dif_badge, 0.5f, 0.5f);
|
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);
|
dif_badge.setPosition(dif_badge_x+dif_index*dif_badge_step, dif_badge_y);
|
||||||
target.draw(dif_badge, states);
|
target.draw(dif_badge, states);
|
||||||
if (chart_name == selected_chart->chart) {
|
if (difficulty == selected_chart->difficulty) {
|
||||||
sf::CircleShape select_triangle(dif_badge_radius, 3);
|
sf::CircleShape select_triangle(dif_badge_radius, 3);
|
||||||
Toolkit::set_origin_normalized(select_triangle, 0.5f, 0.5f);
|
Toolkit::set_origin_normalized(select_triangle, 0.5f, 0.5f);
|
||||||
select_triangle.rotate(180.f);
|
select_triangle.rotate(180.f);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user