implement game configuration file

this integrates https://github.com/cktan/tomlc99 into the repo as a dependency
This commit is contained in:
wanp 2024-09-30 21:13:58 -03:00 committed by veclavtalica
parent ec15d8ec4b
commit 57fe5e8946
165 changed files with 4797 additions and 92 deletions

View File

@ -86,6 +86,7 @@ endif()
set(TWN_THIRD_PARTY_SOURCE_FILES set(TWN_THIRD_PARTY_SOURCE_FILES
third-party/physfs/extras/physfsrwops.c third-party/physfs/extras/physfsrwops.c
third-party/stb/stb_vorbis.c third-party/stb/stb_vorbis.c
third-party/tomlc99/toml.c
$<$<NOT:$<BOOL:${EMSCRIPTEN}>>:third-party/glad/src/glad.c>) $<$<NOT:$<BOOL:${EMSCRIPTEN}>>:third-party/glad/src/glad.c>)
set(TWN_SOURCE_FILES set(TWN_SOURCE_FILES
@ -135,10 +136,6 @@ target_precompile_headers(${TWN_TARGET} PRIVATE
third-party/stb/stb_ds.h) third-party/stb/stb_ds.h)
# distribution definitions, set them with -DX=X in cli # distribution definitions, set them with -DX=X in cli
set(ORGANIZATION_NAME "wanp" CACHE STRING
"App developer/publisher's identifier")
set(APP_NAME "townengine" CACHE STRING
"App identifier")
set(PACKAGE_EXTENSION "btw" CACHE STRING set(PACKAGE_EXTENSION "btw" CACHE STRING
"File extension used to look for data archives") "File extension used to look for data archives")
@ -226,6 +223,7 @@ function(include_deps target)
third-party/libxm/include third-party/libxm/include
third-party/stb third-party/stb
third-party/x-watcher third-party/x-watcher
third-party/tomlc99
$<$<NOT:$<BOOL:${EMSCRIPTEN}>>:third-party/glad/include>) $<$<NOT:$<BOOL:${EMSCRIPTEN}>>:third-party/glad/include>)
list(TRANSFORM THIRD_PARTY_INCLUDES PREPEND ${TWN_ROOT_DIR}/) list(TRANSFORM THIRD_PARTY_INCLUDES PREPEND ${TWN_ROOT_DIR}/)

View File

