diff --git a/src/twn_engine_context_c.h b/src/twn_engine_context_c.h index 35d77db..95b6b4a 100644 --- a/src/twn_engine_context_c.h +++ b/src/twn_engine_context_c.h @@ -28,6 +28,7 @@ typedef struct EngineContext { char **argv; /* where the app was run from, used as the root for packs */ char *base_dir; + char *title; Vec2 window_dims; Rect viewport_rect; diff --git a/src/twn_loop.c b/src/twn_loop.c index c562d37..de0369b 100644 --- a/src/twn_loop.c +++ b/src/twn_loop.c @@ -4,7 +4,6 @@ #include "twn_util.h" #include "twn_util_c.h" #include "twn_game_object_c.h" -#include "twn_audio_c.h" #include "twn_textures_c.h" #include @@ -20,6 +19,9 @@ #define PACKAGE_EXTENSION "btw" +static SDL_Thread *opengl_load_thread; + + static int event_callback(void *userdata, SDL_Event *event) { (void)userdata; @@ -342,14 +344,16 @@ ERR_PACK_MANIFEST_PATH_ALLOC_FAIL: } -static bool initialize(void) { - profile_start("SDL initialization"); - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) == -1) { - CRY_SDL("SDL initialization failed."); - return false; - } - profile_end("SDL initialization"); +static int opengl_load_thread_fn(void *data) { + (void)data; + SDL_GL_LoadLibrary(NULL); + + return 0; +} + + +static bool initialize(void) { /* first things first, most things here will be loaded from the config file */ /* it's expected to be present in the data directory, no matter what */ /* that is why PhysicsFS is initialized before anything else */ @@ -446,91 +450,46 @@ static bool initialize(void) { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); - /* init got far enough to create a window */ - { - toml_datum_t datum_title = toml_string_in(about, "title"); - if (!datum_title.ok) - datum_title.u.s = "townengine project"; + toml_datum_t datum_title = toml_string_in(about, "title"); + if (!datum_title.ok) + datum_title.u.s = SDL_strdup("townengine project"); - /* not yet used - toml_datum_t datum_developer = toml_string_in(about, "developer"); - if (!datum_developer.ok) { - CRY("Initialization failed", "Valid about.developer expected in configuration file"); + ctx.title = datum_title.u.s; + + /* not yet used + toml_datum_t datum_developer = toml_string_in(about, "developer"); + if (!datum_developer.ok) { + CRY("Initialization failed", "Valid about.developer expected in configuration file"); + goto fail; + } + */ + + toml_array_t *datum_resolution = toml_array_in(game, "resolution"); + if (datum_resolution) { + toml_datum_t datum_base_render_width = toml_int_at(datum_resolution, 0); + if (!datum_base_render_width.ok) { + CRY("Initialization failed", "Valid game.resolution expected in configuration file"); goto fail; } - */ - toml_array_t *datum_resolution = toml_array_in(game, "resolution"); - if (datum_resolution) { - toml_datum_t datum_base_render_width = toml_int_at(datum_resolution, 0); - if (!datum_base_render_width.ok) { - CRY("Initialization failed", "Valid game.resolution expected in configuration file"); - goto fail; - } - - toml_datum_t datum_base_render_height = toml_int_at(datum_resolution, 1); - if (!datum_base_render_height.ok) { - CRY("Initialization failed", "Valid game.resolution expected in configuration file"); - goto fail; - } - - ctx.base_render_width = datum_base_render_width.u.i; - ctx.base_render_height = datum_base_render_height.u.i; - - } else { - ctx.base_render_width = 640; - ctx.base_render_height = 360; + toml_datum_t datum_base_render_height = toml_int_at(datum_resolution, 1); + if (!datum_base_render_height.ok) { + CRY("Initialization failed", "Valid game.resolution expected in configuration file"); + goto fail; } - ctx.game.resolution.x = (float)ctx.base_render_width; - ctx.game.resolution.y = (float)ctx.base_render_height; + ctx.base_render_width = datum_base_render_width.u.i; + ctx.base_render_height = datum_base_render_height.u.i; - /* TODO: investigate viability of detached thread driver and window creation, as it's the worst load time offender */ - profile_start("window creation"); - ctx.window = SDL_CreateWindow(datum_title.u.s, - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - (int)ctx.base_render_width, - (int)ctx.base_render_height, - //SDL_WINDOW_ALLOW_HIGHDPI | - SDL_WINDOW_RESIZABLE | - SDL_WINDOW_OPENGL); - profile_end("window creation"); - - if (datum_title.ok) - SDL_free(datum_title.u.s); - - //SDL_free(datum_developer.u.s); + } else { + ctx.base_render_width = 640; + ctx.base_render_height = 360; } - if (ctx.window == NULL) { - CRY_SDL("Window creation failed."); - goto fail; - } + ctx.game.resolution.x = (float)ctx.base_render_width; + ctx.game.resolution.y = (float)ctx.base_render_height; - profile_start("opengl context creation"); - ctx.gl_context = SDL_GL_CreateContext(ctx.window); - if (!ctx.gl_context) { - CRY_SDL("GL context creation failed."); - goto fail; - } - - if (SDL_GL_MakeCurrent(ctx.window, ctx.gl_context)) { - CRY_SDL("GL context binding failed."); - goto fail; - } - - /* TODO: figure out what we ultimately prefer */ - SDL_GL_SetSwapInterval(0); - - if (!render_init()) - goto fail; - - setup_viewport(0, 0, (int)ctx.base_render_width, (int)ctx.base_render_height); - profile_end("opengl context creation"); - - /* might need this to have multiple windows */ - ctx.window_id = SDL_GetWindowID(ctx.window); + //SDL_free(datum_developer.u.s); /* TODO: */ // SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h); @@ -628,11 +587,6 @@ static bool initialize(void) { ctx.render_queue_2d = NULL; ctx.uncolored_mesh_batches = NULL; - profile_start("texture and text cache initialization"); - textures_cache_init(&ctx.texture_cache, ctx.window); - text_cache_init(&ctx.text_cache); - profile_end("texture and text cache initialization"); - /* input */ toml_datum_t datum_keybind_slots = toml_int_in(engine, "keybind_slots"); if (!datum_keybind_slots.ok) { @@ -652,6 +606,63 @@ static bool initialize(void) { ctx.game.fog_color = (Color){ 255, 255, 255, 255 }; /* TODO: pick some grey? */ ctx.game.fog_end = 1.0f; + update_viewport(); + + profile_start("game object load"); + /* now we can actually start doing stuff */ + game_object_load(); + profile_end("game object load"); + + /* delayed as further as possible so that more work is done before we have to wait */ + SDL_WaitThread(opengl_load_thread, NULL); + profile_end("opengl loading"); + + /* TODO: investigate viability of detached thread driver and window creation, as it's the worst load time offender */ + profile_start("window creation"); + ctx.window = SDL_CreateWindow(ctx.title, + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + (int)ctx.base_render_width, + (int)ctx.base_render_height, + //SDL_WINDOW_ALLOW_HIGHDPI | + SDL_WINDOW_RESIZABLE | + SDL_WINDOW_OPENGL); + profile_end("window creation"); + + if (ctx.window == NULL) { + CRY_SDL("Window creation failed."); + goto fail; + } + + profile_start("opengl context creation"); + ctx.gl_context = SDL_GL_CreateContext(ctx.window); + if (!ctx.gl_context) { + CRY_SDL("GL context creation failed."); + goto fail; + } + + if (SDL_GL_MakeCurrent(ctx.window, ctx.gl_context)) { + CRY_SDL("GL context binding failed."); + goto fail; + } + + /* TODO: figure out what we ultimately prefer */ + SDL_GL_SetSwapInterval(0); + + if (!render_init()) + goto fail; + + setup_viewport(0, 0, (int)ctx.base_render_width, (int)ctx.base_render_height); + profile_end("opengl context creation"); + + /* might need this to have multiple windows */ + ctx.window_id = SDL_GetWindowID(ctx.window); + + profile_start("texture and text cache initialization"); + textures_cache_init(&ctx.texture_cache, ctx.window); + text_cache_init(&ctx.text_cache); + profile_end("texture and text cache initialization"); + return true; fail: @@ -674,7 +685,9 @@ static void clean_up(void) { PHYSFS_deinit(); SDL_free(ctx.base_dir); + SDL_free(ctx.title); SDL_GL_DeleteContext(ctx.gl_context); + SDL_GL_UnloadLibrary(); SDL_Quit(); } @@ -688,6 +701,20 @@ static void reset_state(void) { int enter_loop(int argc, char **argv) { profile_start("startup"); + profile_start("SDL initialization"); + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) == -1) { + CRY_SDL("SDL initialization failed."); + return EXIT_FAILURE; + } + profile_end("SDL initialization"); + + profile_start("opengl loading"); + opengl_load_thread = SDL_CreateThread(opengl_load_thread_fn, "opengl loader", NULL); + if (!opengl_load_thread) { + CRY_SDL("Cannot create opengl loading thread: "); + return EXIT_FAILURE; + } + ctx.argc = argc; ctx.argv = argv; ctx.base_dir = SDL_GetBasePath(); @@ -763,13 +790,6 @@ int enter_loop(int argc, char **argv) { ctx.game.debug = false; } - update_viewport(); - - profile_start("game object load"); - /* now we can actually start doing stuff */ - game_object_load(); - profile_end("game object load"); - ctx.was_successful = true; ctx.game.initialization_needed = true;