diff --git a/src/corelib/scene.c b/src/corelib/scene.c new file mode 100644 index 0000000..c2ce3e9 --- /dev/null +++ b/src/corelib/scene.c @@ -0,0 +1,160 @@ +#include "scene.h" + +#include "ctype.h" +#include "stdint.h" +#include "stddef.h" +#include "stdlib.h" +#include "string.h" +#include "stdio.h" +#include "hash.h" +#include "malloc.h" +#include "math.h" +#include "world.h" + +static +struct type_handler_t { + uintptr_t hash; + char* type; + type_handler_fn handler; +} _type_handlers[99]; + +static +int _type_handler_num = 0; + +static +struct type_handler_t* _find_handler_for(const char* type) { + uintptr_t hash = hashstr(type); + for(int i = 0; i < 99; ++i) { + if(_type_handlers[i].hash == hash && strcmp(type, _type_handlers[i].type) == 0) { + return _type_handlers + i; + } + } + return NULL; +} + +static +struct type_handler_t* _new_handler_for(const char* type) { + _type_handlers[_type_handler_num].type = malloc(strlen(type) * sizeof(char)); + strcpy(_type_handlers[_type_handler_num].type, type); + _type_handlers[_type_handler_num].hash = hashstr(type); + struct type_handler_t* ptr = _type_handlers + _type_handler_num; + ++_type_handler_num; + return ptr; +} + +void set_type_handler(const char* type, type_handler_fn handler) { + struct type_handler_t* ptr = _find_handler_for(type); + if(ptr == NULL) { + ptr = _new_handler_for(type); + } + ptr->handler = handler; +} + +static +int fpeekc(FILE* file) { + int c = fgetc(file); + ungetc(c, file); + return c; +} + +static +int nextnw(FILE* file) { + int next; + char c; + do { + next = fgetc(file); + c = (char)next; + } while(isspace(c)); + return next; +} + +static +void _parse_key(FILE* file, char* out) { + char c; + do { + c = fgetc(file); + if(c == ':') { + *out = '\0'; + } else if(!isspace(c)) { + *out = c; + ++out; + } + } while(c != ':'); +} + +static +void _parse_value(FILE* file, char* out, int* _argc, char** argv) { + char c; + int argc = 0; + argv[argc] = out; + ++argc; + do { + c = fgetc(file); + switch(c) { + case ';': + *out = '\0'; + break; + case ',': + *out = '\0'; + ++out; + argv[argc] = out; + ++argc; + ungetc(nextnw(file), file); + break; + default: + *out = c; + ++out; + break; + } + } while(c != ';'); + *_argc = argc; +} + +static +void _parse_config(FILE* file) { + char key[24]; + char value[128]; + int argc = 0; + char* argv[24]; + + char begin = nextnw(file); + ungetc(begin, file); + + _parse_key(file, key); + ungetc(nextnw(file), file); + _parse_value(file, value, &argc, argv); + + struct type_handler_t* handler = _find_handler_for(key); + + if(handler != NULL) { + printf("found handler\n"); + if(begin == '!') { + handler->handler(NULL, argc, argv); + } else { + handler->handler(make_object(), argc, argv); + } + } + if(fpeekc(file) == EOF) return; +} + +static +void _parse_scene(const char* filename) { + FILE* file = fopen(filename, "r"); + int next; + do { + _parse_config(file); + next = nextnw(file); + ungetc(next, file); + } while(next != EOF); +} + +void load_scene(const char* file) { + world_clear(); + _parse_scene(file); +} + +void load_scene_additive(const char* file) { + printf("parsing scene\n"); + _parse_scene(file); + printf("parsed scene\n"); +} diff --git a/src/corelib/scene.h b/src/corelib/scene.h index 164b3ed..5fef139 100644 --- a/src/corelib/scene.h +++ b/src/corelib/scene.h @@ -3,7 +3,20 @@ #include "memory.h" +typedef struct object_t object_t; +typedef void(*type_handler_fn)(object_t* this, int argc, char** argv); + +// Add or replace the type handler for [Object] entries of a given key. +// Will delete the handler entry if handler == NULL. +void set_type_handler(const char* type, type_handler_fn handler); + +// Load a scene exclusively. Clears the current scene before parsing file. +void load_scene(const char* file); + +// Load a scene additively. +// Will not clear the currently active objects before parsing file. +void load_scene_additive(const char* file); #endif /* _corelib_scene_h */