Add SongList class
This commit is contained in:
parent
7d8aa5e265
commit
b2bd5d3e30
15
meson.build
15
meson.build
@ -15,19 +15,20 @@ filesystem = cpp.find_library('stdc++fs')
|
|||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
'src/Main.cpp',
|
'src/Main.cpp',
|
||||||
'src/Model/Chart.hpp',
|
'src/Data/Note.hpp',
|
||||||
'src/Model/MusicList.hpp',
|
'src/Data/Note.cpp',
|
||||||
'src/Model/MusicList.cpp',
|
'srx/Data/Score.hpp',
|
||||||
'src/Model/Score.hpp',
|
'src/Data/SongList.hpp',
|
||||||
|
'src/Data/SongList.cpp',
|
||||||
'src/Screens/Gameplay.hpp',
|
'src/Screens/Gameplay.hpp',
|
||||||
'src/Screens/MusicSelect.hpp',
|
'src/Screens/MusicSelect.hpp',
|
||||||
'src/Screens/Result.hpp',
|
'src/Screens/Result.hpp',
|
||||||
'src/Textures/TexturePack.hpp',
|
|
||||||
'src/Textures/TexturePack.cpp',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'jujube',
|
'jujube',
|
||||||
sources,
|
'src/Test.cpp',
|
||||||
|
'src/Textures/CoverPack.hpp',
|
||||||
|
'src/Textures/CoverPack.cpp',
|
||||||
dependencies: [sfml, filesystem]
|
dependencies: [sfml, filesystem]
|
||||||
)
|
)
|
8
src/Data/Chart.hpp
Normal file
8
src/Data/Chart.hpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class Chart {
|
||||||
|
public:
|
||||||
|
Chart(/* args */);
|
||||||
|
};
|
||||||
|
}
|
73
src/Data/Note.cpp
Normal file
73
src/Data/Note.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "Note.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
Data::Note::Note(
|
||||||
|
unsigned int t_position,
|
||||||
|
sf::Time t_timing,
|
||||||
|
sf::Time t_length,
|
||||||
|
unsigned int t_tail_position
|
||||||
|
) :
|
||||||
|
position(t_position),
|
||||||
|
timing(t_timing),
|
||||||
|
length(t_length),
|
||||||
|
tail_position(t_tail_position)
|
||||||
|
{
|
||||||
|
if (t_position > 15) {
|
||||||
|
throw std::out_of_range("Tried creating a note with invalid position : "+std::to_string(t_position));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_length.asMicroseconds < 0) {
|
||||||
|
throw std::out_of_range("Tried creating a long note with negative length : "+std::to_string(t_length.asSeconds)+ "s");
|
||||||
|
|
||||||
|
}
|
||||||
|
if (t_length.asMicroseconds > 0) {
|
||||||
|
if (t_tail_position > 5) {
|
||||||
|
throw std::out_of_range("Tried creating a long note with invalid tail position : "+std::to_string(t_tail_position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Data::Note::operator==(const Data::Note &rhs) const {
|
||||||
|
return timing == rhs.timing && position == rhs.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Data::Note::operator!=(const Data::Note &rhs) const {
|
||||||
|
return !(rhs == *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Data::Note::operator<(const Data::Note &rhs) const {
|
||||||
|
if (timing < rhs.timing) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (rhs.timing < timing) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return position < rhs.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Data::Note::operator>(const Data::Note &rhs) const {
|
||||||
|
return rhs < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Data::Note::operator<=(const Data::Note &rhs) const {
|
||||||
|
return !(rhs < *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Data::Note::operator>=(const Data::Note &rhs) const {
|
||||||
|
return !(*this < rhs);
|
||||||
|
}
|
||||||
|
const unsigned int Data::Note::getPosition() const {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sf::Time& Data::Note::getTiming() const {
|
||||||
|
return timing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sf::Time& Data::Note::getLength() const {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int Data::Note::getTailPosition() const {
|
||||||
|
return tail_position;
|
||||||
|
}
|
30
src/Data/Note.hpp
Normal file
30
src/Data/Note.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class Note {
|
||||||
|
public:
|
||||||
|
Note(unsigned int t_position, sf::Time t_timing, sf::Time t_length, unsigned int t_tail_position);
|
||||||
|
|
||||||
|
bool operator==(const Note &rhs) const;
|
||||||
|
bool operator!=(const Note &rhs) const;
|
||||||
|
bool operator<(const Note &rhs) const;
|
||||||
|
bool operator>(const Note &rhs) const;
|
||||||
|
bool operator<=(const Note &rhs) const;
|
||||||
|
bool operator>=(const Note &rhs) const;
|
||||||
|
|
||||||
|
const unsigned int getPosition() const;
|
||||||
|
const sf::Time& getTiming() const;
|
||||||
|
const sf::Time& getLength() const;
|
||||||
|
const unsigned int getTailPosition() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const unsigned int position;
|
||||||
|
const sf::Time timing;
|
||||||
|
const sf::Time length = sf::Time{};
|
||||||
|
const unsigned int tail_position = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
8
src/Data/Score.hpp
Normal file
8
src/Data/Score.hpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class Score {
|
||||||
|
public:
|
||||||
|
Score();
|
||||||
|
};
|
||||||
|
};
|
116
src/Data/SongList.cpp
Normal file
116
src/Data/SongList.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include "SongList.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
Data::SongList::SongList::SongList() {
|
||||||
|
|
||||||
|
// Loading all song metadata
|
||||||
|
for (const auto& folder : getSongFolders()) {
|
||||||
|
try {
|
||||||
|
songs.emplace_back(folder);
|
||||||
|
} catch (const std::invalid_argument& e) {
|
||||||
|
std::cerr << "Exception while parsing song folder "
|
||||||
|
<< folder.string() << " : " << e.what() << '\n';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading all cover previews
|
||||||
|
for (const auto& song : songs) {
|
||||||
|
if (song.cover) {
|
||||||
|
try {
|
||||||
|
cover_previews.emplace_back(*song.cover);
|
||||||
|
} catch (const std::invalid_argument& e) {
|
||||||
|
std::cerr << "Exception while loading song cover "
|
||||||
|
<< song.cover->string() << " : " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<fs::path> Data::getSongFolders() {
|
||||||
|
|
||||||
|
std::vector<fs::path> song_folders;
|
||||||
|
|
||||||
|
for (const auto& dir_item : fs::directory_iterator("songs/")) {
|
||||||
|
if (dir_item.is_directory()) {
|
||||||
|
for (auto& path : recursiveSongSearch(dir_item.path())) {
|
||||||
|
song_folders.push_back(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return song_folders;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<fs::path> Data::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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::Song::Song(fs::path 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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// .memo ?
|
||||||
|
auto memo_files = getMemoFiles(song_folder);
|
||||||
|
if (not memo_files.empty()) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("No valid file found in song folder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<fs::path>& Data::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>& Data::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;
|
||||||
|
}
|
47
src/Data/SongList.hpp
Normal file
47
src/Data/SongList.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../Textures/CoverPack.hpp"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
// Basic metadata about a song
|
||||||
|
struct Song {
|
||||||
|
Song() = default;
|
||||||
|
explicit Song(fs::path song_folder);
|
||||||
|
std::string title;
|
||||||
|
std::string artist;
|
||||||
|
// Path to the album cover
|
||||||
|
std::optional<fs::path> cover;
|
||||||
|
// Path the the audio file
|
||||||
|
std::optional<fs::path> audio;
|
||||||
|
// Mapping from chart difficulty (BSC, ADV, EXT ...) to the numeric level,
|
||||||
|
// the level is stored multiplied by 10 and displayed divided by 10
|
||||||
|
// to allow for decimal levels (introduced in jubeat ... festo ?)
|
||||||
|
std::unordered_map<std::string, unsigned int> chart_levels;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class holding all the necessary data to run the Music Select screen
|
||||||
|
class SongList {
|
||||||
|
public:
|
||||||
|
SongList();
|
||||||
|
private:
|
||||||
|
Textures::CoverPack cover_previews;
|
||||||
|
std::vector<const 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);
|
||||||
|
}
|
@ -22,8 +22,8 @@ int main(int argc, char const *argv[]) {
|
|||||||
Screen::Gameplay gameplay(selected_chart);
|
Screen::Gameplay gameplay(selected_chart);
|
||||||
Score score = gameplay.play_chart(window);
|
Score score = gameplay.play_chart(window);
|
||||||
|
|
||||||
Screen::Result result(score);
|
Screen::Result result_screen(score);
|
||||||
result.display(window);
|
result_screen.display(window);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class Chart {
|
|
||||||
public:
|
|
||||||
Chart();
|
|
||||||
};
|
|
||||||
|
|
||||||
class ChartMetadata {
|
|
||||||
public:
|
|
||||||
ChartMetadata(
|
|
||||||
std::string title,
|
|
||||||
std::string artist
|
|
||||||
);
|
|
||||||
private:
|
|
||||||
std::string title;
|
|
||||||
std::string artist;
|
|
||||||
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#include "MusicList.hpp"
|
|
||||||
|
|
||||||
MusicList::MusicList()
|
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "../Textures/JacketPack.hpp"
|
|
||||||
|
|
||||||
class MusicList {
|
|
||||||
public:
|
|
||||||
MusicList();
|
|
||||||
private:
|
|
||||||
Textures::JacketPack jacket_previews;
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class Score {
|
|
||||||
public:
|
|
||||||
Score();
|
|
||||||
};
|
|
@ -1,14 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
#include "../Model/Chart.hpp"
|
#include "../Data/Chart.hpp"
|
||||||
#include "../Model/Score.hpp"
|
#include "../Data/Score.hpp"
|
||||||
|
|
||||||
namespace Screen {
|
namespace Screen {
|
||||||
class Gameplay {
|
class Gameplay {
|
||||||
const Chart& chart;
|
const Data::Chart& chart;
|
||||||
public:
|
public:
|
||||||
explicit Gameplay(const Chart& selected_chart);
|
explicit Gameplay(const Data::Chart& selected_chart);
|
||||||
Score play_chart(sf::Window& window) const;
|
Score play_chart(sf::Window& window) const;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
#include "../Model/MusicList.hpp"
|
#include "../Data/SongList.hpp"
|
||||||
#include "../Model/Chart.hpp"
|
#include "../Data/Chart.hpp"
|
||||||
|
|
||||||
namespace Screen {
|
namespace Screen {
|
||||||
/*
|
|
||||||
The music select screen is created only once and loads a cache of available songs
|
// The music select screen is created only once and loads a cache of available songs
|
||||||
in the music_list attribute
|
// in the music_list attribute
|
||||||
*/
|
|
||||||
class MusicSelect {
|
class MusicSelect {
|
||||||
MusicList music_list;
|
Data::SongList music_list;
|
||||||
public:
|
public:
|
||||||
MusicSelect() = default;
|
MusicSelect() = default;
|
||||||
Chart& select_chart(sf::Window& window) const;
|
Chart& select_chart(sf::Window& window) const;
|
||||||
|
48
src/Textures/CoverPack.cpp
Normal file
48
src/Textures/CoverPack.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "CoverPack.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
sf::Sprite Textures::CoverPack::at(const std::filesystem::path& path) const{
|
||||||
|
auto location = get_detailed_location(locations.at(path));
|
||||||
|
sf::IntRect rect(location.column, location.row, 128, 128);
|
||||||
|
sf::Sprite cover;
|
||||||
|
cover.setTexture(textures.at(location.texture_index)->getTexture());
|
||||||
|
cover.setTextureRect(rect);
|
||||||
|
return cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Textures::CoverPack::emplace_back(const std::filesystem::path& cover) {
|
||||||
|
|
||||||
|
sf::Texture cover_texture;
|
||||||
|
if (!cover_texture.loadFromFile(cover)) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Unable to load cover image : " << cover;
|
||||||
|
throw std::invalid_argument(ss.str());
|
||||||
|
} else {
|
||||||
|
locations[cover] = next_location;
|
||||||
|
}
|
||||||
|
auto size = cover_texture.getSize();
|
||||||
|
auto location = get_detailed_location(next_location);
|
||||||
|
sf::Sprite new_cover;
|
||||||
|
new_cover.setTexture(cover_texture);
|
||||||
|
new_cover.setScale(128.0f/size.x, 128.0f/size.y);
|
||||||
|
new_cover.setPosition(128.0f * location.column, 128.0f * location.row);
|
||||||
|
if (location.column == 0 and location.row == 0) {
|
||||||
|
// first cover means it's a new texture
|
||||||
|
textures.push_back(std::make_shared<sf::RenderTexture>());
|
||||||
|
textures.back()->create(1024, 1024);
|
||||||
|
}
|
||||||
|
textures.at(location.texture_index)->draw(new_cover);
|
||||||
|
textures.at(location.texture_index)->display();
|
||||||
|
next_location++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Textures::DetailedLocation Textures::get_detailed_location(unsigned int location) {
|
||||||
|
return {location / 64, (location % 64) / 8, location % 8};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::shared_ptr<sf::RenderTexture>>& Textures::CoverPack::getTextures() const {
|
||||||
|
return textures;
|
||||||
|
}
|
45
src/Textures/CoverPack.hpp
Normal file
45
src/Textures/CoverPack.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
// Define the way we hash std::filesystem::path for use in unordered maps
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<std::filesystem::path> {
|
||||||
|
std::size_t operator()(const std::filesystem::path& p) const {
|
||||||
|
return std::hash<std::string>()(p.string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Textures {
|
||||||
|
|
||||||
|
/*
|
||||||
|
A CoverPack stores 128x128 cover previews in a vector of 1024x1024 textures
|
||||||
|
*/
|
||||||
|
class CoverPack {
|
||||||
|
public:
|
||||||
|
CoverPack() = default;
|
||||||
|
sf::Sprite at(const std::filesystem::path& path) const;
|
||||||
|
void emplace_back(const std::filesystem::path& cover);
|
||||||
|
const std::vector<std::shared_ptr<sf::RenderTexture>>& getTextures() const;
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::filesystem::path, unsigned int> locations;
|
||||||
|
std::vector<std::shared_ptr<sf::RenderTexture>> textures;
|
||||||
|
unsigned int next_location = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DetailedLocation {
|
||||||
|
unsigned int texture_index;
|
||||||
|
unsigned int row;
|
||||||
|
unsigned int column;
|
||||||
|
};
|
||||||
|
|
||||||
|
DetailedLocation get_detailed_location(unsigned int location);
|
||||||
|
};
|
@ -1,44 +0,0 @@
|
|||||||
#include "JacketPack.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
sf::Sprite Textures::JacketPack::operator[](const std::string& path) const{
|
|
||||||
auto location = get_detailed_location(locations.at(path));
|
|
||||||
sf::IntRect rect(location.column, location.row, 128, 128);
|
|
||||||
sf::Sprite jacket;
|
|
||||||
jacket.setTexture(textures.at(location.texture_index)->getTexture());
|
|
||||||
jacket.setTextureRect(rect);
|
|
||||||
return jacket;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Textures::JacketPack::push_back(const std::filesystem::path& jacket) {
|
|
||||||
|
|
||||||
sf::Texture jacket_texture;
|
|
||||||
if (!jacket_texture.loadFromFile(jacket)) {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Unable to load jacket image : " << jacket;
|
|
||||||
throw std::runtime_error(ss.str());
|
|
||||||
} else {
|
|
||||||
locations[jacket] = next_location;
|
|
||||||
}
|
|
||||||
auto size = jacket_texture.getSize();
|
|
||||||
auto location = get_detailed_location(next_location);
|
|
||||||
sf::Sprite new_jacket;
|
|
||||||
new_jacket.setTexture(jacket_texture);
|
|
||||||
new_jacket.setScale(128.0f/size.x, 128.0f/size.y);
|
|
||||||
new_jacket.setPosition(128.0f * location.column, 128.0f * location.row);
|
|
||||||
if (location.column == 0 and location.row == 0) {
|
|
||||||
// first jacket means it's a new texture
|
|
||||||
textures.push_back(std::make_shared<sf::RenderTexture>());
|
|
||||||
textures.back()->create(1024, 1024);
|
|
||||||
}
|
|
||||||
textures.at(location.texture_index)->draw(new_jacket);
|
|
||||||
textures.at(location.texture_index)->display();
|
|
||||||
next_location++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Textures::DetailedLocation Textures::get_detailed_location(unsigned int location) {
|
|
||||||
return {location / 64, (location % 64) / 8, location % 8};
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
namespace Textures {
|
|
||||||
|
|
||||||
/*
|
|
||||||
A JacketPack stores 128x128 jacket previews in 1024x1024 textures
|
|
||||||
*/
|
|
||||||
class JacketPack {
|
|
||||||
public:
|
|
||||||
JacketPack() = default;
|
|
||||||
sf::Sprite operator[](const std::string& path) const;
|
|
||||||
void push_back(const std::filesystem::path& jacket);
|
|
||||||
//private:
|
|
||||||
std::unordered_map<std::filesystem::path, unsigned int> locations;
|
|
||||||
std::vector<std::shared_ptr<sf::RenderTexture>> textures;
|
|
||||||
unsigned int next_location = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DetailedLocation {
|
|
||||||
unsigned int texture_index;
|
|
||||||
unsigned int row;
|
|
||||||
unsigned int column;
|
|
||||||
};
|
|
||||||
|
|
||||||
DetailedLocation get_detailed_location(unsigned int location);
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user