implement game configuration file
this integrates https://github.com/cktan/tomlc99 into the repo as a dependency
This commit is contained in:
@ -104,7 +104,7 @@ void use_2d_pipeline(void) {
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
|
||||
glOrtho(0, (double)ctx.base_render_width, (double)ctx.base_render_height, 0, -1, 1);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
@ -106,9 +106,9 @@ void render(void) {
|
||||
|
||||
/* fit rendering context onto the resizable screen */
|
||||
if (ctx.game.window_size_has_changed) {
|
||||
if ((float)ctx.game.window_w / (float)ctx.game.window_h > RENDER_BASE_RATIO) {
|
||||
float ratio = (float)ctx.game.window_h / (float)RENDER_BASE_HEIGHT;
|
||||
int w = (int)((float)RENDER_BASE_WIDTH * ratio);
|
||||
if ((float)ctx.game.window_w / (float)ctx.game.window_h > (float)(ctx.base_render_width / ctx.base_render_height)) {
|
||||
float ratio = (float)ctx.game.window_h / (float)ctx.base_render_height;
|
||||
int w = (int)((float)ctx.base_render_width * ratio);
|
||||
setup_viewport(
|
||||
ctx.game.window_w / 2 - w / 2,
|
||||
0,
|
||||
@ -116,8 +116,8 @@ void render(void) {
|
||||
ctx.game.window_h
|
||||
);
|
||||
} else {
|
||||
float ratio = (float)ctx.game.window_w / (float)RENDER_BASE_WIDTH;
|
||||
int h = (int)((float)RENDER_BASE_HEIGHT * ratio);
|
||||
float ratio = (float)ctx.game.window_w / (float)ctx.base_render_width;
|
||||
int h = (int)((float)ctx.base_render_height * ratio);
|
||||
setup_viewport(
|
||||
0,
|
||||
ctx.game.window_h / 2 - h / 2,
|
||||
|
@ -99,7 +99,7 @@ static FontData *text_load_font_data(const char *path, int height_px) {
|
||||
font_data->file_path = path;
|
||||
font_data->height_px = height_px;
|
||||
|
||||
unsigned char* bitmap = ccalloc(TEXT_FONT_TEXTURE_SIZE * TEXT_FONT_TEXTURE_SIZE, 1);
|
||||
unsigned char* bitmap = ccalloc(ctx.font_texture_size * ctx.font_texture_size, 1);
|
||||
|
||||
{
|
||||
unsigned char *buf = NULL;
|
||||
@ -121,19 +121,19 @@ static FontData *text_load_font_data(const char *path, int height_px) {
|
||||
font_data->line_gap = (int)((float)font_data->line_gap * font_data->scale_factor);
|
||||
|
||||
stbtt_pack_context pctx;
|
||||
stbtt_PackBegin(&pctx, bitmap, TEXT_FONT_TEXTURE_SIZE, TEXT_FONT_TEXTURE_SIZE, 0, 1, NULL);
|
||||
stbtt_PackSetOversampling(&pctx, TEXT_FONT_OVERSAMPLING, TEXT_FONT_OVERSAMPLING);
|
||||
stbtt_PackBegin(&pctx, bitmap, (int)ctx.font_texture_size, (int)ctx.font_texture_size, 0, 1, NULL);
|
||||
stbtt_PackSetOversampling(&pctx, (unsigned int)ctx.font_oversampling, (unsigned int)ctx.font_oversampling);
|
||||
stbtt_PackFontRange(&pctx, buf, 0, (float)height_px, ASCII_START, NUM_DISPLAY_ASCII, font_data->char_data);
|
||||
stbtt_PackEnd(&pctx);
|
||||
}
|
||||
|
||||
font_data->texture = create_gpu_texture(TEXT_FONT_FILTERING, true);
|
||||
font_data->texture = create_gpu_texture(ctx.font_filtering, true);
|
||||
upload_gpu_texture(
|
||||
font_data->texture,
|
||||
bitmap,
|
||||
1,
|
||||
TEXT_FONT_TEXTURE_SIZE,
|
||||
TEXT_FONT_TEXTURE_SIZE
|
||||
(int)ctx.font_texture_size,
|
||||
(int)ctx.font_texture_size
|
||||
);
|
||||
SDL_free(bitmap);
|
||||
|
||||
@ -169,8 +169,8 @@ static void text_draw_with(FontData* font_data, char* text, Vec2 position, Color
|
||||
stbtt_aligned_quad quad;
|
||||
stbtt_GetPackedQuad(
|
||||
font_data->char_data,
|
||||
TEXT_FONT_TEXTURE_SIZE,
|
||||
TEXT_FONT_TEXTURE_SIZE,
|
||||
(int)ctx.font_texture_size,
|
||||
(int)ctx.font_texture_size,
|
||||
c - ASCII_START,
|
||||
&position.x,
|
||||
&position.y,
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "twn_camera.h"
|
||||
#include "twn_config.h"
|
||||
#include "twn_engine_context_c.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@ -37,7 +38,7 @@ Matrix4 camera_perspective(const Camera *const camera) {
|
||||
/* from cglm */
|
||||
Matrix4 result = {0};
|
||||
|
||||
const float aspect = RENDER_BASE_RATIO;
|
||||
const float aspect = (float)(ctx.base_render_width / ctx.base_render_height);
|
||||
|
||||
const float f = 1.0f / tanf(camera->fov * 0.5f);
|
||||
const float fn = 1.0f / (CAMERA_NEAR_Z - CAMERA_FAR_Z);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "rendering/twn_rendering_c.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <toml.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@ -21,11 +22,24 @@ typedef struct EngineContext {
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
struct Primitive2D *render_queue_2d;
|
||||
/* configuration */
|
||||
toml_table_t *config_table;
|
||||
int64_t base_render_width;
|
||||
int64_t base_render_height;
|
||||
int64_t ticks_per_second;
|
||||
int64_t keybind_slots;
|
||||
int64_t texture_atlas_size;
|
||||
int64_t font_texture_size;
|
||||
int64_t font_oversampling;
|
||||
TextureFilter font_filtering;
|
||||
|
||||
/* rendering */
|
||||
Primitive2D *render_queue_2d;
|
||||
MeshBatchItem *uncolored_mesh_batches;
|
||||
struct TextCache text_cache;
|
||||
TextCache text_cache;
|
||||
TextureCache texture_cache;
|
||||
|
||||
/* audio */
|
||||
AudioChannelItem *audio_channels;
|
||||
SDL_AudioDeviceID audio_device;
|
||||
int audio_stream_frequency;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "twn_input_c.h"
|
||||
#include "twn_util.h"
|
||||
#include "twn_engine_context_c.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stb_ds.h>
|
||||
@ -9,7 +10,7 @@
|
||||
|
||||
|
||||
static void update_action_pressed_state(InputState *input, Action *action) {
|
||||
for (size_t i = 0; i < SDL_arraysize(action->bindings); ++i) {
|
||||
for (size_t i = 0; i < (uint64_t)ctx.keybind_slots; ++i) {
|
||||
switch (action->bindings[i].source) {
|
||||
case BUTTON_SOURCE_NOT_SET:
|
||||
break;
|
||||
@ -74,7 +75,7 @@ static void input_bind_code_to_action(InputState *input,
|
||||
Action *action = &action_item->value;
|
||||
|
||||
/* check every binding to make sure this code isn't already bound */
|
||||
for (size_t i = 0; i < SDL_arraysize(action->bindings); ++i) {
|
||||
for (size_t i = 0; i < (uint64_t)ctx.keybind_slots; ++i) {
|
||||
Button *binding = &action->bindings[i];
|
||||
|
||||
if (binding->source != source)
|
||||
@ -105,7 +106,7 @@ static void input_bind_code_to_action(InputState *input,
|
||||
}
|
||||
|
||||
/* if we're at max bindings, forget the first element and shift the rest */
|
||||
if (action->num_bindings == SDL_arraysize(action->bindings)) {
|
||||
if (action->num_bindings == (uint64_t)ctx.keybind_slots) {
|
||||
--action->num_bindings;
|
||||
size_t shifted_size = (sizeof action->bindings) - (sizeof action->bindings[0]);
|
||||
SDL_memmove(action->bindings, action->bindings + 1, shifted_size);
|
||||
@ -133,7 +134,7 @@ static void input_unbind_code_from_action(InputState *input,
|
||||
/* check every binding to make sure this code is bound */
|
||||
size_t index = 0;
|
||||
bool is_bound = false;
|
||||
for (index = 0; index < SDL_arraysize(action->bindings); ++index) {
|
||||
for (index = 0; index < (uint64_t)ctx.keybind_slots; ++index) {
|
||||
Button *binding = &action->bindings[index];
|
||||
|
||||
if (binding->source != source)
|
||||
@ -249,13 +250,21 @@ void input_add_action(InputState *input, char *action_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
shput(input->action_hash, action_name, (Action) { 0 });
|
||||
Action new_action = { 0 };
|
||||
new_action.bindings = ccalloc(ctx.keybind_slots, sizeof *new_action.bindings);
|
||||
shput(input->action_hash, action_name, new_action);
|
||||
}
|
||||
|
||||
|
||||
void input_delete_action(InputState *input, char *action_name) {
|
||||
if (shdel(input->action_hash, action_name) == 0)
|
||||
ActionHashItem *action = shgetp_null(input->action_hash, action_name);
|
||||
if (action == NULL) {
|
||||
log_warn("(%s) Action \"%s\" is not registered.", __func__, action_name);
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_free(action->value.bindings);
|
||||
shdel(input->action_hash, action_name);
|
||||
}
|
||||
|
||||
|
||||
@ -314,5 +323,10 @@ bool input_is_mouse_captured(InputState *input) {
|
||||
|
||||
|
||||
void input_reset_state(InputState *input) {
|
||||
for (size_t i = 0; i < shlenu(input->action_hash); ++i) {
|
||||
Action *action = &input->action_hash[i].value;
|
||||
SDL_free(action->bindings);
|
||||
}
|
||||
|
||||
stbds_shfree(input->action_hash);
|
||||
}
|
||||
|
265
src/twn_loop.c
265
src/twn_loop.c
@ -9,6 +9,7 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <physfs.h>
|
||||
#include <stb_ds.h>
|
||||
#include <toml.h>
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include <GLES2/gl2.h>
|
||||
@ -193,14 +194,78 @@ static bool initialize(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* debug mode defaults to being enabled on debug builds. */
|
||||
/* pass --debug to enable it on release builds */
|
||||
/* or, on debug builds, pass --release to disable it */
|
||||
#ifndef NDEBUG
|
||||
ctx.game.debug = true;
|
||||
#else
|
||||
ctx.game.debug = false;
|
||||
#endif
|
||||
/* 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 */
|
||||
toml_set_memutil(SDL_malloc, SDL_free);
|
||||
|
||||
/* load the config file into an opaque table */
|
||||
{
|
||||
char *config_file = file_to_str("/twn.toml");
|
||||
if (config_file == NULL) {
|
||||
CRY_PHYSFS("Configuration file loading failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
char errbuf[256]; /* tomlc99 example implies that this is enough... */
|
||||
ctx.config_table = toml_parse(config_file, errbuf, sizeof errbuf);
|
||||
SDL_free(config_file);
|
||||
|
||||
if (ctx.config_table == NULL) {
|
||||
CRY("Configuration file loading failed", errbuf);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* at this point we can save references to the tables within the parent one for later */
|
||||
toml_table_t *about = toml_table_in(ctx.config_table, "about");
|
||||
if (about == NULL) {
|
||||
CRY("Initialization failed", "[about] table expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
toml_table_t *game = toml_table_in(ctx.config_table, "game");
|
||||
if (game == NULL) {
|
||||
CRY("Initialization failed", "[game] table expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
toml_table_t *engine = toml_table_in(ctx.config_table, "engine");
|
||||
if (engine == NULL) {
|
||||
CRY("Initialization failed", "[engine] table expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* configure physicsfs write dir */
|
||||
{
|
||||
toml_datum_t datum_dev_id = toml_string_in(about, "dev_id");
|
||||
if (!datum_dev_id.ok) {
|
||||
CRY("Initialization failed", "Valid about.dev_id expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
toml_datum_t datum_app_id = toml_string_in(about, "app_id");
|
||||
if (!datum_app_id.ok) {
|
||||
CRY("Initialization failed", "Valid about.app_id expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!PHYSFS_setSaneConfig(datum_dev_id.u.s, datum_app_id.u.s, PACKAGE_EXTENSION, false, true)) {
|
||||
CRY_PHYSFS("Filesystem initialization failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SDL_free(datum_dev_id.u.s);
|
||||
SDL_free(datum_app_id.u.s);
|
||||
}
|
||||
|
||||
/* debug mode defaults to being enabled */
|
||||
/* pass --debug or --release to force a mode, ignoring configuration */
|
||||
toml_datum_t datum_debug = toml_bool_in(game, "debug");
|
||||
if (!datum_debug.ok) {
|
||||
ctx.game.debug = true;
|
||||
} else {
|
||||
ctx.game.debug = datum_debug.u.b;
|
||||
}
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
/* emscripten interpretes those as GL ES version against WebGL */
|
||||
@ -225,14 +290,48 @@ static bool initialize(void) {
|
||||
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
|
||||
|
||||
/* init got far enough to create a window */
|
||||
ctx.window = SDL_CreateWindow("townengine",
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
RENDER_BASE_WIDTH,
|
||||
RENDER_BASE_HEIGHT,
|
||||
// SDL_WINDOW_ALLOW_HIGHDPI |
|
||||
SDL_WINDOW_RESIZABLE |
|
||||
SDL_WINDOW_OPENGL);
|
||||
{
|
||||
toml_datum_t datum_title = toml_string_in(about, "title");
|
||||
if (!datum_title.ok) {
|
||||
CRY("Initialization failed", "Valid about.title expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
/* 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_datum_t datum_base_render_width = toml_int_in(game, "base_render_width");
|
||||
if (!datum_base_render_width.ok) {
|
||||
CRY("Initialization failed", "Valid game.base_render_width expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
ctx.base_render_width = datum_base_render_width.u.i;
|
||||
ctx.game.base_draw_w = (int)ctx.base_render_width;
|
||||
|
||||
toml_datum_t datum_base_render_height = toml_int_in(game, "base_render_height");
|
||||
if (!datum_base_render_height.ok) {
|
||||
CRY("Initialization failed", "Valid game.base_render_height expected in configuration file");
|
||||
goto fail;
|
||||
}
|
||||
ctx.base_render_height = datum_base_render_height.u.i;
|
||||
ctx.game.base_draw_h = (int)ctx.base_render_height;
|
||||
|
||||
ctx.window = SDL_CreateWindow(datum_title.u.s,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
(int)datum_base_render_width.u.i,
|
||||
(int)datum_base_render_height.u.i,
|
||||
//SDL_WINDOW_ALLOW_HIGHDPI |
|
||||
SDL_WINDOW_RESIZABLE |
|
||||
SDL_WINDOW_OPENGL);
|
||||
|
||||
SDL_free(datum_title.u.s);
|
||||
//SDL_free(datum_developer.u.s);
|
||||
}
|
||||
|
||||
if (ctx.window == NULL) {
|
||||
CRY_SDL("Window creation failed.");
|
||||
goto fail;
|
||||
@ -270,12 +369,12 @@ static bool initialize(void) {
|
||||
/* might need this to have multiple windows */
|
||||
ctx.window_id = SDL_GetWindowID(ctx.window);
|
||||
|
||||
glViewport(0, 0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT);
|
||||
glViewport(0, 0, ctx.base_render_width, ctx.base_render_height);
|
||||
|
||||
/* TODO: */
|
||||
// SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h);
|
||||
ctx.game.window_w = RENDER_BASE_WIDTH;
|
||||
ctx.game.window_h = RENDER_BASE_HEIGHT;
|
||||
ctx.game.window_w = (int)ctx.base_render_width;
|
||||
ctx.game.window_h = (int)ctx.base_render_height;
|
||||
|
||||
/* audio initialization */
|
||||
{
|
||||
@ -297,15 +396,6 @@ static bool initialize(void) {
|
||||
|
||||
}
|
||||
|
||||
/* filesystem time */
|
||||
/* TODO: ANDROID: see the warning in physicsfs PHYSFS_init docs/header */
|
||||
if (!PHYSFS_init(ctx.argv[0]) ||
|
||||
!PHYSFS_setSaneConfig(ORGANIZATION_NAME, APP_NAME, PACKAGE_EXTENSION, false, true))
|
||||
{
|
||||
CRY_PHYSFS("Filesystem initialization failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* you could change this at runtime if you wanted */
|
||||
ctx.game.update_multiplicity = 1;
|
||||
|
||||
@ -325,11 +415,22 @@ static bool initialize(void) {
|
||||
stbds_rand_seed(ctx.game.random_seed);
|
||||
|
||||
/* main loop machinery */
|
||||
toml_datum_t datum_ticks_per_second = toml_int_in(engine, "ticks_per_second");
|
||||
if (!datum_ticks_per_second.ok) {
|
||||
ctx.ticks_per_second = TICKS_PER_SECOND_DEFAULT;
|
||||
} else {
|
||||
if (datum_ticks_per_second.u.i < 8) {
|
||||
ctx.ticks_per_second = TICKS_PER_SECOND_DEFAULT;
|
||||
} else {
|
||||
ctx.ticks_per_second = datum_ticks_per_second.u.i;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.game.is_running = true;
|
||||
ctx.resync_flag = true;
|
||||
ctx.clocks_per_second = SDL_GetPerformanceFrequency();
|
||||
ctx.prev_frame_time = SDL_GetPerformanceCounter();
|
||||
ctx.desired_frametime = ctx.clocks_per_second / TICKS_PER_SECOND;
|
||||
ctx.desired_frametime = ctx.clocks_per_second / ctx.ticks_per_second;
|
||||
ctx.frame_accumulator = 0;
|
||||
ctx.game.tick_count = 0;
|
||||
|
||||
@ -340,6 +441,56 @@ static bool initialize(void) {
|
||||
}
|
||||
|
||||
/* rendering */
|
||||
/* configuration */
|
||||
{
|
||||
toml_datum_t datum_texture_atlas_size = toml_int_in(engine, "texture_atlas_size");
|
||||
if (!datum_texture_atlas_size.ok) {
|
||||
ctx.texture_atlas_size = TEXTURE_ATLAS_SIZE_DEFAULT;
|
||||
} else {
|
||||
if (datum_texture_atlas_size.u.i < 32) {
|
||||
ctx.texture_atlas_size = TEXTURE_ATLAS_SIZE_DEFAULT;
|
||||
} else {
|
||||
ctx.texture_atlas_size = datum_texture_atlas_size.u.i;
|
||||
}
|
||||
}
|
||||
|
||||
toml_datum_t datum_font_texture_size = toml_int_in(engine, "font_texture_size");
|
||||
if (!datum_font_texture_size.ok) {
|
||||
ctx.font_texture_size = TEXT_FONT_TEXTURE_SIZE_DEFAULT;
|
||||
} else {
|
||||
if (datum_font_texture_size.u.i < 1024) {
|
||||
ctx.font_texture_size = TEXT_FONT_TEXTURE_SIZE_DEFAULT;
|
||||
} else {
|
||||
ctx.font_texture_size = datum_font_texture_size.u.i;
|
||||
}
|
||||
}
|
||||
|
||||
toml_datum_t datum_font_oversampling = toml_int_in(engine, "font_oversampling");
|
||||
if (!datum_font_oversampling.ok) {
|
||||
ctx.font_oversampling = TEXT_FONT_OVERSAMPLING_DEFAULT;
|
||||
} else {
|
||||
if (datum_font_oversampling.u.i < 0) {
|
||||
ctx.font_oversampling = TEXT_FONT_OVERSAMPLING_DEFAULT;
|
||||
} else {
|
||||
ctx.font_oversampling = datum_font_oversampling.u.i;
|
||||
}
|
||||
}
|
||||
|
||||
toml_datum_t datum_font_filtering = toml_string_in(engine, "font_filtering");
|
||||
if (!datum_font_filtering.ok) {
|
||||
ctx.font_filtering = TEXT_FONT_FILTERING_DEFAULT;
|
||||
} else {
|
||||
if (SDL_strcmp(datum_font_filtering.u.s, "nearest") == 0) {
|
||||
ctx.font_filtering = TEXTURE_FILTER_NEAREAST;
|
||||
} else if (SDL_strcmp(datum_font_filtering.u.s, "linear") == 0) {
|
||||
ctx.font_filtering = TEXTURE_FILTER_LINEAR;
|
||||
} else {
|
||||
ctx.font_filtering = TEXT_FONT_FILTERING_DEFAULT;
|
||||
}
|
||||
}
|
||||
SDL_free(datum_font_filtering.u.s);
|
||||
}
|
||||
|
||||
/* these are dynamic arrays and will be allocated lazily by stb_ds */
|
||||
ctx.render_queue_2d = NULL;
|
||||
ctx.uncolored_mesh_batches = NULL;
|
||||
@ -348,6 +499,16 @@ static bool initialize(void) {
|
||||
text_cache_init(&ctx.text_cache);
|
||||
|
||||
/* input */
|
||||
toml_datum_t datum_keybind_slots = toml_int_in(engine, "keybind_slots");
|
||||
if (!datum_keybind_slots.ok) {
|
||||
ctx.keybind_slots = KEYBIND_SLOTS_DEFAULT;
|
||||
} else {
|
||||
if (datum_keybind_slots.u.i < 1) {
|
||||
ctx.keybind_slots = KEYBIND_SLOTS_DEFAULT;
|
||||
} else {
|
||||
ctx.keybind_slots = datum_keybind_slots.u.i;
|
||||
}
|
||||
}
|
||||
input_state_init(&ctx.game.input);
|
||||
|
||||
/* scripting */
|
||||
@ -377,6 +538,7 @@ static void clean_up(void) {
|
||||
|
||||
arrfree(ctx.render_queue_2d);
|
||||
|
||||
toml_free(ctx.config_table);
|
||||
PHYSFS_deinit();
|
||||
SDL_Quit();
|
||||
}
|
||||
@ -392,11 +554,35 @@ int enter_loop(int argc, char **argv) {
|
||||
ctx.argc = argc;
|
||||
ctx.argv = argv;
|
||||
|
||||
|
||||
if (!initialize())
|
||||
/* needs to be done before anything else so config can be loaded */
|
||||
/* TODO: ANDROID: see the warning in physicsfs PHYSFS_init docs/header */
|
||||
if (!PHYSFS_init(ctx.argv[0]) || !PHYSFS_mount(PHYSFS_getBaseDir(), NULL, true)) {
|
||||
CRY_PHYSFS("Filesystem initialization failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* base dir is fine, but we'd like to look into all the data archives, too */
|
||||
char **files_here = PHYSFS_enumerateFiles("/");
|
||||
if (files_here == NULL) {
|
||||
CRY_PHYSFS("Filesystem initialization failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (char **ptr = files_here; *ptr != NULL; ++ptr) {
|
||||
char *file = *ptr;
|
||||
|
||||
if (!strends(file, "." PACKAGE_EXTENSION)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!PHYSFS_mount(file, "/", true)) {
|
||||
CRY_PHYSFS("Filesystem initialization failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
PHYSFS_freeList(files_here);
|
||||
|
||||
/* process arguments */
|
||||
bool force_debug = false;
|
||||
bool force_release = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
/* override data directory */
|
||||
if (SDL_strcmp(argv[i], "--data-dir") == 0) {
|
||||
@ -415,17 +601,29 @@ int enter_loop(int argc, char **argv) {
|
||||
|
||||
/* force debug mode */
|
||||
if (SDL_strcmp(argv[i], "--debug") == 0) {
|
||||
ctx.game.debug = true;
|
||||
force_debug = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* force release mode */
|
||||
if (SDL_strcmp(argv[i], "--release") == 0) {
|
||||
ctx.game.debug = false;
|
||||
force_release = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialize())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* good time to override anything that was set in initialize() */
|
||||
if (force_debug) {
|
||||
ctx.game.debug = true;
|
||||
}
|
||||
if (force_release) {
|
||||
ctx.game.debug = false;
|
||||
}
|
||||
|
||||
/* now we can actually start doing stuff */
|
||||
game_object_load();
|
||||
|
||||
ctx.was_successful = true;
|
||||
@ -440,6 +638,7 @@ int enter_loop(int argc, char **argv) {
|
||||
main_loop();
|
||||
}
|
||||
|
||||
/* loop is over */
|
||||
game_object_unload();
|
||||
|
||||
clean_up();
|
||||
|
@ -132,7 +132,7 @@ static SDL_Surface *create_surface(int width, int height) {
|
||||
|
||||
/* adds a new, blank atlas surface to the cache */
|
||||
static void add_new_atlas(TextureCache *cache) {
|
||||
SDL_Surface *new_atlas = create_surface(TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS_SIZE);
|
||||
SDL_Surface *new_atlas = create_surface((int)ctx.texture_atlas_size, (int)ctx.texture_atlas_size);
|
||||
arrput(cache->atlas_surfaces, new_atlas);
|
||||
arrput(cache->atlas_textures, create_gpu_texture(TEXTURE_FILTER_NEAREAST, true));
|
||||
}
|
||||
@ -269,7 +269,7 @@ void textures_cache_init(TextureCache *cache, SDL_Window *window) {
|
||||
cache->window = window;
|
||||
sh_new_arena(cache->hash);
|
||||
|
||||
cache->node_buffer = SDL_calloc(TEXTURE_ATLAS_SIZE, sizeof *cache->node_buffer);
|
||||
cache->node_buffer = SDL_calloc(ctx.texture_atlas_size, sizeof *cache->node_buffer);
|
||||
|
||||
add_new_atlas(cache);
|
||||
recreate_current_atlas_texture(cache);
|
||||
@ -341,7 +341,7 @@ static TextureKey textures_load(TextureCache *cache, const char *path) {
|
||||
};
|
||||
|
||||
/* it's a "loner texture," it doesn't fit in an atlas so it's not in one */
|
||||
if (surface->w >= TEXTURE_ATLAS_SIZE || surface->h >= TEXTURE_ATLAS_SIZE) {
|
||||
if (surface->w >= ctx.texture_atlas_size || surface->h >= ctx.texture_atlas_size) {
|
||||
if (ctx.game.debug) {
|
||||
if (surface->w > 2048 || surface->h > 2048)
|
||||
log_warn("Unportable texture dimensions for %s, use 2048x2048 at max", path);
|
||||
@ -368,10 +368,10 @@ void textures_update_atlas(TextureCache *cache) {
|
||||
/* this function makes a lot more sense if you read stb_rect_pack.h */
|
||||
stbrp_context pack_ctx; /* target info */
|
||||
stbrp_init_target(&pack_ctx,
|
||||
TEXTURE_ATLAS_SIZE,
|
||||
TEXTURE_ATLAS_SIZE,
|
||||
ctx.texture_atlas_size,
|
||||
ctx.texture_atlas_size,
|
||||
cache->node_buffer,
|
||||
TEXTURE_ATLAS_SIZE);
|
||||
ctx.texture_atlas_size);
|
||||
|
||||
stbrp_rect *rects = create_rects_from_cache(cache);
|
||||
|
||||
@ -493,7 +493,7 @@ Rect textures_get_dims(const TextureCache *cache, TextureKey key) {
|
||||
if (cache->hash[key.id].value.loner_texture != 0)
|
||||
return cache->hash[key.id].value.srcrect;
|
||||
else
|
||||
return (Rect){ .w = TEXTURE_ATLAS_SIZE, .h = TEXTURE_ATLAS_SIZE };
|
||||
return (Rect){ .w = ctx.texture_atlas_size, .h = ctx.texture_atlas_size };
|
||||
} else {
|
||||
CRY("Texture lookup failed.",
|
||||
"Tried to get texture that isn't loaded.");
|
||||
|
Reference in New Issue
Block a user