#include #include #include #include #include #include #include "util.h" #ifndef NULL #define NULL ((void *)(0)) #endif // NULL #define ASSETNAME_MAX ((Uint32)1024) #define READLINE_BUFFER_SIZE (2048) const Sint32 SCR_W = 640; const Sint32 SCR_H = 480; typedef struct _AssetContainer { char name[ASSETNAME_MAX]; Uint32 name_length; SDL_Surface *data; } ACont; typedef struct _GContainer { SDL_Window *window; SDL_Surface *surf; Map *assets; Uint32 last_tick; Uint32 current_tick; SDL_bool running; } GCont; static int read_line(char [], int, FILE *); static void add_asset(GCont *, const char *, const char *); static SDL_bool init(GCont *); static SDL_bool load(GCont *, const char *); static void loop(GCont *); static void close(GCont *); // Private int read_line(char buffer[], int size, FILE *file) { int pos = 0; int ch = 0; do { ch = fgetc(file); if (ch != EOF && ch != '\r' && ch != '\n') buffer[pos++] = (char)ch; if (ferror(file) != 0) return (size << 1); } while (ch != EOF && ch != '\n' && pos < size); buffer[pos] = '\0'; return (ch == EOF ? EOF : pos); } void add_asset(GCont *gc, const char *name, const char *filename) { Uint32 i = 0; ACont *asset = NULL; SDL_Surface *data = IMG_Load(filename); if (!data) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to read '%s': %s\n", filename, SDL_GetError()); return; } asset = (ACont *)calloc(1, sizeof(ACont)); for (i = 0; i < ASSETNAME_MAX; i++) asset->name[i] = '\0'; asset->data = data; asset->name_length = min(ASSETNAME_MAX, strlen(name)); memcpy(asset->name, name, asset->name_length); gc->assets = map_put(gc->assets, asset->name, asset); } SDL_bool init(GCont *gc) { static const Uint32 SDL_FLAGS = (SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS); static const Uint32 IMG_FLAGS = (IMG_INIT_PNG | IMG_INIT_JPG); if (SDL_Init(SDL_FLAGS) != 0) { printf("SDL could not initialize: %s\n", SDL_GetError()); return SDL_FALSE; } if ((IMG_Init(IMG_FLAGS) & IMG_FLAGS) != IMG_FLAGS) { printf("SDL image manager could not initialize: %s\n", SDL_GetError()); SDL_Quit(); return SDL_FALSE; } gc->running = SDL_FALSE; gc->assets = NULL; gc->surf = NULL; gc->window = SDL_CreateWindow("SDL experiment", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCR_W, SCR_H, SDL_WINDOW_SHOWN); if (!gc->window) { printf("SDL window could not be created: %s\n", SDL_GetError()); SDL_Quit(); IMG_Quit(); return SDL_FALSE; } gc->surf = SDL_GetWindowSurface(gc->window); return SDL_TRUE; } SDL_bool load(GCont *gc, const char *path) { const char *error = NULL; const char *error_extra = NULL; int err_offset = 0; pcre *regex = NULL; pcre_extra *regex_extra = NULL; int len = 0; int res_vector[8] = {0}; char buffer[READLINE_BUFFER_SIZE] = {0}; FILE *file = NULL; SDL_bool retval = SDL_FALSE; regex = pcre_compile("^\\s*\"([^\"]+)\"\\s*:\\s*\"([^\"]+)\"\\s*$", (PCRE_EXTENDED | PCRE_UTF8), &error, &err_offset, NULL); if (!regex) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to compile regex: %s\n", error); return SDL_FALSE; } regex_extra = pcre_study(regex, 0, &error_extra); if (error_extra) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to study regex: %s\n", error_extra); goto load_cleanup; } if (!(file = fopen(path, "r"))) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to open file '%s'.\n", path); goto load_cleanup; } do { int regex_ret = 0; len = read_line(buffer, READLINE_BUFFER_SIZE, file); if (READLINE_BUFFER_SIZE < len) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to read file '%s'.\n", path); goto load_cleanup; } else if (len == EOF) { break; } else if (len == 0) { continue; } regex_ret = pcre_exec(regex, regex_extra, buffer, len, 0, 0, res_vector, 32); if (regex_ret < 0) { switch (regex_ret) { case PCRE_ERROR_NOMATCH: break; case PCRE_ERROR_NULL: SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Null error while parsing '%.*s'!\n", len, buffer); goto load_cleanup; case PCRE_ERROR_BADOPTION: SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Bad option while parsing '%.*s'!\n", len, buffer); goto load_cleanup; case PCRE_ERROR_BADMAGIC: SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Corrupt regex while parsing '%.*s'!\n", len, buffer); goto load_cleanup; case PCRE_ERROR_UNKNOWN_NODE: SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Bad regex while parsing '%.*s'!\n", len, buffer); goto load_cleanup; case PCRE_ERROR_NOMEMORY: SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Out of memory while parsing '%.*s'!\n", len, buffer); goto load_cleanup; default: break; } } if (regex_ret != 0 && regex_ret != 3) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Invalid number of results (%d) while parsing '%.*s'!\n", regex_ret, len, buffer); goto load_cleanup; } else if (regex_ret == 3) // [ "", "", "" ] { const char *name = NULL; const char *path = NULL; int name_len = pcre_get_substring(buffer, res_vector, regex_ret, 1, &(name)); int path_len = pcre_get_substring(buffer, res_vector, regex_ret, 2, &(path)); if (0 < name_len && 0 < path_len) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loading asset '%.*s' from path '%.*s'\n", name_len, name, path_len, path); add_asset(gc, name, path); } else { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Invalid line '%.*s' where\n name = '%.*s'\n path = '%.*s'\n", len, buffer, name_len, (0 < name_len ? name : "(null)"), path_len, (0 < path_len ? path : "(null)")); } if (0 < name_len) pcre_free_substring(name); if (0 < path_len) pcre_free_substring(path); } } while (0 < len); retval = SDL_TRUE; load_cleanup: if (regex) pcre_free(regex); if (regex_extra) #ifdef PCRE_CONFIG_JIT pcre_free_study(regex_extra); #else pcre_free(regex_extra); #endif // PCRE_CONFIG_JIT if (file) fclose(file); return retval; } void loop(GCont *gc) { SDL_Event ev = {0}; gc->running = SDL_TRUE; SDL_FillRect(gc->surf, NULL, SDL_MapRGB(gc->surf->format, 0xff, 0xff, 0xff)); SDL_UpdateWindowSurface(gc->window); gc->last_tick = 0; gc->current_tick = 0; while (gc->running) { while (SDL_PollEvent(&ev)) { if (ev.type == SDL_QUIT) gc->running = SDL_FALSE; } if (gc->running) { gc->last_tick = gc->current_tick; gc->current_tick = SDL_GetTicks(); // update(gc); // draw(gc); } SDL_UpdateWindowSurface(gc->window); } } void close(GCont *gc) { if (gc->assets) { Uint32 i = 0; Map *assets = gc->assets; gc->assets = NULL; for (i = 0; i < assets->size; i++) { ACont *asset = (ACont *)assets->nodes[i].value; assets->nodes[i].value = NULL; if (asset) { SDL_FreeSurface(asset->data); asset->data = NULL; free(asset); } } free(assets); } SDL_DestroyWindow(gc->window); IMG_Quit(); SDL_Quit(); gc->window = NULL; gc->surf = NULL; } int main(int argc, char *argv[]) { GCont gc = {0}; if (argc != 2) { fprintf(stderr, "Usage: ./sandbox \n"); return EXIT_FAILURE; } if (!init(&gc)) return EXIT_FAILURE; if (!load(&gc,argv[1])) { fprintf(stderr, "Failed to load file: %s\n", argv[1]); close(&gc); return EXIT_FAILURE; } loop(&gc); close(&gc); return EXIT_SUCCESS; }