resource.pack
This commit is contained in:
218
source/resource.cpp
Normal file
218
source/resource.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user