mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
loading screen (#495)
* loading screen * fix compile error * Fix animation comparisons after character anim commit * Cleaned up character sound/anim lookup code * hopefully fix problems with queued mods * use dj's changes * fix compile errors due to upstream merge
This commit is contained in:
parent
e8b6a8cffa
commit
b12b479d70
29 changed files with 427 additions and 66 deletions
|
@ -25,6 +25,7 @@ bool dynos_warp_exit_level(s32 aDelay);
|
|||
bool dynos_warp_to_castle(s32 aLevel);
|
||||
|
||||
// -- dynos packs -- //
|
||||
void dynos_gfx_init(void);
|
||||
void dynos_packs_init(void);
|
||||
int dynos_pack_get_count(void);
|
||||
const char* dynos_pack_get_name(s32 index);
|
||||
|
|
|
@ -62,8 +62,11 @@ bool dynos_warp_to_castle(s32 aLevel) {
|
|||
|
||||
// -- dynos packs -- //
|
||||
|
||||
void dynos_packs_init(void) {
|
||||
void dynos_gfx_init(void) {
|
||||
DynOS_Gfx_Init();
|
||||
}
|
||||
|
||||
void dynos_packs_init(void) {
|
||||
DynOS_Pack_Init();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
#include "dynos.cpp.h"
|
||||
#include "src/pc/loading.h"
|
||||
|
||||
void DynOS_Gfx_GeneratePacks(const char* directory) {
|
||||
DIR *modsDir = opendir(directory);
|
||||
if (!modsDir) { return; }
|
||||
|
||||
struct dirent *dir = NULL;
|
||||
while ((dir = readdir(modsDir)) != NULL) {
|
||||
DIR* d = opendir(directory);
|
||||
u32 pathCount = 0;
|
||||
while ((dir = readdir(d)) != NULL) pathCount++;
|
||||
closedir(d);
|
||||
|
||||
for (u32 i = 0; (dir = readdir(modsDir)) != NULL; ++i) {
|
||||
// Skip . and ..
|
||||
if (SysPath(dir->d_name) == ".") continue;
|
||||
if (SysPath(dir->d_name) == "..") continue;
|
||||
|
@ -15,21 +21,24 @@ void DynOS_Gfx_GeneratePacks(const char* directory) {
|
|||
if (fs_sys_dir_exists(_LevelPackFolder.c_str())) {
|
||||
DynOS_Lvl_GeneratePack(_LevelPackFolder);
|
||||
}
|
||||
|
||||
SysPath _ActorPackFolder = fstring("%s/%s/actors", directory, dir->d_name);
|
||||
if (fs_sys_dir_exists(_ActorPackFolder.c_str())) {
|
||||
DynOS_Actor_GeneratePack(_ActorPackFolder);
|
||||
}
|
||||
|
||||
|
||||
SysPath _BehaviorPackFolder = fstring("%s/%s/data", directory, dir->d_name);
|
||||
if (fs_sys_dir_exists(_BehaviorPackFolder.c_str())) {
|
||||
DynOS_Bhv_GeneratePack(_BehaviorPackFolder);
|
||||
}
|
||||
|
||||
|
||||
SysPath _TexturePackFolder = fstring("%s/%s", directory, dir->d_name);
|
||||
SysPath _TexturePackOutputFolder = fstring("%s/%s/textures", directory, dir->d_name);
|
||||
if (fs_sys_dir_exists(_TexturePackFolder.c_str())) {
|
||||
DynOS_Tex_GeneratePack(_TexturePackFolder, _TexturePackOutputFolder, true);
|
||||
}
|
||||
|
||||
if (gIsThreaded) REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / (f32) pathCount);
|
||||
}
|
||||
|
||||
closedir(modsDir);
|
||||
|
|
|
@ -374,3 +374,6 @@ REFRESHING = "Obnovování..."
|
|||
ENTER_PASSWORD = "Zadejte heslo soukromé hry:"
|
||||
SEARCH = "Hledat"
|
||||
NONE_FOUND = "Nebyly nalezeny žádné hry."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Načítání"
|
||||
|
|
|
@ -374,3 +374,6 @@ REFRESHING = "herladen..."
|
|||
ENTER_PASSWORD = "Typ het wachtwoord van de privé lobby:"
|
||||
SEARCH = "Zoek"
|
||||
NONE_FOUND = "Er zijn geen lobby's gevonden."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Bezig met laden"
|
||||
|
|
|
@ -374,3 +374,6 @@ REFRESHING = "Refreshing..."
|
|||
ENTER_PASSWORD = "Enter the private lobby's password:"
|
||||
SEARCH = "Search"
|
||||
NONE_FOUND = "No lobbies were found."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Loading"
|
||||
|
|
|
@ -374,3 +374,6 @@ REFRESHING = "Actualisation..."
|
|||
ENTER_PASSWORD = "Entrez le mot de passe de la partie:"
|
||||
SEARCH = "Rechercher"
|
||||
NONE_FOUND = "Aucune partie n'a été trouvée."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Chargement"
|
||||
|
|
|
@ -374,3 +374,6 @@ REFRESHING = "Aktualisiere..."
|
|||
ENTER_PASSWORD = "Gib das Passwort für die Lobby ein:"
|
||||
SEARCH = "Suchen"
|
||||
NONE_FOUND = "Keine Lobbys gefunden."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Wird geladen"
|
||||
|
|
|
@ -371,3 +371,6 @@ REFRESHING = "Refreshing..."
|
|||
ENTER_PASSWORD = "Enter the private lobby's password:"
|
||||
SEARCH = "Search"
|
||||
NONE_FOUND = "No lobbies were found."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Caricamento"
|
||||
|
|
|
@ -31,7 +31,7 @@ UNKNOWN = "desconhecido"
|
|||
LOBBY_HOST = "o host da partida"
|
||||
|
||||
[CHAT]
|
||||
KICKING = "Expulso '@'!"
|
||||
KICKING = "Expulso '@'!"
|
||||
BANNING = "Banindo '@'!"
|
||||
SERVER_ONLY = "Apenas o servidor pode usar este comando."
|
||||
PERM_BANNING = "'@' permanentemente banido!"
|
||||
|
@ -374,3 +374,6 @@ REFRESHING = "Recarregando..."
|
|||
ENTER_PASSWORD = "Coloque a senha para a partida privada:"
|
||||
SEARCH = "Pesquisar"
|
||||
NONE_FOUND = "Nenhuma partida foi encontrada."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Carregando"
|
||||
|
|
|
@ -372,4 +372,7 @@ REFRESH = "Обновить"
|
|||
REFRESHING = "Обновление..."
|
||||
ENTER_PASSWORD = "Введите пароль закрытой группы:"
|
||||
SEARCH = "Поиск"
|
||||
NONE_FOUND = "Группы не найдены."
|
||||
NONE_FOUND = "Группы не найдены."
|
||||
|
||||
[LOADING_SCREEN]
|
||||
LOADING = "Загрузка"
|
||||
|
|
|
@ -324,7 +324,7 @@ struct Character gCharacters[CT_MAX] = {
|
|||
.torsoRotMult = 1.0f,
|
||||
// anim
|
||||
.animOffsetEnabled = false,
|
||||
|
||||
|
||||
// character anims
|
||||
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
|
||||
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
|
||||
|
@ -601,7 +601,7 @@ struct Character gCharacters[CT_MAX] = {
|
|||
.torsoRotMult = 1.0f,
|
||||
// anim
|
||||
.animOffsetEnabled = false,
|
||||
|
||||
|
||||
// character anims
|
||||
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
|
||||
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
|
||||
|
@ -881,7 +881,7 @@ struct Character gCharacters[CT_MAX] = {
|
|||
.animOffsetLowYPoint = 11,
|
||||
.animOffsetFeet = 25,
|
||||
.animOffsetHand = -10,
|
||||
|
||||
|
||||
// character anims
|
||||
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
|
||||
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
|
||||
|
@ -1158,7 +1158,7 @@ struct Character gCharacters[CT_MAX] = {
|
|||
.torsoRotMult = 1.0f,
|
||||
// anim
|
||||
.animOffsetEnabled = true,
|
||||
|
||||
|
||||
// character anims
|
||||
.animSlowLedgeGrab = MARIO_ANIM_SLOW_LEDGE_GRAB,
|
||||
.animFallOverBackwards = MARIO_ANIM_FALL_OVER_BACKWARDS,
|
||||
|
@ -1521,7 +1521,7 @@ struct Character* get_character(struct MarioState* m) {
|
|||
|
||||
static s32 get_character_sound(struct MarioState* m, enum CharacterSound characterSound) {
|
||||
if (m == NULL || m->marioObj == NULL) { return 0; }
|
||||
|
||||
|
||||
s32 override = 0;
|
||||
if (smlua_call_event_hooks_mario_character_sound_param_ret_int(HOOK_CHARACTER_SOUND, m, characterSound, &override)) {
|
||||
return override;
|
||||
|
@ -1612,7 +1612,7 @@ void update_character_anim_offset(struct MarioState* m) {
|
|||
|
||||
s32 get_character_anim(struct MarioState* m, enum CharacterAnimID characterAnim) {
|
||||
if (m == NULL || m->marioObj == NULL) { return 0; }
|
||||
|
||||
|
||||
struct Character* character = ((m == NULL || m->character == NULL) ? &gCharacters[CT_MARIO] : m->character);
|
||||
if (!character || characterAnim < 0 || characterAnim >= CHAR_ANIM_MAX) { return 0; }
|
||||
return character->anims[characterAnim];
|
||||
|
|
|
@ -43,7 +43,8 @@ static inline int arg_uint(UNUSED const char *name, const char *value, unsigned
|
|||
return 1;
|
||||
}
|
||||
|
||||
inline void parse_cli_opts(int argc, char* argv[]) {
|
||||
bool parse_cli_opts(int argc, char* argv[]) {
|
||||
|
||||
// Initialize options with false values.
|
||||
memset(&gCLIOpts, 0, sizeof(gCLIOpts));
|
||||
|
||||
|
@ -88,7 +89,9 @@ inline void parse_cli_opts(int argc, char* argv[]) {
|
|||
// Print help
|
||||
else if (strcmp(argv[i], "--help") == 0) {
|
||||
print_help();
|
||||
game_exit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,6 @@ struct PCCLIOptions {
|
|||
|
||||
extern struct PCCLIOptions gCLIOpts;
|
||||
|
||||
void parse_cli_opts(int argc, char* argv[]);
|
||||
bool parse_cli_opts(int argc, char* argv[]);
|
||||
|
||||
#endif // _CLIOPTS_H
|
||||
|
|
|
@ -279,6 +279,23 @@ static const struct ConfigOption options[] = {
|
|||
|
||||
// FunctionConfigOption functions
|
||||
|
||||
struct QueuedMods {
|
||||
char* path;
|
||||
struct QueuedMods *next;
|
||||
};
|
||||
|
||||
static struct QueuedMods *sQueuedEnableModsHead = NULL;
|
||||
|
||||
void enable_queued_mods() {
|
||||
while (sQueuedEnableModsHead) {
|
||||
struct QueuedMods *next = sQueuedEnableModsHead->next;
|
||||
mods_enable(sQueuedEnableModsHead->path);
|
||||
free(sQueuedEnableModsHead->path);
|
||||
free(sQueuedEnableModsHead);
|
||||
sQueuedEnableModsHead = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_mod_read(char** tokens, UNUSED int numTokens) {
|
||||
char combined[256] = { 0 };
|
||||
for (int i = 1; i < numTokens; i++) {
|
||||
|
@ -286,7 +303,16 @@ static void enable_mod_read(char** tokens, UNUSED int numTokens) {
|
|||
strncat(combined, tokens[i], 255);
|
||||
}
|
||||
|
||||
mods_enable(combined);
|
||||
struct QueuedMods* queued = malloc(sizeof(struct QueuedMods));
|
||||
queued->path = strdup(combined);
|
||||
queued->next = NULL;
|
||||
if (!sQueuedEnableModsHead) {
|
||||
sQueuedEnableModsHead = queued;
|
||||
} else {
|
||||
struct QueuedMods* tail = sQueuedEnableModsHead;
|
||||
while (tail->next) { tail = tail->next; }
|
||||
tail->next = queued;
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_mod_write(FILE* file) {
|
||||
|
|
|
@ -120,6 +120,7 @@ extern bool configFadeoutDistantSounds;
|
|||
extern unsigned int configDjuiTheme;
|
||||
extern bool configCoopCompatibility;
|
||||
|
||||
void enable_queued_mods();
|
||||
void configfile_load(void);
|
||||
void configfile_save(const char *filename);
|
||||
const char *configfile_name(void);
|
||||
|
|
|
@ -275,8 +275,7 @@ static void crash_handler_produce_one_frame(void) {
|
|||
// Render frame
|
||||
end_master_display_list();
|
||||
alloc_display_list(0);
|
||||
extern void send_display_list(struct SPTask *spTask);
|
||||
send_display_list(&gGfxPool->spTask);
|
||||
gfx_run((Gfx*) gGfxSPTask->task.t.data_ptr); // send_display_list
|
||||
display_and_vsync();
|
||||
gfx_end_frame();
|
||||
}
|
||||
|
@ -302,7 +301,7 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) {
|
|||
#elif __linux__
|
||||
static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *context) {
|
||||
#endif
|
||||
LOG_INFO("game crashed! preparing crash screen...");
|
||||
printf("game crashed! preparing crash screen...\n");
|
||||
memset(sCrashHandlerText, 0, sizeof(sCrashHandlerText));
|
||||
CrashHandlerText *pText = &sCrashHandlerText[0];
|
||||
gDjuiDisabled = true;
|
||||
|
@ -658,6 +657,11 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont
|
|||
}
|
||||
#endif
|
||||
|
||||
// Incase it crashed before the game window opened
|
||||
if (!gGfxInited) gfx_init(&WAPI, &RAPI, TITLE);
|
||||
djui_init();
|
||||
djui_unicode_init();
|
||||
|
||||
// Main loop
|
||||
while (true) {
|
||||
WAPI.main_loop(crash_handler_produce_one_frame);
|
||||
|
@ -670,17 +674,17 @@ AT_STARTUP static void init_crash_handler(void) {
|
|||
// Windows
|
||||
SetUnhandledExceptionFilter(crash_handler);
|
||||
#elif __linux__
|
||||
|
||||
// Linux
|
||||
struct sigaction linux_crash_handler;
|
||||
struct sigaction linuxCrashHandler;
|
||||
linuxCrashHandler.sa_handler = (void*) &crash_handler;
|
||||
sigemptyset(&linuxCrashHandler.sa_mask);
|
||||
linuxCrashHandler.sa_flags = SA_SIGINFO; // Get extra info about the crash
|
||||
|
||||
linux_crash_handler.sa_handler = (void *)crash_handler;
|
||||
sigemptyset(&linux_crash_handler.sa_mask);
|
||||
linux_crash_handler.sa_flags = SA_SIGINFO; // Get extra info about the crash
|
||||
|
||||
sigaction(SIGBUS, &linux_crash_handler, NULL);
|
||||
sigaction(SIGFPE, &linux_crash_handler, NULL);
|
||||
sigaction(SIGILL, &linux_crash_handler, NULL);
|
||||
sigaction(SIGSEGV, &linux_crash_handler, NULL);
|
||||
sigaction(SIGBUS, &linuxCrashHandler, NULL);
|
||||
sigaction(SIGFPE, &linuxCrashHandler, NULL);
|
||||
sigaction(SIGILL, &linuxCrashHandler, NULL);
|
||||
sigaction(SIGSEGV, &linuxCrashHandler, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#define CTX_BEGIN(_ctx) debug_context_begin(_ctx)
|
||||
#define CTX_END(_ctx) debug_context_end(_ctx)
|
||||
#define CTX_WITHIN(_ctx) debug_context_within(_ctx)
|
||||
#define CTX_EXTENT(__ctx, __func) CTX_BEGIN(__ctx); __func(); CTX_END(__ctx);
|
||||
#define CTX_EXTENT(_ctx, _f) { CTX_BEGIN(_ctx); _f(); CTX_END(_ctx); }
|
||||
|
||||
enum DebugContext {
|
||||
CTX_NONE,
|
||||
|
|
|
@ -24,9 +24,26 @@ static u32 sDjuiLuaErrorTimeout = 0;
|
|||
bool gDjuiInMainMenu = true;
|
||||
bool gDjuiDisabled = false;
|
||||
bool gDjuiRenderBehindHud = false;
|
||||
static bool sDjuiInited = false;
|
||||
|
||||
bool sDjuiRendered60fps = false;
|
||||
|
||||
void reset_djui_text(void);
|
||||
|
||||
void reset_djui(void) {
|
||||
sSavedDisplayListHead = NULL;
|
||||
sDjuiPauseOptions = NULL;
|
||||
sDjuiLuaError = NULL;
|
||||
sDjuiLuaErrorTimeout = 0;
|
||||
if (gDjuiRoot) djui_base_destroy(&gDjuiRoot->base);
|
||||
|
||||
if (gDjuiConsole) djui_base_destroy(&gDjuiConsole->panel->base);
|
||||
extern u32 sDjuiConsoleMessages;
|
||||
sDjuiConsoleMessages = 0;
|
||||
|
||||
sDjuiInited = false;
|
||||
}
|
||||
|
||||
void patch_djui_before(void) {
|
||||
sDjuiRendered60fps = false;
|
||||
}
|
||||
|
@ -68,6 +85,7 @@ void djui_init(void) {
|
|||
djui_panel_playerlist_create(NULL);
|
||||
|
||||
djui_console_create();
|
||||
sDjuiInited = true;
|
||||
}
|
||||
|
||||
void djui_init_late(void) {
|
||||
|
@ -91,6 +109,7 @@ void djui_connect_menu_open(void) {
|
|||
}
|
||||
|
||||
void djui_lua_error(char* text) {
|
||||
if (!sDjuiLuaError) { return; }
|
||||
djui_text_set_text(sDjuiLuaError, text);
|
||||
djui_base_set_visible(&sDjuiLuaError->base, true);
|
||||
sDjuiLuaErrorTimeout = 30 * 5;
|
||||
|
@ -105,7 +124,7 @@ void djui_reset_hud_params(void) {
|
|||
}
|
||||
|
||||
void djui_render(void) {
|
||||
if (gDjuiDisabled) { return; }
|
||||
if (!sDjuiInited || gDjuiDisabled) { return; }
|
||||
djui_reset_hud_params();
|
||||
|
||||
sSavedDisplayListHead = gDisplayListHead;
|
||||
|
|
|
@ -46,3 +46,5 @@ void djui_connect_menu_open(void);
|
|||
void djui_lua_error(char* text);
|
||||
void djui_render(void);
|
||||
void djui_reset_hud_params(void);
|
||||
|
||||
void reset_djui(void);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "../platform.h"
|
||||
#include "../configfile.h"
|
||||
#include "../fs/fs.h"
|
||||
#include "../pc_main.h"
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
|
@ -1779,6 +1780,8 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co
|
|||
gfx_rapi->init();
|
||||
|
||||
gfx_cc_precomp();
|
||||
|
||||
gGfxInited = true;
|
||||
}
|
||||
|
||||
struct GfxRenderingAPI *gfx_get_current_rendering_api(void) {
|
||||
|
|
193
src/pc/loading.c
Normal file
193
src/pc/loading.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
#include "gfx_dimensions.h"
|
||||
#include "game/segment2.h"
|
||||
|
||||
#include "djui/djui.h"
|
||||
#include "pc/djui/djui_unicode.h"
|
||||
|
||||
#include "controller/controller_keyboard.h"
|
||||
|
||||
#include "pc_main.h"
|
||||
#include "loading.h"
|
||||
#include "pc/utils/misc.h"
|
||||
|
||||
struct LoadingSegment gCurrLoadingSegment = { "", 0 };
|
||||
|
||||
struct LoadingScreen {
|
||||
struct DjuiBase base;
|
||||
struct DjuiText* splashText;
|
||||
struct DjuiText* loadingText;
|
||||
struct DjuiText* loadingDesc;
|
||||
struct DjuiProgressBar *loadingBar;
|
||||
};
|
||||
|
||||
struct LoadingScreen* sLoading = NULL;
|
||||
pthread_t gLoadingThreadId;
|
||||
pthread_mutex_t gLoadingThreadMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
bool gIsThreaded = false;
|
||||
|
||||
extern Vp D_8032CF00;
|
||||
extern u8 gRenderingInterpolated;
|
||||
|
||||
static void loading_screen_produce_one_frame() {
|
||||
|
||||
// Start frame
|
||||
gfx_start_frame();
|
||||
config_gfx_pool();
|
||||
init_render_image();
|
||||
create_dl_ortho_matrix();
|
||||
djui_gfx_displaylist_begin();
|
||||
|
||||
// Fix scaling issues
|
||||
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00));
|
||||
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - BORDER_HEIGHT);
|
||||
|
||||
// Clear screen
|
||||
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.f, 0.f);
|
||||
create_dl_scale_matrix(MENU_MTX_NOPUSH, (GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT) / 130.f, 3.f, 1.f);
|
||||
gDPSetEnvColor(gDisplayListHead++, 0x00, 0x00, 0x00, 0xFF);
|
||||
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
|
||||
// Render loading screen elements
|
||||
if (sLoading) { djui_base_render(&sLoading->base); }
|
||||
|
||||
// Render frame
|
||||
djui_gfx_displaylist_end();
|
||||
end_master_display_list();
|
||||
alloc_display_list(0);
|
||||
gfx_run((Gfx*) gGfxSPTask->task.t.data_ptr); // send_display_list
|
||||
display_and_vsync();
|
||||
gfx_end_frame();
|
||||
}
|
||||
|
||||
static bool loading_screen_on_render(struct DjuiBase* base) {
|
||||
pthread_mutex_lock(&gLoadingThreadMutex);
|
||||
|
||||
u32 windowWidth, windowHeight;
|
||||
WAPI.get_dimensions(&windowWidth, &windowHeight);
|
||||
f32 scale = djui_gfx_get_scale();
|
||||
windowWidth /= scale;
|
||||
windowHeight /= scale;
|
||||
|
||||
// Fill the screen
|
||||
djui_base_set_size(base, windowWidth, windowHeight);
|
||||
|
||||
// Splash text
|
||||
djui_base_set_location(&sLoading->splashText->base, (windowWidth / 2) - 416, 0);
|
||||
|
||||
{
|
||||
// Loading... text
|
||||
char* loadingStr = DLANG(LOADING_SCREEN, LOADING);
|
||||
char tmp[20] = "";
|
||||
switch ((u8) floor(clock_elapsed()) % 3) {
|
||||
case 0: snprintf(tmp, 20, "%s...", loadingStr); break;
|
||||
case 1: snprintf(tmp, 20, "%s.", loadingStr); break;
|
||||
default: snprintf(tmp, 20, "%s..", loadingStr); break;
|
||||
}
|
||||
djui_text_set_text(sLoading->loadingText, tmp);
|
||||
djui_base_set_visible(&sLoading->loadingText->base, sLoading->loadingText->base.y.value + 50 < sLoading->loadingDesc->base.y.value);
|
||||
}
|
||||
|
||||
{
|
||||
// Loading text description
|
||||
char buffer[256] = "";
|
||||
if (strlen(gCurrLoadingSegment.str) > 0) {
|
||||
if (gCurrLoadingSegment.percentage > 0) {
|
||||
snprintf(buffer, 256, "%s... %d%%", gCurrLoadingSegment.str, (u8) floor(gCurrLoadingSegment.percentage * 100));
|
||||
} else {
|
||||
snprintf(buffer, 256, "%s...", gCurrLoadingSegment.str);
|
||||
}
|
||||
}
|
||||
djui_text_set_text(sLoading->loadingDesc, buffer);
|
||||
djui_base_set_location(&sLoading->loadingDesc->base, 0, windowHeight - 250);
|
||||
}
|
||||
|
||||
// Loading bar
|
||||
djui_base_set_location(&sLoading->loadingBar->base, windowWidth / 4, windowHeight - 100);
|
||||
djui_base_set_visible(&sLoading->loadingBar->base, gCurrLoadingSegment.percentage > 0 && strlen(gCurrLoadingSegment.str) > 0);
|
||||
|
||||
djui_base_compute(base);
|
||||
|
||||
pthread_mutex_unlock(&gLoadingThreadMutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void loading_screen_destroy(struct DjuiBase* base) {
|
||||
struct LoadingScreen* load = (struct LoadingScreen*)base;
|
||||
free(load);
|
||||
sLoading = NULL;
|
||||
}
|
||||
|
||||
void render_loading_screen() {
|
||||
struct LoadingScreen* load = malloc(sizeof(struct LoadingScreen));
|
||||
struct DjuiBase* base = &load->base;
|
||||
|
||||
djui_base_init(NULL, base, loading_screen_on_render, loading_screen_destroy);
|
||||
|
||||
{
|
||||
// Splash text
|
||||
struct DjuiText* splashDjuiText = djui_text_create(base, "\\#ff0800\\SM\\#1be700\\64\\#00b3ff\\EX\\#ffef00\\COOP");
|
||||
djui_text_set_font(splashDjuiText, gDjuiFonts[1]);
|
||||
djui_text_set_font_scale(splashDjuiText, gDjuiFonts[1]->defaultFontScale * 4);
|
||||
djui_text_set_alignment(splashDjuiText, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
|
||||
djui_base_set_size(&splashDjuiText->base, 800, 800);
|
||||
|
||||
load->splashText = splashDjuiText;
|
||||
}
|
||||
|
||||
{
|
||||
// "Loading..." text
|
||||
struct DjuiText *text = djui_text_create(base, "");
|
||||
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&text->base, 1.0f, 32 * 4);
|
||||
djui_base_set_color(&text->base, 200, 200, 200, 255);
|
||||
djui_base_set_location(&text->base, 0, 400);
|
||||
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
|
||||
djui_text_set_font(text, gDjuiFonts[0]);
|
||||
djui_text_set_font_scale(text, gDjuiFonts[0]->defaultFontScale * 2);
|
||||
|
||||
load->loadingText = text;
|
||||
}
|
||||
|
||||
{
|
||||
// Current loading stage text
|
||||
struct DjuiText *text = djui_text_create(base, "");
|
||||
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
|
||||
djui_base_set_size(&text->base, 1.0f, 32 * 4);
|
||||
djui_base_set_color(&text->base, 200, 200, 200, 255);
|
||||
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
|
||||
djui_text_set_font(text, gDjuiFonts[0]);
|
||||
djui_text_set_font_scale(text, gDjuiFonts[0]->defaultFontScale * 2);
|
||||
|
||||
load->loadingDesc = text;
|
||||
}
|
||||
|
||||
{
|
||||
// Loading bar
|
||||
struct DjuiProgressBar *progressBar = djui_progress_bar_create(base, &gCurrLoadingSegment.percentage, 0.0f, 1.0f, false);
|
||||
djui_base_set_visible(&progressBar->base, false);
|
||||
progressBar->base.width.value = 0.5;
|
||||
|
||||
load->loadingBar = progressBar;
|
||||
}
|
||||
|
||||
sLoading = load;
|
||||
|
||||
// Loading screen loop
|
||||
while (!gGameInited) {
|
||||
WAPI.main_loop(loading_screen_produce_one_frame);
|
||||
}
|
||||
|
||||
pthread_join(gLoadingThreadId, NULL);
|
||||
|
||||
// Reset some things after rendering the loading screen
|
||||
reset_djui();
|
||||
alloc_display_list_reset();
|
||||
gDisplayListHead = NULL;
|
||||
djui_init();
|
||||
djui_unicode_init();
|
||||
rendering_init();
|
||||
configWindow.settings_changed = true;
|
||||
}
|
25
src/pc/loading.h
Normal file
25
src/pc/loading.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef LOADING_HEADER
|
||||
#define LOADING_HEADER
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct LoadingSegment {
|
||||
char str[256];
|
||||
f32 percentage;
|
||||
};
|
||||
|
||||
extern struct LoadingSegment gCurrLoadingSegment;
|
||||
|
||||
#define REFRESH_MUTEX(...) \
|
||||
pthread_mutex_lock(&gLoadingThreadMutex); \
|
||||
__VA_ARGS__; \
|
||||
pthread_mutex_unlock(&gLoadingThreadMutex); \
|
||||
|
||||
extern pthread_t gLoadingThreadId;
|
||||
extern pthread_mutex_t gLoadingThreadMutex;
|
||||
|
||||
extern bool gIsThreaded;
|
||||
|
||||
void render_loading_screen();
|
||||
|
||||
#endif
|
|
@ -10,10 +10,7 @@
|
|||
#include "pc/crash_handler.h"
|
||||
#include "src/game/hud.h"
|
||||
#include "pc/debug_context.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/network/network_player.h"
|
||||
#include "pc/network/socket/socket.h"
|
||||
#include "pc/chat_commands.h"
|
||||
#include "pc/pc_main.h"
|
||||
|
||||
#if defined(DEVELOPMENT)
|
||||
#include "../mods/mods.h"
|
||||
|
@ -92,6 +89,8 @@ struct LuaHookedEvent {
|
|||
static struct LuaHookedEvent sHookedEvents[HOOK_MAX] = { 0 };
|
||||
|
||||
int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod) {
|
||||
if (!gGameInited) { return 0; } // Don't call hooks while the game is booting
|
||||
|
||||
struct Mod* prev = gLuaActiveMod;
|
||||
gLuaActiveMod = activeMod;
|
||||
gLuaLastHookMod = activeMod;
|
||||
|
|
|
@ -322,7 +322,7 @@ static bool mod_load_files(struct Mod* mod, char* modName, char* fullPath) {
|
|||
const char* fileTypes[] = { ".bin", ".col", NULL };
|
||||
if (!mod_load_files_dir(mod, fullPath, "actors", fileTypes)) { return false; }
|
||||
}
|
||||
|
||||
|
||||
// deal with behaviors directory
|
||||
{
|
||||
const char* fileTypes[] = { ".bhv", NULL };
|
||||
|
@ -525,11 +525,11 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) {
|
|||
}
|
||||
|
||||
// print
|
||||
LOG_INFO(" %s", mod->name);
|
||||
// LOG_INFO(" %s", mod->name);
|
||||
for (int i = 0; i < mod->fileCount; i++) {
|
||||
struct ModFile* file = &mod->files[i];
|
||||
mod_cache_add(mod, file, true);
|
||||
LOG_INFO(" - %s", file->relativePath);
|
||||
// LOG_INFO(" - %s", file->relativePath);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -230,6 +230,7 @@ bool mod_import_file(char* path) {
|
|||
djui_language_replace(DLANG(NOTIF, IMPORT_MOD_SUCCESS), msg, SYS_MAX_PATH, '@', basename);
|
||||
djui_popup_create(msg, 2);
|
||||
} else if (isDynos) {
|
||||
dynos_gfx_init();
|
||||
dynos_packs_init();
|
||||
djui_language_replace(DLANG(NOTIF, IMPORT_DYNOS_SUCCESS), msg, SYS_MAX_PATH, '@', basename);
|
||||
djui_popup_create(msg, 2);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "mod_cache.h"
|
||||
#include "data/dynos.c.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "pc/loading.h"
|
||||
|
||||
#define MAX_SESSION_CHARS 7
|
||||
|
||||
|
@ -147,7 +147,18 @@ static void mods_sort(struct Mods* mods) {
|
|||
}
|
||||
}
|
||||
|
||||
static void mods_load(struct Mods* mods, char* modsBasePath) {
|
||||
static u32 mods_count_directory(char* modsBasePath) {
|
||||
struct dirent* dir = NULL;
|
||||
DIR* d = opendir(modsBasePath);
|
||||
u32 pathCount = 0;
|
||||
while ((dir = readdir(d)) != NULL) pathCount++;
|
||||
closedir(d);
|
||||
return pathCount;
|
||||
}
|
||||
|
||||
static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath) {
|
||||
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs in %s mod path (%s)", isUserModPath ? "user" : "local", modsBasePath)); }
|
||||
|
||||
// generate bins
|
||||
dynos_generate_packs(modsBasePath);
|
||||
|
||||
|
@ -174,10 +185,13 @@ static void mods_load(struct Mods* mods, char* modsBasePath) {
|
|||
LOG_ERROR("Could not open directory '%s'", modsBasePath);
|
||||
return;
|
||||
}
|
||||
f32 count = (f32) mods_count_directory(modsBasePath);
|
||||
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mods in %s mod path (%s)", isUserModPath ? "user" : "local", modsBasePath)); }
|
||||
|
||||
// iterate
|
||||
char path[SYS_MAX_PATH] = { 0 };
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
for (u32 i = 0; (dir = readdir(d)) != NULL; ++i) {
|
||||
|
||||
// sanity check / fill path[]
|
||||
if (!directory_sanity_check(dir, modsBasePath, path)) { continue; }
|
||||
|
||||
|
@ -185,10 +199,11 @@ static void mods_load(struct Mods* mods, char* modsBasePath) {
|
|||
if (!mod_load(mods, modsBasePath, dir->d_name)) {
|
||||
break;
|
||||
}
|
||||
if (gIsThreaded) { REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / count); }
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
if (gIsThreaded) { REFRESH_MUTEX(gCurrLoadingSegment.percentage = 1); }
|
||||
}
|
||||
|
||||
void mods_refresh_local(void) {
|
||||
|
@ -208,13 +223,13 @@ void mods_refresh_local(void) {
|
|||
mods_clear(&gLocalMods);
|
||||
|
||||
// load mods
|
||||
if (hasUserPath) { mods_load(&gLocalMods, userModPath); }
|
||||
if (hasUserPath) { mods_load(&gLocalMods, userModPath, true); }
|
||||
|
||||
const char* exePath = path_to_executable();
|
||||
char defaultModsPath[SYS_MAX_PATH] = { 0 };
|
||||
path_get_folder((char*)exePath, defaultModsPath);
|
||||
strncat(defaultModsPath, MOD_DIRECTORY, SYS_MAX_PATH-1);
|
||||
mods_load(&gLocalMods, defaultModsPath);
|
||||
mods_load(&gLocalMods, defaultModsPath, false);
|
||||
|
||||
// sort
|
||||
mods_sort(&gLocalMods);
|
||||
|
@ -242,6 +257,8 @@ void mods_enable(char* relativePath) {
|
|||
}
|
||||
|
||||
void mods_init(void) {
|
||||
if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Caching mods")); }
|
||||
|
||||
// load mod cache
|
||||
mod_cache_load();
|
||||
mods_refresh_local();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "audio/audio_null.h"
|
||||
|
||||
#include "pc_main.h"
|
||||
#include "loading.h"
|
||||
#include "cliopts.h"
|
||||
#include "configfile.h"
|
||||
#include "controller/controller_api.h"
|
||||
|
@ -238,8 +239,10 @@ void audio_shutdown(void) {
|
|||
}
|
||||
|
||||
void game_deinit(void) {
|
||||
smlua_call_event_hooks(HOOK_ON_EXIT);
|
||||
configfile_save(configfile_name());
|
||||
if (gGameInited) {
|
||||
smlua_call_event_hooks(HOOK_ON_EXIT);
|
||||
configfile_save(configfile_name());
|
||||
}
|
||||
controller_shutdown();
|
||||
audio_custom_shutdown();
|
||||
audio_shutdown();
|
||||
|
@ -256,24 +259,28 @@ void game_exit(void) {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
void main_func(void) {
|
||||
void *main_game_init(void*) {
|
||||
const char *gamedir = gCLIOpts.GameDir[0] ? gCLIOpts.GameDir : FS_BASEDIR;
|
||||
const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path();
|
||||
fs_init(sys_ropaths, gamedir, userpath);
|
||||
|
||||
sync_objects_init_system();
|
||||
djui_unicode_init();
|
||||
djui_init();
|
||||
dynos_packs_init();
|
||||
mods_init();
|
||||
dynos_gfx_init();
|
||||
|
||||
// load config
|
||||
configfile_load();
|
||||
if (!djui_language_init(configLanguage)) {
|
||||
snprintf(configLanguage, MAX_CONFIG_STRING, "%s", "");
|
||||
}
|
||||
configWindow.settings_changed = true;
|
||||
if (!djui_language_init(configLanguage)) { snprintf(configLanguage, MAX_CONFIG_STRING, "%s", ""); }
|
||||
dynos_packs_init();
|
||||
sync_objects_init_system();
|
||||
|
||||
dynos_pack_init();
|
||||
mods_init();
|
||||
enable_queued_mods();
|
||||
if (gIsThreaded) {
|
||||
REFRESH_MUTEX(
|
||||
gCurrLoadingSegment.percentage = 0;
|
||||
snprintf(gCurrLoadingSegment.str, 256, "Starting game");
|
||||
);
|
||||
}
|
||||
|
||||
// If coop_custom_palette_* values are not found in sm64config.txt, the custom palette config will use the default values (Mario's palette)
|
||||
// But if no preset is found, that means the current palette is a custom palette
|
||||
|
@ -292,7 +299,6 @@ void main_func(void) {
|
|||
if (gCLIOpts.FullScreen == 1) { configWindow.fullscreen = true; }
|
||||
else if (gCLIOpts.FullScreen == 2) { configWindow.fullscreen = false; }
|
||||
|
||||
// incase the loading screen failed, or is disabled
|
||||
if (!gGfxInited) {
|
||||
gfx_init(&WAPI, &RAPI, TITLE);
|
||||
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
|
||||
|
@ -310,9 +316,36 @@ void main_func(void) {
|
|||
|
||||
thread5_game_loop(NULL);
|
||||
|
||||
gGameInited = true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// Handle terminal arguments
|
||||
if (!parse_cli_opts(argc, argv)) { return 0; }
|
||||
|
||||
// Create the window straight away
|
||||
if (!gGfxInited) {
|
||||
gfx_init(&WAPI, &RAPI, TITLE);
|
||||
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
|
||||
}
|
||||
|
||||
// Start the thread for setting up the game
|
||||
if (pthread_mutex_init(&gLoadingThreadMutex, NULL) == 0 && pthread_create(&gLoadingThreadId, NULL, main_game_init, (void*) 1) == 0) {
|
||||
gIsThreaded = true;
|
||||
render_loading_screen(); // Render the loading screen while the game is setup
|
||||
gIsThreaded = false;
|
||||
} else {
|
||||
main_game_init(NULL); // Failsafe incase threading doesn't work
|
||||
}
|
||||
pthread_mutex_destroy(&gLoadingThreadMutex);
|
||||
|
||||
// Initialize djui
|
||||
djui_init();
|
||||
djui_unicode_init();
|
||||
djui_init_late();
|
||||
|
||||
// init network
|
||||
// Init network
|
||||
if (gCLIOpts.Network == NT_CLIENT) {
|
||||
network_set_system(NS_SOCKET);
|
||||
snprintf(gGetHostName, MAX_CONFIG_STRING, "%s", gCLIOpts.JoinIp);
|
||||
|
@ -322,6 +355,12 @@ void main_func(void) {
|
|||
} else if (gCLIOpts.Network == NT_SERVER) {
|
||||
network_set_system(NS_SOCKET);
|
||||
configHostPort = gCLIOpts.NetworkPort;
|
||||
|
||||
// Horrible, hacky fix for mods that access marioObj straight away
|
||||
// best fix: host with the standard main menu method
|
||||
static struct Object sHackyObject = { 0 };
|
||||
gMarioStates[0].marioObj = &sHackyObject;
|
||||
|
||||
network_init(NT_SERVER, false);
|
||||
djui_panel_shutdown();
|
||||
djui_panel_modlist_create(NULL);
|
||||
|
@ -329,8 +368,7 @@ void main_func(void) {
|
|||
network_init(NT_NONE, false);
|
||||
}
|
||||
|
||||
gGameInited = true;
|
||||
|
||||
// Main loop
|
||||
while (true) {
|
||||
debug_context_reset();
|
||||
CTX_BEGIN(CTX_FRAME);
|
||||
|
@ -346,10 +384,5 @@ void main_func(void) {
|
|||
}
|
||||
|
||||
bassh_deinit();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
parse_cli_opts(argc, argv);
|
||||
main_func();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -60,8 +60,6 @@ extern bool gCoopCompatibility;
|
|||
#define TITLE "sm64coopdx"
|
||||
#endif
|
||||
|
||||
#define LOAD_STEPS 6
|
||||
|
||||
#define AT_STARTUP __attribute__((constructor))
|
||||
|
||||
extern bool gGameInited;
|
||||
|
|
Loading…
Reference in a new issue