219 lines
7.0 KiB
C++
219 lines
7.0 KiB
C++
#include "resource.h"
|
|
|
|
#include <algorithm>
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include "asset.h"
|
|
#include "jail_audio.hpp"
|
|
#include "menu.h"
|
|
#include "resource_helper.h"
|
|
#include "text.h"
|
|
#include "texture.h"
|
|
|
|
Resource *Resource::instance_ = nullptr;
|
|
|
|
static std::string basename(const std::string &path) {
|
|
return path.substr(path.find_last_of("\\/") + 1);
|
|
}
|
|
|
|
static std::string stem(const std::string &path) {
|
|
std::string b = basename(path);
|
|
size_t dot = b.find_last_of('.');
|
|
if (dot == std::string::npos) return b;
|
|
return b.substr(0, dot);
|
|
}
|
|
|
|
void Resource::init(SDL_Renderer *renderer, Asset *asset, Input *input) {
|
|
if (instance_ == nullptr) {
|
|
instance_ = new Resource(renderer, asset, input);
|
|
instance_->preloadAll();
|
|
}
|
|
}
|
|
|
|
void Resource::destroy() {
|
|
delete instance_;
|
|
instance_ = nullptr;
|
|
}
|
|
|
|
Resource *Resource::get() {
|
|
return instance_;
|
|
}
|
|
|
|
Resource::Resource(SDL_Renderer *renderer, Asset *asset, Input *input)
|
|
: renderer_(renderer),
|
|
asset_(asset),
|
|
input_(input) {}
|
|
|
|
Resource::~Resource() {
|
|
for (auto &[name, m] : menus_) delete m;
|
|
menus_.clear();
|
|
|
|
for (auto &[name, t] : texts_) delete t;
|
|
texts_.clear();
|
|
|
|
for (auto &[name, t] : textures_) delete t;
|
|
textures_.clear();
|
|
|
|
for (auto &[name, s] : sounds_) JA_DeleteSound(s);
|
|
sounds_.clear();
|
|
|
|
for (auto &[name, m] : musics_) JA_DeleteMusic(m);
|
|
musics_.clear();
|
|
}
|
|
|
|
void Resource::preloadAll() {
|
|
const auto &items = asset_->getAll();
|
|
|
|
// Pass 1: texturas, sonidos, músicas, animaciones (raw lines), demo, lenguajes
|
|
for (const auto &it : items) {
|
|
if (!ResourceHelper::shouldUseResourcePack(it.file) && it.type != t_lang) {
|
|
// Ficheros absolutos (config.txt, score.bin, systemFolder) — no se precargan
|
|
continue;
|
|
}
|
|
auto bytes = ResourceHelper::loadFile(it.file);
|
|
if (bytes.empty()) continue;
|
|
|
|
const std::string bname = basename(it.file);
|
|
|
|
switch (it.type) {
|
|
case t_bitmap: {
|
|
auto *tex = new Texture(renderer_, bytes);
|
|
textures_[bname] = tex;
|
|
break;
|
|
}
|
|
case t_sound: {
|
|
JA_Sound_t *s = JA_LoadSound(bytes.data(), (uint32_t)bytes.size());
|
|
if (s) sounds_[bname] = s;
|
|
break;
|
|
}
|
|
case t_music: {
|
|
JA_Music_t *m = JA_LoadMusic(bytes.data(), (Uint32)bytes.size());
|
|
if (m) musics_[bname] = m;
|
|
break;
|
|
}
|
|
case t_data: {
|
|
if (bname.size() >= 4 && bname.substr(bname.size() - 4) == ".ani") {
|
|
std::string content(reinterpret_cast<const char *>(bytes.data()), bytes.size());
|
|
std::stringstream ss(content);
|
|
std::vector<std::string> lines;
|
|
std::string line;
|
|
while (std::getline(ss, line)) {
|
|
lines.push_back(line);
|
|
}
|
|
animationLines_[bname] = std::move(lines);
|
|
} else if (bname == "demo.bin") {
|
|
demoBytes_ = bytes;
|
|
} else if (bname.size() >= 4 && bname.substr(bname.size() - 4) == ".men") {
|
|
// Menús: se construyen en pass 2 porque dependen de textos y sonidos
|
|
}
|
|
break;
|
|
}
|
|
case t_font:
|
|
// Fonts: se emparejan en pass 2
|
|
break;
|
|
case t_lang:
|
|
// Lenguaje: lo sigue leyendo la clase Lang a través de ResourceHelper
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Pass 2: Text (fuentes emparejadas png+txt) y Menus (dependen de Text+sonidos)
|
|
// Fuentes: construimos un Text por cada par basename.png + basename.txt
|
|
// Acumulamos los bytes encontrados por stem (basename sin ext.)
|
|
std::unordered_map<std::string, std::vector<uint8_t>> fontPngs;
|
|
std::unordered_map<std::string, std::vector<uint8_t>> fontTxts;
|
|
for (const auto &it : items) {
|
|
if (it.type != t_font) continue;
|
|
auto bytes = ResourceHelper::loadFile(it.file);
|
|
if (bytes.empty()) continue;
|
|
const std::string s = stem(it.file);
|
|
const std::string bname = basename(it.file);
|
|
if (bname.size() >= 4 && bname.substr(bname.size() - 4) == ".png") {
|
|
fontPngs[s] = std::move(bytes);
|
|
} else if (bname.size() >= 4 && bname.substr(bname.size() - 4) == ".txt") {
|
|
fontTxts[s] = std::move(bytes);
|
|
}
|
|
}
|
|
for (const auto &[s, png] : fontPngs) {
|
|
auto itTxt = fontTxts.find(s);
|
|
if (itTxt == fontTxts.end()) continue;
|
|
Text *t = new Text(png, itTxt->second, renderer_);
|
|
texts_[s] = t;
|
|
}
|
|
|
|
// Menus: usan aún Menu::loadFromBytes que internamente llama a asset->get() y
|
|
// Text/JA_LoadSound por path. Funciona en modo fallback; en pack estricto
|
|
// requiere que Menu se adapte a cargar desde ResourceHelper. Por ahora
|
|
// lo dejamos así y será una migración del paso 7.
|
|
for (const auto &it : items) {
|
|
if (it.type != t_data) continue;
|
|
const std::string bname = basename(it.file);
|
|
if (bname.size() < 4 || bname.substr(bname.size() - 4) != ".men") continue;
|
|
auto bytes = ResourceHelper::loadFile(it.file);
|
|
if (bytes.empty()) continue;
|
|
Menu *m = new Menu(renderer_, asset_, input_, "");
|
|
m->loadFromBytes(bytes, bname);
|
|
const std::string s = stem(it.file);
|
|
menus_[s] = m;
|
|
}
|
|
}
|
|
|
|
Texture *Resource::getTexture(const std::string &name) {
|
|
auto it = textures_.find(name);
|
|
if (it == textures_.end()) {
|
|
std::cerr << "Resource::getTexture: missing " << name << '\n';
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
JA_Sound_t *Resource::getSound(const std::string &name) {
|
|
auto it = sounds_.find(name);
|
|
if (it == sounds_.end()) {
|
|
std::cerr << "Resource::getSound: missing " << name << '\n';
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
JA_Music_t *Resource::getMusic(const std::string &name) {
|
|
auto it = musics_.find(name);
|
|
if (it == musics_.end()) {
|
|
std::cerr << "Resource::getMusic: missing " << name << '\n';
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
std::vector<std::string> &Resource::getAnimationLines(const std::string &name) {
|
|
auto it = animationLines_.find(name);
|
|
if (it == animationLines_.end()) {
|
|
static std::vector<std::string> empty;
|
|
std::cerr << "Resource::getAnimationLines: missing " << name << '\n';
|
|
return empty;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
Text *Resource::getText(const std::string &name) {
|
|
auto it = texts_.find(name);
|
|
if (it == texts_.end()) {
|
|
std::cerr << "Resource::getText: missing " << name << '\n';
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
Menu *Resource::getMenu(const std::string &name) {
|
|
auto it = menus_.find(name);
|
|
if (it == menus_.end()) {
|
|
std::cerr << "Resource::getMenu: missing " << name << '\n';
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|