taisei/src/util/kvparser.c
Andrei Alexeyev 9b3779ebb4
Some renderer refactoring (mostly API and GLES preparations) (#144)
* Refacor uniforms API:

    - More complete and consistent
    - Type-safety
    - Usage correctess assertions missing for now, planned

* Redesign texturing API: texunits gone, assign textures to sampler uniforms directly

r_texture_create now allocates memory and returns an opaque Texture
pointer; similar changes to the other renderer APIs will follow.

* Framebuffers: make _create return an opaque pointer, add debug label APIs (unused for now)

* opaque pointers and debug label APIs for vertex arrays and buffers

* fix null renderer

* Refactor glsl preprocessing into an independent module

* Separate shader resource management from renderer backend

This makes it possible to add more shading languages and/or include a
transpiler, which will be useful for the GLES backend.

* refactor r_clear into a stateless API

* add r_texture_clear API; fix gl33_framebuffer_clear

* Replace deprecated glsl_objects with objects in all *.prog files

* fix missing texture_clear implementation in null renderer

* remove some dead code in null renderer

* fix GLES segfault

* GLES 3.0 actually has glVertexAttribDivisor

* Query GL for supported GLSL versions (preparing to add shader transcompilation)
2018-09-14 10:37:20 +03:00

191 lines
4 KiB
C

/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "taisei.h"
#include "kvparser.h"
#include "log.h"
#include "stringops.h"
#include "io.h"
#include "vfs/public.h"
bool parse_keyvalue_stream_cb(SDL_RWops *strm, KVCallback callback, void *data) {
static const char separator[] = "= ";
char buffer[256];
int lineno = 0;
int errors = 0;
loopstart: while(SDL_RWgets(strm, buffer, sizeof(buffer))) {
char *ptr = buffer;
char *sep, *key, *val;
++lineno;
while(isspace(*ptr)) {
if(!*(++ptr)) {
// blank line
goto loopstart;
}
}
if(*ptr == '#') {
// comment
continue;
}
sep = strstr(ptr, separator);
if(!sep) {
++errors;
log_warn("Syntax error on line %i: missing separator", lineno);
continue;
}
// split it up
*sep = 0;
key = ptr;
val = sep + sizeof(separator) - 1;
// the separator may be preceeded by any kind of whitespace, so strip it from the key
while(isspace(*(ptr = strchr(key, 0) - 1))) {
*ptr = 0;
}
// strip any kind of line endings from the value
while(strchr("\r\n", *(ptr = strchr(val, 0) - 1))) {
*ptr = 0;
}
if(!callback(key, val, data)) {
++errors;
continue;
}
}
return !errors;
}
bool parse_keyvalue_file_cb(const char *filename, KVCallback callback, void *data) {
SDL_RWops *strm = vfs_open(filename, VFS_MODE_READ);
if(!strm) {
log_warn("VFS error: %s", vfs_get_error());
return false;
}
bool status = parse_keyvalue_stream_cb(strm, callback, data);
SDL_RWclose(strm);
return status;
}
static bool kvcallback_hashtable(const char *key, const char *val, void *data) {
ht_str2ptr_t *ht = data;
ht_set(ht, key, strdup(val));
return true;
}
bool parse_keyvalue_stream(SDL_RWops *strm, ht_str2ptr_t *ht) {
return parse_keyvalue_stream_cb(strm, kvcallback_hashtable, ht);
}
bool parse_keyvalue_file(const char *filename, ht_str2ptr_t *ht) {
return parse_keyvalue_file_cb(filename, kvcallback_hashtable, ht);
}
static bool kvcallback_spec(const char *key, const char *val, void *data) {
KVSpec *spec = data;
for(KVSpec *s = spec; s->name; ++s) {
if(!strcmp(key, s->name)) {
if(s->out_str) {
stralloc(s->out_str, val);
}
if(s->out_int) {
*s->out_int = strtol(val, NULL, 0);
}
if(s->out_long) {
*s->out_long = strtol(val, NULL, 0);
}
if(s->out_float) {
*s->out_float = strtod(val, NULL);
}
if(s->out_double) {
*s->out_double = strtod(val, NULL);
}
if(s->out_bool) {
*s->out_bool = parse_bool(val, *s->out_bool);
}
if(s->callback) {
return s->callback(key, val, s->callback_data);
}
return true;
}
}
log_warn("Unknown key '%s' with value '%s' ignored", key, val);
return true;
}
bool parse_keyvalue_stream_with_spec(SDL_RWops *strm, KVSpec *spec) {
return parse_keyvalue_stream_cb(strm, kvcallback_spec, spec);
}
bool parse_keyvalue_file_with_spec(const char *filename, KVSpec *spec) {
return parse_keyvalue_file_cb(filename, kvcallback_spec, spec);
}
bool parse_bool(const char *str, bool fallback) {
while(isspace(*str)) {
++str;
}
char buf[strlen(str) + 1], *bufp = buf;
while(*str && !isspace(*str)) {
*bufp++ = *str++;
}
*bufp = 0;
double numeric_val = strtod(buf, &bufp);
if(*buf && !*bufp) {
return (bool)numeric_val;
}
static const char *true_vals[] = { "on", "yes", "true", NULL };
static const char *false_vals[] = { "off", "no", "false", NULL };
for(const char **v = true_vals; *v; ++v) {
if(!SDL_strcasecmp(buf, *v)) {
return true;
}
}
for(const char **v = false_vals; *v; ++v) {
if(!SDL_strcasecmp(buf, *v)) {
return false;
}
}
log_warn("Bad value `%s`, assuming %s", buf, fallback ? "true" : "false");
return fallback;
}
bool kvparser_deprecation(const char *key, const char *val, void *data) {
const char *alt = data;
log_warn("'%s' is deprecated, use '%s' instead", key, alt);
return true;
}