--- /dev/null
+/*!@file
+ \brief engine entry
+ \details initializes necessary subsystems before invoking the preloader,
+ which loads initial game data, before finally invoking the
+ main loop main_loop(void), which may be run in either blocking
+ or non-blocking mode.
+ \author Mihrtec
+ \date 2016
+------------------------------------------------------------------------------*/
+#ifdef __EMSCRIPTEN__
+/* Web Environment */
+#define main em_main
+#include <SDL_ttf.h>
+#include <emscripten/emscripten.h>
+#else
+/* Traditional Environment */
+#ifdef __Win32
+#include <windows.h>
+#endif //__Win32
+#include <SDL2/SDL_ttf.h>
+#endif
+/* ENVIRONMENT-AGNOSTIC DEFINES */
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdio.h>
+#define TRIGGERS quit_trigger
+#include <core/trigger.h>
+#include <core/engine.h>
+
+/* exposed functions */
+void main_loop(void);
+
+/* private functions */
+static int main_init(void);
+
+/* unexposed externs */
+extern int state_init(void);
+extern void state_tick(uint32_t delta_ticks);
+extern const char* state_get_error(void);
+extern void state_quit(void);
+extern void state_handle_event(SDL_Event *event);
+#if 0
+extern int io_init(void);
+extern const char* io_get_error(void);
+extern void io_quit(void);
+#endif //TODO
+
+/* main jump buffer */
+jmp_buf jmp_main;
+
+/*@
+ initializes subsystems and calls main_loop(void)
+
+ main sets a jump buffer for its primary switch, which may be jumped to
+ at any time. Jumping with a 0 return value is equivalent to calling
+ setjmp directly, which initializes the system and begins the main loop.
+ Jumping with any other value will process one of the directives associated
+ with the exit codes in core.h
+*/
+#ifdef __EMSCRIPTEN__
+#define main_loop() \
+ do { \
+ emscripten_set_main_loop(main_loop,0,0); \
+ TRIGGER_SET(quit_trigger, emscripten_cancel_main_loop); \
+ return 0; \
+ } while (0)
+#endif
+
+int
+main (int argc, char** argv)
+{ switch(setjmp(jmp_main))
+ { case 0:
+ if (main_init())
+ return -1;
+ main_loop();
+ case EXIT_GRACEFUL:
+ break;
+ default:
+ case EXIT_PANIC:
+ //dump some debug info
+ break;
+ }
+ TRIGGER(quit_trigger);
+ return 0;
+}
+
+#ifdef __EMSCRIPTEN__
+#undef main_loop
+#endif
+
+/*@
+ subsystem initializer
+ Calling main_init() boots the system, and may be called multiple times to
+ cause a system-wide reboot.
+ @return 0 if successful, -1 SDL, -2 IMG, -3 TTF, -4 STATE.
+ SDL and logging is available after this is called
+*/
+#define INIT(_cond,_errorstring,_quit) \
+ do { \
+ if (_cond) \
+ { fprintf(stderr, #_cond " failed: %s\n", _errorstring()); \
+ return -1; \
+ } \
+ TRIGGER_SET(quit_trigger, _quit); \
+ } while (0)
+
+#define SDL_FLAGS SDL_INIT_EVERYTHING & ~(SDL_INIT_TIMER | SDL_INIT_HAPTIC)
+
+static int
+main_init()
+{ static uint32_t bInitialized = 0;
+ if (bInitialized++)
+ { TRIGGER(quit_trigger);
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Resetting [%d]\n",
+ bInitialized);
+ }
+
+ INIT(SDL_Init(SDL_FLAGS) < 0, SDL_GetError, SDL_Quit);
+ INIT(IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG, IMG_GetError, IMG_Quit);
+ INIT(TTF_Init() == -1, TTF_GetError, TTF_Quit);
+ INIT(state_init(), state_get_error, state_quit);
+ INIT(fs_init(), fs_get_error, fs_quit);
+
+ SDL_Log("Initialization Complete.");
+ return 0;
+}
+
+/*@
+ The main loop may be compiled in blocking or non-blocking mode, and
+ synchronizes time in ticks (milliseconds) as established by SDL anchored
+ on the state_tick() event.
+*/
+void
+main_loop()
+{ static uint32_t state_last_ticks = 0;
+ SDL_Event event;
+ uint32_t delta_ticks;
+
+#ifndef NON_BLOCKING_LOOPS
+loop:
+#endif
+ /* user/system inputs */
+ while (SDL_PollEvent(&event))
+ state_handle_event(&event);
+
+ /* change in time since last loop */
+ delta_ticks = SDL_GetTicks() - state_last_ticks;
+ /* handle breakpoints (long pause likely a breakpoint) */
+ if (delta_ticks > 1000)
+ { SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "Recovering from long pause.");
+ delta_ticks = TARGET_DT;
+ }
+ /* tick the state manager and immediately save the time */
+ state_tick(delta_ticks);
+ state_last_ticks = SDL_GetTicks();
+
+ //TODO: render(screen)
+ //TODO: SDL_Flip(screen)::sdl_geterror
+
+#ifndef NON_BLOCKING_LOOPS
+#define DIV_UP(x,y) (((x) + ((y) / 2)) / (x))
+ /* yield if we have a substantial portion of time leftover */
+ delta_ticks += SDL_GetTicks() - state_last_ticks;
+ if (delta_ticks < (TARGET_DT - DIV_UP(TARGET_DT, 10)))
+ SDL_Delay(TARGET_DT - delta_ticks);
+ goto loop;
+#endif
+}
+