@ -18,7 +18,7 @@ static void title_tick(State *state) {
m_sprite("/assets/title.png", ((Rect) { m_sprite("/assets/title.png", ((Rect) {
((float)RENDER_BASE_WIDTH / 2) - ((float)320 / 2), 64, 320, 128 })); ((float)ctx.base_draw_w / 2) - ((float)320 / 2), 64, 320, 128 }));
/* draw the tick count as an example of dynamic text */ /* draw the tick count as an example of dynamic text */

View File

@ -16,7 +16,7 @@ static void title_tick(State *state) {
m_sprite("/assets/title.png", ((Rect) { m_sprite("/assets/title.png", ((Rect) {
((float)RENDER_BASE_WIDTH / 2) - ((float)320 / 2), 64, 320, 128 })); ((float)ctx.base_draw_w / 2) - ((float)320 / 2), 64, 320, 128 }));
/* draw the tick count as an example of dynamic text */ /* draw the tick count as an example of dynamic text */

27
data/twn.toml Normal file
View File

@ -0,0 +1,27 @@
# This file contains everything about the engine and your game that can be
# configured before it runs.
#
# Optional settings are commented out, with their default values shown.
# Invalid values in these settings will be ignored.
# Data about your game as an application
[about]
title = "It's TownEngine!"
developer = "Somebody"
app_id = "townengine"
dev_id = "somebody"
# Game runtime details
[game]
base_render_width = 640
base_render_height = 360
#debug = true
# Engine tweaks. You probably don't need to change these
[engine]
#ticks_per_second = 60 # minimum of 8
#keybind_slots = 3 # minimum of 1
#texture_atlas_size = 2048 # minimum of 32
#font_texture_size = 2048 # minimum of 1024
#font_oversampling = 4 # minimum of 0
#font_filtering = "linear" # possible values: "nearest", "linear"

View File

@ -1,35 +1,25 @@
#ifndef TWN_CONFIG_H #ifndef TWN_CONFIG_H
#define TWN_CONFIG_H #define TWN_CONFIG_H
/* /* TODO: consider if it's still necessary to keep these in one place */
* this file is for configuration values which are to be set at
* compile time. generally speaking, it's for things that would be unwise to
* change mid-development without considering the work it might take to
* adapt the game logic.
*
* if you're looking for distribution-related definitions like
* APP_NAME, you should know that they are set from CMake.
*/
#define TICKS_PER_SECOND 60 #define TICKS_PER_SECOND_DEFAULT 60
#define FIXED_DELTA_TIME (1.0 / TICKS_PER_SECOND)
#define RENDER_BASE_WIDTH 640 #define BASE_RENDER_WIDTH_DEFAULT 640
#define RENDER_BASE_HEIGHT 360 #define BASE_RENDER_HEIGHT_DEFAULT 360
#define RENDER_BASE_RATIO ((float)RENDER_BASE_WIDTH / (float)RENDER_BASE_HEIGHT)
#define TEXTURE_ATLAS_SIZE 2048 #define TEXTURE_ATLAS_SIZE_DEFAULT 2048
#define TEXTURE_ATLAS_BIT_DEPTH 32 #define TEXTURE_ATLAS_BIT_DEPTH 32
#define TEXTURE_ATLAS_FORMAT SDL_PIXELFORMAT_RGBA32 #define TEXTURE_ATLAS_FORMAT SDL_PIXELFORMAT_RGBA32
#define NUM_KEYBIND_SLOTS 8 #define KEYBIND_SLOTS_DEFAULT 3
#define AUDIO_FREQUENCY 48000 #define AUDIO_FREQUENCY 48000
#define AUDIO_N_CHANNELS 2 #define AUDIO_N_CHANNELS 2
#define TEXT_FONT_TEXTURE_SIZE 1024 #define TEXT_FONT_TEXTURE_SIZE_DEFAULT 2048
#define TEXT_FONT_OVERSAMPLING 4 #define TEXT_FONT_OVERSAMPLING_DEFAULT 4
#define TEXT_FONT_FILTERING TEXTURE_FILTER_LINEAR #define TEXT_FONT_FILTERING_DEFAULT TEXTURE_FILTER_LINEAR
#endif #endif

View File

@ -9,7 +9,7 @@
typedef struct Context { typedef struct Context {
struct InputState input; InputState input;
int64_t delta_time; /* preserves real time frame delta with no manipilation */ int64_t delta_time; /* preserves real time frame delta with no manipilation */
uint64_t tick_count; uint64_t tick_count;
@ -17,12 +17,14 @@ typedef struct Context {
/* set just once on startup */ /* set just once on startup */
uint64_t random_seed; uint64_t random_seed;
/* this should be a multiple of TICKS_PER_SECOND */ /* this should be a multiple of the current ticks per second */
/* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */ /* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */
/* it can be changed at runtime; any resulting logic anomalies are bugs */ /* it can be changed at runtime; any resulting logic anomalies are bugs */
unsigned int update_multiplicity; unsigned int update_multiplicity;
int window_w; int window_w;
int window_h; int window_h;
int base_draw_w;
int base_draw_h;
/* you may read from and write to these from game code */ /* you may read from and write to these from game code */
void *udata; void *udata;

View File

@ -41,9 +41,9 @@ typedef struct Button {
typedef struct Action { typedef struct Action {
size_t num_bindings; size_t num_bindings;
/* if you bind more than NUM_KEYBIND_SLOTS (set in config.h) */ /* if you bind more than the number set in the configuration file */
/* it forgets the first Button to add the new one at the end */ /* it forgets the first Button to add the new one at the end */
Button bindings[NUM_KEYBIND_SLOTS]; Button *bindings;
Vec2 position; /* set if applicable, e.g. mouse click */ Vec2 position; /* set if applicable, e.g. mouse click */
bool is_pressed; bool is_pressed;

View File

@ -104,7 +104,7 @@ void use_2d_pipeline(void) {
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); 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); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();

View File

@ -106,9 +106,9 @@ void render(void) {
/* fit rendering context onto the resizable screen */ /* fit rendering context onto the resizable screen */
if (ctx.game.window_size_has_changed) { if (ctx.game.window_size_has_changed) {
if ((float)ctx.game.window_w / (float)ctx.game.window_h > RENDER_BASE_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)RENDER_BASE_HEIGHT; float ratio = (float)ctx.game.window_h / (float)ctx.base_render_height;
int w = (int)((float)RENDER_BASE_WIDTH * ratio); int w = (int)((float)ctx.base_render_width * ratio);
setup_viewport( setup_viewport(
ctx.game.window_w / 2 - w / 2, ctx.game.window_w / 2 - w / 2,
0, 0,
@ -116,8 +116,8 @@ void render(void) {
ctx.game.window_h ctx.game.window_h
); );
} else { } else {
float ratio = (float)ctx.game.window_w / (float)RENDER_BASE_WIDTH; float ratio = (float)ctx.game.window_w / (float)ctx.base_render_width;
int h = (int)((float)RENDER_BASE_HEIGHT * ratio); int h = (int)((float)ctx.base_render_height * ratio);
setup_viewport( setup_viewport(
0, 0,
ctx.game.window_h / 2 - h / 2, ctx.game.window_h / 2 - h / 2,

View File

@ -99,7 +99,7 @@ static FontData *text_load_font_data(const char *path, int height_px) {
font_data->file_path = path; font_data->file_path = path;
font_data->height_px = height_px; 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; 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); font_data->line_gap = (int)((float)font_data->line_gap * font_data->scale_factor);
stbtt_pack_context pctx; stbtt_pack_context pctx;
stbtt_PackBegin(&pctx, bitmap, TEXT_FONT_TEXTURE_SIZE, TEXT_FONT_TEXTURE_SIZE, 0, 1, NULL); stbtt_PackBegin(&pctx, bitmap, (int)ctx.font_texture_size, (int)ctx.font_texture_size, 0, 1, NULL);
stbtt_PackSetOversampling(&pctx, TEXT_FONT_OVERSAMPLING, TEXT_FONT_OVERSAMPLING); 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_PackFontRange(&pctx, buf, 0, (float)height_px, ASCII_START, NUM_DISPLAY_ASCII, font_data->char_data);
stbtt_PackEnd(&pctx); 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( upload_gpu_texture(
font_data->texture, font_data->texture,
bitmap, bitmap,
1, 1,
TEXT_FONT_TEXTURE_SIZE, (int)ctx.font_texture_size,
TEXT_FONT_TEXTURE_SIZE (int)ctx.font_texture_size
); );
SDL_free(bitmap); 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_aligned_quad quad;
stbtt_GetPackedQuad( stbtt_GetPackedQuad(
font_data->char_data, font_data->char_data,
TEXT_FONT_TEXTURE_SIZE, (int)ctx.font_texture_size,
TEXT_FONT_TEXTURE_SIZE, (int)ctx.font_texture_size,
c - ASCII_START, c - ASCII_START,
&position.x, &position.x,
&position.y, &position.y,

View File

@ -1,5 +1,6 @@
#include "twn_camera.h" #include "twn_camera.h"
#include "twn_config.h" #include "twn_config.h"
#include "twn_engine_context_c.h"
#include <math.h> #include <math.h>
@ -37,7 +38,7 @@ Matrix4 camera_perspective(const Camera *const camera) {
/* from cglm */ /* from cglm */
Matrix4 result = {0}; 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 f = 1.0f / tanf(camera->fov * 0.5f);
const float fn = 1.0f / (CAMERA_NEAR_Z - CAMERA_FAR_Z); const float fn = 1.0f / (CAMERA_NEAR_Z - CAMERA_FAR_Z);

View File

@ -8,6 +8,7 @@
#include "rendering/twn_rendering_c.h" #include "rendering/twn_rendering_c.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <toml.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -21,11 +22,24 @@ typedef struct EngineContext {
int argc; int argc;
char **argv; 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; MeshBatchItem *uncolored_mesh_batches;
struct TextCache text_cache; TextCache text_cache;
TextureCache texture_cache; TextureCache texture_cache;
/* audio */
AudioChannelItem *audio_channels; AudioChannelItem *audio_channels;
SDL_AudioDeviceID audio_device; SDL_AudioDeviceID audio_device;
int audio_stream_frequency; int audio_stream_frequency;

View File

@ -1,5 +1,6 @@
#include "twn_input_c.h" #include "twn_input_c.h"
#include "twn_util.h" #include "twn_util.h"
#include "twn_engine_context_c.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <stb_ds.h> #include <stb_ds.h>
@ -9,7 +10,7 @@
static void update_action_pressed_state(InputState *input, Action *action) { 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) { switch (action->bindings[i].source) {
case BUTTON_SOURCE_NOT_SET: case BUTTON_SOURCE_NOT_SET:
break; break;
@ -74,7 +75,7 @@ static void input_bind_code_to_action(InputState *input,
Action *action = &action_item->value; Action *action = &action_item->value;
/* check every binding to make sure this code isn't already bound */ /* 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]; Button *binding = &action->bindings[i];
if (binding->source != source) 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 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; --action->num_bindings;
size_t shifted_size = (sizeof action->bindings) - (sizeof action->bindings[0]); size_t shifted_size = (sizeof action->bindings) - (sizeof action->bindings[0]);
SDL_memmove(action->bindings, action->bindings + 1, shifted_size); 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 */ /* check every binding to make sure this code is bound */
size_t index = 0; size_t index = 0;
bool is_bound = false; 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]; Button *binding = &action->bindings[index];
if (binding->source != source) if (binding->source != source)
@ -249,13 +250,21 @@ void input_add_action(InputState *input, char *action_name) {
return; 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) { 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); 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) { 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); stbds_shfree(input->action_hash);
} }

View File

@ -9,6 +9,7 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <physfs.h> #include <physfs.h>
#include <stb_ds.h> #include <stb_ds.h>
#include <toml.h>
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
@ -193,14 +194,78 @@ static bool initialize(void) {
return false; return false;
} }
/* debug mode defaults to being enabled on debug builds. */ /* first things first, most things here will be loaded from the config file */
/* pass --debug to enable it on release builds */ /* it's expected to be present in the data directory, no matter what */
/* or, on debug builds, pass --release to disable it */ /* that is why PhysicsFS is initialized before anything else */
#ifndef NDEBUG 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; ctx.game.debug = true;
#else } else {
ctx.game.debug = false; ctx.game.debug = datum_debug.u.b;
#endif }
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
/* emscripten interpretes those as GL ES version against WebGL */ /* 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); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
/* init got far enough to create a window */ /* init got far enough to create a window */
ctx.window = SDL_CreateWindow("townengine", {
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,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
RENDER_BASE_WIDTH, (int)datum_base_render_width.u.i,
RENDER_BASE_HEIGHT, (int)datum_base_render_height.u.i,
//SDL_WINDOW_ALLOW_HIGHDPI | //SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_RESIZABLE | SDL_WINDOW_RESIZABLE |
SDL_WINDOW_OPENGL); SDL_WINDOW_OPENGL);
SDL_free(datum_title.u.s);
//SDL_free(datum_developer.u.s);
}
if (ctx.window == NULL) { if (ctx.window == NULL) {
CRY_SDL("Window creation failed."); CRY_SDL("Window creation failed.");
goto fail; goto fail;
@ -270,12 +369,12 @@ static bool initialize(void) {
/* might need this to have multiple windows */ /* might need this to have multiple windows */
ctx.window_id = SDL_GetWindowID(ctx.window); 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: */ /* TODO: */
// SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h); // SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h);
ctx.game.window_w = RENDER_BASE_WIDTH; ctx.game.window_w = (int)ctx.base_render_width;
ctx.game.window_h = RENDER_BASE_HEIGHT; ctx.game.window_h = (int)ctx.base_render_height;
/* audio initialization */ /* 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 */ /* you could change this at runtime if you wanted */
ctx.game.update_multiplicity = 1; ctx.game.update_multiplicity = 1;
@ -325,11 +415,22 @@ static bool initialize(void) {
stbds_rand_seed(ctx.game.random_seed); stbds_rand_seed(ctx.game.random_seed);
/* main loop machinery */ /* 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.game.is_running = true;
ctx.resync_flag = true; ctx.resync_flag = true;
ctx.clocks_per_second = SDL_GetPerformanceFrequency(); ctx.clocks_per_second = SDL_GetPerformanceFrequency();
ctx.prev_frame_time = SDL_GetPerformanceCounter(); 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.frame_accumulator = 0;
ctx.game.tick_count = 0; ctx.game.tick_count = 0;
@ -340,6 +441,56 @@ static bool initialize(void) {
} }
/* rendering */ /* 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 */ /* these are dynamic arrays and will be allocated lazily by stb_ds */
ctx.render_queue_2d = NULL; ctx.render_queue_2d = NULL;
ctx.uncolored_mesh_batches = NULL; ctx.uncolored_mesh_batches = NULL;
@ -348,6 +499,16 @@ static bool initialize(void) {
text_cache_init(&ctx.text_cache); text_cache_init(&ctx.text_cache);
/* input */ /* 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); input_state_init(&ctx.game.input);
/* scripting */ /* scripting */
@ -377,6 +538,7 @@ static void clean_up(void) {
arrfree(ctx.render_queue_2d); arrfree(ctx.render_queue_2d);
toml_free(ctx.config_table);
PHYSFS_deinit(); PHYSFS_deinit();
SDL_Quit(); SDL_Quit();
} }
@ -392,11 +554,35 @@ int enter_loop(int argc, char **argv) {
ctx.argc = argc; ctx.argc = argc;
ctx.argv = argv; ctx.argv = argv;
/* needs to be done before anything else so config can be loaded */
if (!initialize()) /* 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; 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 */ /* process arguments */
bool force_debug = false;
bool force_release = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
/* override data directory */ /* override data directory */
if (SDL_strcmp(argv[i], "--data-dir") == 0) { if (SDL_strcmp(argv[i], "--data-dir") == 0) {
@ -415,17 +601,29 @@ int enter_loop(int argc, char **argv) {
/* force debug mode */ /* force debug mode */
if (SDL_strcmp(argv[i], "--debug") == 0) { if (SDL_strcmp(argv[i], "--debug") == 0) {
ctx.game.debug = true; force_debug = true;
continue; continue;
} }
/* force release mode */ /* force release mode */
if (SDL_strcmp(argv[i], "--release") == 0) { if (SDL_strcmp(argv[i], "--release") == 0) {
ctx.game.debug = false; force_release = false;
continue; 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(); game_object_load();
ctx.was_successful = true; ctx.was_successful = true;
@ -440,6 +638,7 @@ int enter_loop(int argc, char **argv) {
main_loop(); main_loop();
} }
/* loop is over */
game_object_unload(); game_object_unload();
clean_up(); clean_up();

View File

@ -132,7 +132,7 @@ static SDL_Surface *create_surface(int width, int height) {
/* adds a new, blank atlas surface to the cache */ /* adds a new, blank atlas surface to the cache */
static void add_new_atlas(TextureCache *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_surfaces, new_atlas);
arrput(cache->atlas_textures, create_gpu_texture(TEXTURE_FILTER_NEAREAST, true)); 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; cache->window = window;
sh_new_arena(cache->hash); 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); add_new_atlas(cache);
recreate_current_atlas_texture(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 */ /* 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 (ctx.game.debug) {
if (surface->w > 2048 || surface->h > 2048) if (surface->w > 2048 || surface->h > 2048)
log_warn("Unportable texture dimensions for %s, use 2048x2048 at max", path); 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 */ /* this function makes a lot more sense if you read stb_rect_pack.h */
stbrp_context pack_ctx; /* target info */ stbrp_context pack_ctx; /* target info */
stbrp_init_target(&pack_ctx, stbrp_init_target(&pack_ctx,
TEXTURE_ATLAS_SIZE, ctx.texture_atlas_size,
TEXTURE_ATLAS_SIZE, ctx.texture_atlas_size,
cache->node_buffer, cache->node_buffer,
TEXTURE_ATLAS_SIZE); ctx.texture_atlas_size);
stbrp_rect *rects = create_rects_from_cache(cache); 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) if (cache->hash[key.id].value.loner_texture != 0)
return cache->hash[key.id].value.srcrect; return cache->hash[key.id].value.srcrect;
else else
return (Rect){ .w = TEXTURE_ATLAS_SIZE, .h = TEXTURE_ATLAS_SIZE }; return (Rect){ .w = ctx.texture_atlas_size, .h = ctx.texture_atlas_size };
} else { } else {
CRY("Texture lookup failed.", CRY("Texture lookup failed.",
"Tried to get texture that isn't loaded."); "Tried to get texture that isn't loaded.");

14
third-party/tomlc99/.editorconfig vendored Normal file
View File

@ -0,0 +1,14 @@
root = true
[*]
end_of_line = lf
insert_final_newline = false
trim_trailing_whitespace = true
[*.{c,h}]
indent_style = space
indent_size = 2
[Makefile]
indent_style = tab
indent_size = 4

38
third-party/tomlc99/.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
*~
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
toml_cat
toml_json
toml_sample
# Debug files
*.dSYM/
*.su

53
third-party/tomlc99/Makefile vendored Normal file
View File

@ -0,0 +1,53 @@
prefix ?= /usr/local
HFILES = toml.h
CFILES = toml.c
OBJ = $(CFILES:.c=.o)
EXEC = toml_json toml_cat toml_sample
PCFILE = libtoml.pc
CFLAGS = -std=c99 -Wall -Wextra -fpic
LIB_VERSION = 1.0
LIB = libtoml.a
LIB_SHARED = libtoml.so.$(LIB_VERSION)
# to compile for debug: make DEBUG=1
# to compile for no debug: make
ifdef DEBUG
CFLAGS += -O0 -g
else
CFLAGS += -O2 -DNDEBUG
endif
all: $(LIB) $(LIB_SHARED) $(EXEC)
*.o: $(HFILES)
libtoml.a: toml.o
ar -rcs $@ $^
libtoml.so.$(LIB_VERSION): toml.o
$(CC) -shared -o $@ $^
$(EXEC): $(LIB)
install: all
install -d ${prefix}/include ${prefix}/lib
install toml.h ${prefix}/include
install $(LIB) ${prefix}/lib
install $(LIB_SHARED) ${prefix}/lib
ifeq "$(prefix)" "/usr/local"
ifneq ("$(wildcard $(PCFILE))","")
install $(PCFILE) /usr/local/lib/pkgconfig
endif
endif
clean:
rm -f *.o $(EXEC) $(LIB) $(LIB_SHARED)
format:
clang-format -i $(shell find . -name '*.[ch]')
.PHONY: all clean install format

194
third-party/tomlc99/README.md vendored Normal file
View File

@ -0,0 +1,194 @@
# tomlc99
TOML in c99; v1.0 compliant.
If you are looking for a C++ library, you might try this wrapper: [https://github.com/cktan/tomlcpp](https://github.com/cktan/tomlcpp).
* Compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0).
* Tested with multiple test suites, including
[toml-lang/toml-test](https://github.com/toml-lang/toml-test) and
[iarna/toml-spec-tests](https://github.com/iarna/toml-spec-tests).
* Provides very simple and intuitive interface.
## Usage
Please see the `toml.h` file for details. The following is a simple example that
parses this config file:
```toml
[server]
host = "www.example.com"
port = [ 8080, 8181, 8282 ]
```
These are the usual steps for getting values from a file:
1. Parse the TOML file.
2. Traverse and locate a table in TOML.
3. Extract values from the table.
4. Free up allocated memory.
Below is an example of parsing the values from the example table.
```c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "toml.h"
static void error(const char* msg, const char* msg1)
{
fprintf(stderr, "ERROR: %s%s\n", msg, msg1?msg1:"");
exit(1);
}
int main()
{
FILE* fp;
char errbuf[200];
// 1. Read and parse toml file
fp = fopen("sample.toml", "r");
if (!fp) {
error("cannot open sample.toml - ", strerror(errno));
}
toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
fclose(fp);
if (!conf) {
error("cannot parse - ", errbuf);
}
// 2. Traverse to a table.
toml_table_t* server = toml_table_in(conf, "server");
if (!server) {
error("missing [server]", "");
}
// 3. Extract values
toml_datum_t host = toml_string_in(server, "host");
if (!host.ok) {
error("cannot read server.host", "");
}
toml_array_t* portarray = toml_array_in(server, "port");
if (!portarray) {
error("cannot read server.port", "");
}
printf("host: %s\n", host.u.s);
printf("port: ");
for (int i = 0; ; i++) {
toml_datum_t port = toml_int_at(portarray, i);
if (!port.ok) break;
printf("%d ", (int)port.u.i);
}
printf("\n");
// 4. Free memory
free(host.u.s);
toml_free(conf);
return 0;
}
```
#### Accessing Table Content
TOML tables are dictionaries where lookups are done using string keys. In
general, all access functions on tables are named `toml_*_in(...)`.
In the normal case, you know the key and its content type, and retrievals can be done
using one of these functions:
```c
toml_string_in(tab, key);
toml_bool_in(tab, key);
toml_int_in(tab, key);
toml_double_in(tab, key);
toml_timestamp_in(tab, key);
toml_table_in(tab, key);
toml_array_in(tab, key);
```
You can also interrogate the keys in a table using an integer index:
```c
toml_table_t* tab = toml_parse_file(...);
for (int i = 0; ; i++) {
const char* key = toml_key_in(tab, i);
if (!key) break;
printf("key %d: %s\n", i, key);
}
```
#### Accessing Array Content
TOML arrays can be deref-ed using integer indices. In general, all access methods on arrays are named `toml_*_at()`.
To obtain the size of an array:
```c
int size = toml_array_nelem(arr);
```
To obtain the content of an array, use a valid index and call one of these functions:
```c
toml_string_at(arr, idx);
toml_bool_at(arr, idx);
toml_int_at(arr, idx);
toml_double_at(arr, idx);
toml_timestamp_at(arr, idx);
toml_table_at(arr, idx);
toml_array_at(arr, idx);
```
#### toml_datum_t
Some `toml_*_at` and `toml_*_in` functions return a toml_datum_t
structure. The `ok` flag in the structure indicates if the function
call was successful. If so, you may proceed to read the value
corresponding to the type of the content.
For example:
```
toml_datum_t host = toml_string_in(tab, "host");
if (host.ok) {
printf("host: %s\n", host.u.s);
free(host.u.s); /* FREE applies to string and timestamp types only */
}
```
** IMPORTANT: if the accessed value is a string or a timestamp, you must call `free(datum.u.s)` or `free(datum.u.ts)` respectively after usage. **
## Building and installing
A normal *make* suffices. You can also simply include the
`toml.c` and `toml.h` files in your project.
Invoking `make install` will install the header and library files into
/usr/local/{include,lib}.
Alternatively, specify `make install prefix=/a/file/path` to install into
/a/file/path/{include,lib}.
## Testing
To test against the standard test set provided by toml-lang/toml-test:
```sh
% make
% cd test1
% bash build.sh # do this once
% bash run.sh # this will run the test suite
```
To test against the standard test set provided by iarna/toml:
```sh
% make
% cd test2
% bash build.sh # do this once
% bash run.sh # this will run the test suite
```

11
third-party/tomlc99/libtoml.pc.sample vendored Normal file
View File

@ -0,0 +1,11 @@
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: libtoml
URL: https://github.com/cktan/tomlc99/
Description: TOML C library in c99.
Version: v1.0
Libs: -L${libdir} -ltoml
Cflags: -I${includedir}

3
third-party/tomlc99/sample.toml vendored Normal file
View File

@ -0,0 +1,3 @@
[server]
host = "example.com"
port = [ 8080, 8181, 8282 ]

1
third-party/tomlc99/stdex/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/*.out

15
third-party/tomlc99/stdex/RUN.sh vendored Normal file
View File

@ -0,0 +1,15 @@
rm -f *.out
for i in *.toml; do
echo -n $i
../toml_cat $i >& $i.out
if [ -f $i.res ]; then
if $(diff $i.out $i.res >& /dev/null); then
echo " [OK]"
else
echo " [FAILED]"
fi
else
echo " [?????]"
fi
done

13
third-party/tomlc99/stdex/arr1.toml vendored Normal file
View File

@ -0,0 +1,13 @@
integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
string_array = [ "all", 'strings', """are the same""", '''type''' ]
# Mixed-type arrays are allowed
numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
]

56
third-party/tomlc99/stdex/arr1.toml.res vendored Normal file
View File

@ -0,0 +1,56 @@
{
integers = [
1,
2,
3,
],
colors = [
"red",
"yellow",
"green",
],
nested_arrays_of_ints = [
[
1,
2,
],
[
3,
4,
5,
],
],
nested_mixed_array = [
[
1,
2,
],
[
"a",
"b",
"c",
],
],
string_array = [
"all",
"strings",
"are the same",
"type",
],
numbers = [
0.100000,
0.200000,
0.500000,
1,
2,
5,
],
contributors = [
"Foo Bar <foo@example.com>",
{
name = "Baz Qux",
email = "bazqux@example.com",
url = "https://example.com/bazqux",
},
],
}

8
third-party/tomlc99/stdex/arr2.toml vendored Normal file
View File

@ -0,0 +1,8 @@
integers2 = [
1, 2, 3
]
integers3 = [
1,
2, # this is ok
]

11
third-party/tomlc99/stdex/arr2.toml.res vendored Normal file
View File

@ -0,0 +1,11 @@
{
integers2 = [
1,
2,
3,
],
integers3 = [
1,
2,
],
}

11
third-party/tomlc99/stdex/arrtab1.toml vendored Normal file
View File

@ -0,0 +1,11 @@
[[products]]
name = "Hammer"
sku = 738594937
[[products]] # empty table within the array
[[products]]
name = "Nail"
sku = 284758393
color = "gray"

View File

@ -0,0 +1,15 @@
{
products = [
{
name = "Hammer",
sku = 738594937,
},
{
},
{
name = "Nail",
sku = 284758393,
color = "gray",
},
],
}

19
third-party/tomlc99/stdex/arrtab2.toml vendored Normal file
View File

@ -0,0 +1,19 @@
[[fruits]]
name = "apple"
[fruits.physical] # subtable
color = "red"
shape = "round"
[[fruits.varieties]] # nested array of tables
name = "red delicious"
[[fruits.varieties]]
name = "granny smith"
[[fruits]]
name = "banana"
[[fruits.varieties]]
name = "plantain"

View File

@ -0,0 +1,27 @@
{
fruits = [
{
name = "apple",
varieties = [
{
name = "red delicious",
},
{
name = "granny smith",
},
],
physical = {
color = "red",
shape = "round",
},
},
{
name = "banana",
varieties = [
{
name = "plantain",
},
],
},
],
}

View File

@ -0,0 +1,8 @@
# INVALID TOML DOC
[fruit.physical] # subtable, but to which parent element should it belong?
color = "red"
shape = "round"
[[fruit]] # parser must throw an error upon discovering that "fruit" is
# an array rather than a table
name = "apple"

View File

@ -0,0 +1 @@
ERROR: line 6: key exists

View File

@ -0,0 +1,4 @@
# INVALID TOML DOC
fruits = []
[[fruits]] # Not allowed

View File

@ -0,0 +1 @@
ERROR: line 4: array mismatch

11
third-party/tomlc99/stdex/arrtab5.toml vendored Normal file
View File

@ -0,0 +1,11 @@
# INVALID TOML DOC
[[fruits]]
name = "apple"
[[fruits.varieties]]
name = "red delicious"
# INVALID: This table conflicts with the previous array of tables
[fruits.varieties]
name = "granny smith"

View File

@ -0,0 +1 @@
ERROR: line 9: key exists

14
third-party/tomlc99/stdex/arrtab6.toml vendored Normal file
View File

@ -0,0 +1,14 @@
# INVALID TOML DOC
[[fruits]]
name = "apple"
[[fruits.varieties]]
name = "red delicious"
[fruits.physical]
color = "red"
shape = "round"
# INVALID: This array of tables conflicts with the previous table
[[fruits.physical]]
color = "green"

View File

@ -0,0 +1 @@
ERROR: line 13: key exists

View File

@ -0,0 +1,3 @@
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]

View File

@ -0,0 +1,19 @@
{
points = [
{
x = 1,
y = 2,
z = 3,
},
{
x = 7,
y = 8,
z = 9,
},
{
x = 2,
y = 4,
z = 8,
},
],
}

3
third-party/tomlc99/stdex/bool1.toml vendored Normal file
View File

@ -0,0 +1,3 @@
bool1 = true
bool2 = false

View File

@ -0,0 +1,4 @@
{
bool1 = true,
bool2 = false,
}

View File

@ -0,0 +1,3 @@
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment"

View File

@ -0,0 +1,4 @@
{
key = "value",
another = "# This is not a comment",
}

13
third-party/tomlc99/stdex/float1.toml vendored Normal file
View File

@ -0,0 +1,13 @@
# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
# exponent
flt4 = 5e+22
flt5 = 1e06
flt6 = -2E-2
# both
flt7 = 6.626e-34

View File

@ -0,0 +1,9 @@
{
flt1 = 1.000000,
flt2 = 3.141500,
flt3 = -0.010000,
flt4 = 49999999999999995805696.000000,
flt5 = 1000000.000000,
flt6 = -0.020000,
flt7 = 0.000000,
}

1
third-party/tomlc99/stdex/float2.toml vendored Normal file
View File

@ -0,0 +1 @@
invalid_float_1 = .7

View File

@ -0,0 +1,2 @@
{
ERROR: unable to decode value in table

2
third-party/tomlc99/stdex/float3.toml vendored Normal file
View File

@ -0,0 +1,2 @@
invalid_float_2 = 7.

View File

@ -0,0 +1,2 @@
{
ERROR: unable to decode value in table

1
third-party/tomlc99/stdex/float4.toml vendored Normal file
View File

@ -0,0 +1 @@
invalid_float_3 = 3.e+20

View File

@ -0,0 +1,2 @@
{
ERROR: unable to decode value in table

1
third-party/tomlc99/stdex/float5.toml vendored Normal file
View File

@ -0,0 +1 @@
flt8 = 224_617.445_991_228

View File

@ -0,0 +1,3 @@
{
flt8 = 224617.445991,
}

10
third-party/tomlc99/stdex/float6.toml vendored Normal file
View File

@ -0,0 +1,10 @@
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific

View File

@ -0,0 +1,8 @@
{
sf1 = inf,
sf2 = inf,
sf3 = -inf,
sf4 = nan,
sf5 = nan,
sf6 = nan,
}

View File

@ -0,0 +1,3 @@
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }

View File

@ -0,0 +1,15 @@
{
name = {
first = "Tom",
last = "Preston-Werner",
},
point = {
x = 1,
y = 2,
},
animal = {
type = {
name = "pug",
},
},
}

View File

@ -0,0 +1,3 @@
[product]
type = { name = "Nail" }
type.edible = false # INVALID

View File

@ -0,0 +1 @@
ERROR: line 3: cannot insert new entry into existing table

View File

@ -0,0 +1,3 @@
[product]
type.name = "Nail"
type = { edible = false } # INVALID

View File

@ -0,0 +1 @@
ERROR: line 3: key exists

9
third-party/tomlc99/stdex/int0.toml vendored Normal file
View File

@ -0,0 +1,9 @@
int1 = +99
int2 = 42
int3 = 0
int4 = -17
int5 = 1_000
int6 = 5_349_221
int7 = 53_49_221 # Indian number system grouping
int8 = 1_2_3_4_5 # VALID but discouraged

10
third-party/tomlc99/stdex/int0.toml.res vendored Normal file
View File

@ -0,0 +1,10 @@
{
int1 = 99,
int2 = 42,
int3 = 0,
int4 = -17,
int5 = 1000,
int6 = 5349221,
int7 = 5349221,
int8 = 12345,
}

12
third-party/tomlc99/stdex/int1.toml vendored Normal file
View File

@ -0,0 +1,12 @@
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110

View File

@ -0,0 +1,8 @@
{
hex1 = 3735928559,
hex2 = 3735928559,
hex3 = 3735928559,
oct1 = 342391,
oct2 = 493,
bin1 = 214,
}

4
third-party/tomlc99/stdex/keys00.toml vendored Normal file
View File

@ -0,0 +1,4 @@
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"

View File

@ -0,0 +1,6 @@
{
key = "value",
bare_key = "value",
bare-key = "value",
1234 = "value",
}

5
third-party/tomlc99/stdex/keys01.toml vendored Normal file
View File

@ -0,0 +1,5 @@
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"

View File

@ -0,0 +1,7 @@
{
127.0.0.1 = "value",
character encoding = "value",
ʎǝʞ = "value",
key2 = "value",
quoted "value" = "value",
}

1
third-party/tomlc99/stdex/keys02.toml vendored Normal file
View File

@ -0,0 +1 @@
= "no key name" # INVALID

View File

@ -0,0 +1 @@
ERROR: line 1: syntax error

1
third-party/tomlc99/stdex/keys03.toml vendored Normal file
View File

@ -0,0 +1 @@
"" = "blank" # VALID but discouraged

View File

@ -0,0 +1,3 @@
{
= "blank",
}

4
third-party/tomlc99/stdex/keys04.toml vendored Normal file
View File

@ -0,0 +1,4 @@
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true

View File

@ -0,0 +1,10 @@
{
name = "Orange",
physical = {
color = "orange",
shape = "round",
},
site = {
google.com = true,
},
}

3
third-party/tomlc99/stdex/keys05.toml vendored Normal file
View File

@ -0,0 +1,3 @@
fruit.name = "banana" # this is best practice
fruit. color = "yellow" # same as fruit.color
fruit . flavor = "banana" # same as fruit.flavor

View File

@ -0,0 +1,7 @@
{
fruit = {
name = "banana",
color = "yellow",
flavor = "banana",
},
}

3
third-party/tomlc99/stdex/keys06.toml vendored Normal file
View File

@ -0,0 +1,3 @@
# DO NOT DO THIS
name = "Tom"
name = "Pradyun"

View File

@ -0,0 +1 @@
ERROR: line 3: key exists

3
third-party/tomlc99/stdex/keys07.toml vendored Normal file
View File

@ -0,0 +1,3 @@
# THIS WILL NOT WORK
spelling = "favorite"
"spelling" = "favourite"

View File

@ -0,0 +1 @@
ERROR: line 3: key exists

5
third-party/tomlc99/stdex/keys08.toml vendored Normal file
View File

@ -0,0 +1,5 @@
# This makes the key "fruit" into a table.
fruit.apple.smooth = true
# So then you can add to the table "fruit" like so:
fruit.orange = 2

View File

@ -0,0 +1,8 @@
{
fruit = {
orange = 2,
apple = {
smooth = true,
},
},
}

8
third-party/tomlc99/stdex/keys09.toml vendored Normal file
View File

@ -0,0 +1,8 @@
# THE FOLLOWING IS INVALID
# This defines the value of fruit.apple to be an integer.
fruit.apple = 1
# But then this treats fruit.apple like it's a table.
# You can't turn an integer into a table.
fruit.apple.smooth = true

View File

@ -0,0 +1 @@
ERROR: line 8: key exists

10
third-party/tomlc99/stdex/keys10.toml vendored Normal file
View File

@ -0,0 +1,10 @@
# VALID BUT DISCOURAGED
apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange"

View File

@ -0,0 +1,12 @@
{
apple = {
type = "fruit",
skin = "thin",
color = "red",
},
orange = {
type = "fruit",
skin = "thick",
color = "orange",
},
}

9
third-party/tomlc99/stdex/keys11.toml vendored Normal file
View File

@ -0,0 +1,9 @@
# RECOMMENDED
apple.type = "fruit"
apple.skin = "thin"
apple.color = "red"
orange.type = "fruit"
orange.skin = "thick"
orange.color = "orange"

View File

@ -0,0 +1,12 @@
{
apple = {
type = "fruit",
skin = "thin",
color = "red",
},
orange = {
type = "fruit",
skin = "thick",
color = "orange",
},
}

1
third-party/tomlc99/stdex/keys12.toml vendored Normal file
View File

@ -0,0 +1 @@
3.14159 = "pi"

View File

@ -0,0 +1,5 @@
{
3 = {
14159 = "pi",
},
}

View File

@ -0,0 +1 @@
key = "value"

View File

@ -0,0 +1,3 @@
{
key = "value",
}

View File

@ -0,0 +1 @@
key = # INVALID

View File

@ -0,0 +1 @@
ERROR: line 1: syntax error

View File

@ -0,0 +1 @@
first = "Tom" last = "Preston-Werner" # INVALID

View File

@ -0,0 +1 @@
ERROR: line 1: extra chars after value

View File

@ -0,0 +1 @@
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."

Some files were not shown because too many files have changed in this diff Show More