càrrega de recursos no bloquejant
This commit is contained in:
@@ -67,7 +67,8 @@ Resource::Resource(LoadingMode mode)
|
||||
Screen::get()->show();
|
||||
if (loading_mode_ == LoadingMode::PRELOAD) {
|
||||
loading_text_ = Screen::get()->getText();
|
||||
load();
|
||||
// Ya NO llamamos load() aquí: Director bombea beginLoad() + loadStep()
|
||||
// desde iterate() para mantener vivo el bucle SDL3 durante la carga.
|
||||
} else {
|
||||
// En modo lazy, cargamos lo mínimo indispensable
|
||||
initResourceLists();
|
||||
@@ -413,31 +414,128 @@ void Resource::clear() {
|
||||
demos_.clear();
|
||||
}
|
||||
|
||||
// Carga todos los recursos del juego y muestra el progreso de carga
|
||||
// Carga síncrona completa: usado por Resource::reload() (hot-reload en debug).
|
||||
// En arranque normal la carga la bombea Director::iterate() vía loadStep().
|
||||
void Resource::load() {
|
||||
// Prepara la gestión del progreso de carga
|
||||
beginLoad();
|
||||
while (!loadStep(INT_MAX)) {
|
||||
// Presupuesto infinito: una sola pasada carga todo
|
||||
}
|
||||
Screen::get()->setVSync(saved_vsync_);
|
||||
}
|
||||
|
||||
// Prepara el estado del cargador incremental. No carga nada todavía.
|
||||
void Resource::beginLoad() {
|
||||
calculateTotalResources();
|
||||
initProgressBar();
|
||||
|
||||
// Muerstra la ventana y desactiva el sincronismo vertical
|
||||
auto* screen = Screen::get();
|
||||
auto vsync = Screen::getVSync();
|
||||
screen->setVSync(false);
|
||||
saved_vsync_ = Screen::getVSync();
|
||||
Screen::get()->setVSync(false); // Maximiza FPS durante el preload
|
||||
|
||||
// SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** LOADING RESOURCES");
|
||||
loadSounds(); // Carga sonidos
|
||||
loadMusics(); // Carga músicas
|
||||
loadTextures(); // Carga texturas
|
||||
loadTextFiles(); // Carga ficheros de texto
|
||||
loadAnimations(); // Carga animaciones
|
||||
loadDemoData(); // Carga datos de demo
|
||||
createText(); // Crea objetos de texto
|
||||
createTextTextures(); // Crea texturas a partir de texto
|
||||
createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
||||
// SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** RESOURCES LOADED");
|
||||
stage_ = LoadStage::SOUNDS;
|
||||
stage_index_ = 0;
|
||||
}
|
||||
|
||||
// Restablece el sincronismo vertical a su valor original
|
||||
screen->setVSync(vsync);
|
||||
auto Resource::isLoadDone() const -> bool {
|
||||
return stage_ == LoadStage::DONE;
|
||||
}
|
||||
|
||||
// Bombea la máquina de etapas hasta agotar el presupuesto de tiempo o completar la carga.
|
||||
// Devuelve true cuando ya no queda nada por cargar.
|
||||
auto Resource::loadStep(int budget_ms) -> bool {
|
||||
if (stage_ == LoadStage::DONE) { return true; }
|
||||
|
||||
const Uint64 start_ns = SDL_GetTicksNS();
|
||||
const Uint64 budget_ns = static_cast<Uint64>(budget_ms) * 1'000'000ULL;
|
||||
|
||||
while (stage_ != LoadStage::DONE) {
|
||||
switch (stage_) {
|
||||
case LoadStage::SOUNDS: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
if (stage_index_ == 0) { sounds_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::MUSICS;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneSound(stage_index_++);
|
||||
break;
|
||||
}
|
||||
case LoadStage::MUSICS: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
if (stage_index_ == 0) { musics_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::TEXTURES;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneMusic(stage_index_++);
|
||||
break;
|
||||
}
|
||||
case LoadStage::TEXTURES: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
if (stage_index_ == 0) { textures_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::TEXT_FILES;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneTexture(stage_index_++);
|
||||
break;
|
||||
}
|
||||
case LoadStage::TEXT_FILES: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
if (stage_index_ == 0) { text_files_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::ANIMATIONS;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneTextFile(stage_index_++);
|
||||
break;
|
||||
}
|
||||
case LoadStage::ANIMATIONS: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
if (stage_index_ == 0) { animations_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::DEMO_DATA;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneAnimation(stage_index_++);
|
||||
break;
|
||||
}
|
||||
case LoadStage::DEMO_DATA: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
if (stage_index_ == 0) { demos_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::CREATE_TEXT;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneDemoData(stage_index_++);
|
||||
break;
|
||||
}
|
||||
case LoadStage::CREATE_TEXT:
|
||||
createText();
|
||||
stage_ = LoadStage::CREATE_TEXT_TEXTURES;
|
||||
break;
|
||||
case LoadStage::CREATE_TEXT_TEXTURES:
|
||||
createTextTextures();
|
||||
stage_ = LoadStage::CREATE_PLAYER_TEXTURES;
|
||||
break;
|
||||
case LoadStage::CREATE_PLAYER_TEXTURES:
|
||||
createPlayerTextures();
|
||||
stage_ = LoadStage::DONE;
|
||||
break;
|
||||
case LoadStage::DONE:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((SDL_GetTicksNS() - start_ns) >= budget_ns) { break; }
|
||||
}
|
||||
|
||||
return stage_ == LoadStage::DONE;
|
||||
}
|
||||
|
||||
// Recarga todos los recursos (limpia y vuelve a cargar)
|
||||
@@ -450,96 +548,78 @@ void Resource::reload() {
|
||||
}
|
||||
}
|
||||
|
||||
// Carga los sonidos del juego
|
||||
void Resource::loadSounds() {
|
||||
// Carga un sonido concreto desde la lista de assets
|
||||
void Resource::loadOneSound(size_t idx) {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
sounds_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
auto audio_data = loadAudioData(l);
|
||||
JA_Sound_t* sound = nullptr;
|
||||
if (!audio_data.data.empty()) {
|
||||
sound = JA_LoadSound(audio_data.data.data(), audio_data.data.size());
|
||||
} else {
|
||||
sound = JA_LoadSound(l.c_str());
|
||||
}
|
||||
if (sound == nullptr) {
|
||||
std::cout << "Sound load failed: " << name << '\n';
|
||||
}
|
||||
sounds_.emplace_back(name, sound);
|
||||
const auto& path = list[idx];
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
auto audio_data = loadAudioData(path);
|
||||
JA_Sound_t* sound = nullptr;
|
||||
if (!audio_data.data.empty()) {
|
||||
sound = JA_LoadSound(audio_data.data.data(), audio_data.data.size());
|
||||
} else {
|
||||
sound = JA_LoadSound(path.c_str());
|
||||
}
|
||||
if (sound == nullptr) {
|
||||
std::cout << "Sound load failed: " << name << '\n';
|
||||
}
|
||||
sounds_.emplace_back(name, sound);
|
||||
}
|
||||
|
||||
// Carga las músicas del juego
|
||||
void Resource::loadMusics() {
|
||||
// Carga una música concreta desde la lista de assets
|
||||
void Resource::loadOneMusic(size_t idx) {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
musics_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
auto audio_data = loadAudioData(l);
|
||||
JA_Music_t* music = nullptr;
|
||||
if (!audio_data.data.empty()) {
|
||||
music = JA_LoadMusic(audio_data.data.data(), audio_data.data.size());
|
||||
} else {
|
||||
music = JA_LoadMusic(l.c_str());
|
||||
}
|
||||
if (music == nullptr) {
|
||||
std::cout << "Music load failed: " << name << '\n';
|
||||
}
|
||||
musics_.emplace_back(name, music);
|
||||
const auto& path = list[idx];
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
auto audio_data = loadAudioData(path);
|
||||
JA_Music_t* music = nullptr;
|
||||
if (!audio_data.data.empty()) {
|
||||
music = JA_LoadMusic(audio_data.data.data(), audio_data.data.size());
|
||||
} else {
|
||||
music = JA_LoadMusic(path.c_str());
|
||||
}
|
||||
if (music == nullptr) {
|
||||
std::cout << "Music load failed: " << name << '\n';
|
||||
}
|
||||
musics_.emplace_back(name, music);
|
||||
}
|
||||
|
||||
// Carga las texturas del juego
|
||||
void Resource::loadTextures() {
|
||||
// Carga una textura concreta desde la lista de assets
|
||||
void Resource::loadOneTexture(size_t idx) {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
textures_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
textures_.emplace_back(name, std::make_shared<Texture>(Screen::get()->getRenderer(), l));
|
||||
}
|
||||
const auto& path = list[idx];
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
textures_.emplace_back(name, std::make_shared<Texture>(Screen::get()->getRenderer(), path));
|
||||
}
|
||||
|
||||
// Carga los ficheros de texto del juego
|
||||
void Resource::loadTextFiles() {
|
||||
// Carga un fichero de texto concreto desde la lista de assets
|
||||
void Resource::loadOneTextFile(size_t idx) {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
text_files_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
text_files_.emplace_back(name, Text::loadFile(l));
|
||||
}
|
||||
const auto& path = list[idx];
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
text_files_.emplace_back(name, Text::loadFile(path));
|
||||
}
|
||||
|
||||
// Carga las animaciones del juego
|
||||
void Resource::loadAnimations() {
|
||||
// Carga una animación concreta desde la lista de assets
|
||||
void Resource::loadOneAnimation(size_t idx) {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
animations_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
animations_.emplace_back(name, loadAnimationsFromFile(l));
|
||||
}
|
||||
const auto& path = list[idx];
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
animations_.emplace_back(name, loadAnimationsFromFile(path));
|
||||
}
|
||||
|
||||
// Carga los datos para el modo demostración
|
||||
void Resource::loadDemoData() {
|
||||
// Carga un fichero de datos de demo concreto desde la lista de assets
|
||||
void Resource::loadOneDemoData(size_t idx) {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
demos_.clear();
|
||||
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
demos_.emplace_back(loadDemoDataFromFile(l));
|
||||
}
|
||||
const auto& path = list[idx];
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
demos_.emplace_back(loadDemoDataFromFile(path));
|
||||
}
|
||||
|
||||
// Crea las texturas de jugadores con todas sus variantes de paleta
|
||||
@@ -756,12 +836,16 @@ void Resource::renderProgress() {
|
||||
screen->start();
|
||||
screen->clean();
|
||||
|
||||
// Si la pantalla de carga está desactivada, dejamos todo en negro
|
||||
// Si la pantalla de carga está desactivada, dejamos todo en negro.
|
||||
// wait_for_input solo tiene efecto cuando la pantalla está visible.
|
||||
if (!Options::loading.show) {
|
||||
screen->coreRender();
|
||||
return;
|
||||
}
|
||||
|
||||
// Estamos en la fase de espera explícita al usuario tras terminar la carga
|
||||
const bool WAITING_FOR_INPUT = isLoadDone() && Options::loading.wait_for_input;
|
||||
|
||||
auto text_color = param.resource.color;
|
||||
auto bar_color = param.resource.color.DARKEN(100);
|
||||
const auto TEXT_HEIGHT = loading_text_->getCharacterSize();
|
||||
@@ -774,13 +858,17 @@ void Resource::renderProgress() {
|
||||
SDL_SetRenderDrawColor(renderer, bar_color.r, bar_color.g, bar_color.b, bar_color.a);
|
||||
SDL_RenderRect(renderer, &loading_wired_rect_);
|
||||
|
||||
// Escribe el nombre del recurso que se está cargando, centrado sobre la barra
|
||||
if (Options::loading.show_resource_name && !loading_resource_name_.empty()) {
|
||||
// Texto centrado sobre la barra: mientras carga, el nombre del recurso;
|
||||
// al terminar en modo wait_for_input, el prompt traducido.
|
||||
const std::string OVER_BAR_TEXT = WAITING_FOR_INPUT
|
||||
? Lang::getText("[RESOURCE] PRESS_TO_CONTINUE")
|
||||
: loading_resource_name_;
|
||||
if ((Options::loading.show_resource_name || WAITING_FOR_INPUT) && !OVER_BAR_TEXT.empty()) {
|
||||
loading_text_->writeDX(
|
||||
Text::CENTER | Text::COLOR,
|
||||
loading_wired_rect_.x + (loading_wired_rect_.w / 2),
|
||||
loading_wired_rect_.y - TEXT_HEIGHT - 2,
|
||||
loading_resource_name_,
|
||||
OVER_BAR_TEXT,
|
||||
1,
|
||||
text_color);
|
||||
}
|
||||
@@ -829,12 +917,12 @@ void Resource::initProgressBar() {
|
||||
loading_full_rect_ = {.x = BAR_X_POSITION, .y = BAR_Y_POSITION, .w = FULL_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||
}
|
||||
|
||||
// Actualiza el progreso de carga y muestra la barra
|
||||
// Actualiza el estado del progreso. No renderiza: el repintado lo hace
|
||||
// Preload::iterate una vez por frame llamando a renderProgress().
|
||||
void Resource::updateLoadingProgress(std::string name) {
|
||||
loading_resource_name_ = std::move(name);
|
||||
loading_count_.increase();
|
||||
updateProgressBar();
|
||||
renderProgress();
|
||||
}
|
||||
|
||||
// Actualiza la barra de estado
|
||||
|
||||
@@ -42,6 +42,15 @@ class Resource {
|
||||
// --- Métodos de recarga de recursos ---
|
||||
void reload(); // Recarga todos los recursos
|
||||
|
||||
// --- Cargador incremental ---
|
||||
// beginLoad prepara el estado; loadStep carga recursos hasta agotar el presupuesto;
|
||||
// devuelve true cuando ya no queda nada. renderProgress se llama una vez por frame
|
||||
// desde la escena Preload.
|
||||
void beginLoad();
|
||||
auto loadStep(int budget_ms) -> bool;
|
||||
[[nodiscard]] auto isLoadDone() const -> bool;
|
||||
void renderProgress();
|
||||
|
||||
// --- Método para obtener el modo de carga actual ---
|
||||
[[nodiscard]] auto getLoadingMode() const -> LoadingMode { return loading_mode_; }
|
||||
|
||||
@@ -146,13 +155,24 @@ class Resource {
|
||||
SDL_FRect loading_wired_rect_;
|
||||
SDL_FRect loading_full_rect_;
|
||||
|
||||
// --- Estado del cargador incremental ---
|
||||
enum class LoadStage {
|
||||
SOUNDS,
|
||||
MUSICS,
|
||||
TEXTURES,
|
||||
TEXT_FILES,
|
||||
ANIMATIONS,
|
||||
DEMO_DATA,
|
||||
CREATE_TEXT,
|
||||
CREATE_TEXT_TEXTURES,
|
||||
CREATE_PLAYER_TEXTURES,
|
||||
DONE
|
||||
};
|
||||
LoadStage stage_{LoadStage::DONE};
|
||||
size_t stage_index_{0};
|
||||
bool saved_vsync_{false}; // Vsync previo a beginLoad, restaurado por finishBoot/load
|
||||
|
||||
// --- Métodos internos de carga y gestión ---
|
||||
void loadSounds(); // Carga los sonidos
|
||||
void loadMusics(); // Carga las músicas
|
||||
void loadTextures(); // Carga las texturas
|
||||
void loadTextFiles(); // Carga los ficheros de texto
|
||||
void loadAnimations(); // Carga las animaciones
|
||||
void loadDemoData(); // Carga los datos para el modo demostración
|
||||
void loadDemoDataQuiet(); // Carga los datos de demo sin mostrar progreso (para modo lazy)
|
||||
void loadEssentialResources(); // Carga recursos esenciales en modo lazy
|
||||
void loadEssentialTextures(); // Carga solo las texturas esenciales (fuentes)
|
||||
@@ -176,11 +196,18 @@ class Resource {
|
||||
|
||||
// --- Métodos internos para gestionar el progreso ---
|
||||
void calculateTotalResources(); // Calcula el número de recursos para cargar
|
||||
void renderProgress(); // Muestra el progreso de carga
|
||||
void updateLoadingProgress(std::string name); // Actualiza el progreso de carga
|
||||
void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso
|
||||
void updateProgressBar(); // Actualiza la barra de estado
|
||||
|
||||
// --- Helpers del cargador incremental (cargan un único recurso) ---
|
||||
void loadOneSound(size_t idx);
|
||||
void loadOneMusic(size_t idx);
|
||||
void loadOneTexture(size_t idx);
|
||||
void loadOneTextFile(size_t idx);
|
||||
void loadOneAnimation(size_t idx);
|
||||
void loadOneDemoData(size_t idx);
|
||||
|
||||
// --- Constructores y destructor privados (singleton) ---
|
||||
explicit Resource(LoadingMode mode); // Constructor privado con modo de carga
|
||||
~Resource(); // Destructor privado
|
||||
|
||||
Reference in New Issue
Block a user