build system 3
[henge/webcc.git] / src / bin / dist / the_march.c~
1 /*!@file
2 \brief engine entry
3 \details initializes necessary subsystems before invoking the preloader,
4 which loads initial game data, before finally invoking the
5 main loop main_loop(void), which may be run in either blocking
6 or non-blocking mode.
7 \author Mihrtec
8 \date 2016
9 ------------------------------------------------------------------------------*/
10 #ifdef __EMSCRIPTEN__
11 /* Web Environment */
12 #define main em_main
13 #include <SDL_ttf.h>
14 #include <emscripten/emscripten.h>
15 #else
16 /* Traditional Environment */
17 #ifdef __Win32
18 #include <windows.h>
19 #endif //__Win32
20 #include <SDL2/SDL_ttf.h>
21 #endif
22 /* ENVIRONMENT-AGNOSTIC DEFINES */
23 #include <SDL2/SDL.h>
24 #include <SDL2/SDL_image.h>
25 #include <stdint.h>
26 #include <setjmp.h>
27 #include <stdio.h>
28 #define TRIGGERS quit_trigger
29 #include <core/trigger.h>
30 #include <core/engine.h>
31
32 /* exposed functions */
33 void main_loop(void);
34
35 /* private functions */
36 static int main_init(void);
37
38 /* unexposed externs */
39 extern int state_init(void);
40 extern void state_tick(uint32_t delta_ticks);
41 extern const char* state_get_error(void);
42 extern void state_quit(void);
43 extern void state_handle_event(SDL_Event *event);
44 #if 0
45 extern int io_init(void);
46 extern const char* io_get_error(void);
47 extern void io_quit(void);
48 #endif //TODO
49
50 /* main jump buffer */
51 jmp_buf jmp_main;
52
53 /*@
54 initializes subsystems and calls main_loop(void)
55
56 main sets a jump buffer for its primary switch, which may be jumped to
57 at any time. Jumping with a 0 return value is equivalent to calling
58 setjmp directly, which initializes the system and begins the main loop.
59 Jumping with any other value will process one of the directives associated
60 with the exit codes in core.h
61 */
62 #ifdef __EMSCRIPTEN__
63 #define main_loop() \
64 do { \
65 emscripten_set_main_loop(main_loop,0,0); \
66 TRIGGER_SET(quit_trigger, emscripten_cancel_main_loop); \
67 return 0; \
68 } while (0)
69 #endif
70
71 int
72 main (int argc, char** argv)
73 { switch(setjmp(jmp_main))
74 { case 0:
75 if (main_init())
76 return -1;
77 main_loop();
78 case EXIT_GRACEFUL:
79 break;
80 default:
81 case EXIT_PANIC:
82 //dump some debug info
83 break;
84 }
85 TRIGGER(quit_trigger);
86 return 0;
87 }
88
89 #ifdef __EMSCRIPTEN__
90 #undef main_loop
91 #endif
92
93 /*@
94 subsystem initializer
95 Calling main_init() boots the system, and may be called multiple times to
96 cause a system-wide reboot.
97 @return 0 if successful, -1 SDL, -2 IMG, -3 TTF, -4 STATE.
98 SDL and logging is available after this is called
99 */
100 #define INIT(_cond,_errorstring,_quit) \
101 do { \
102 if (_cond) \
103 { fprintf(stderr, #_cond " failed: %s\n", _errorstring()); \
104 return -1; \
105 } \
106 TRIGGER_SET(quit_trigger, _quit); \
107 } while (0)
108
109 #define SDL_FLAGS SDL_INIT_EVERYTHING & ~(SDL_INIT_TIMER | SDL_INIT_HAPTIC)
110
111 static int
112 main_init()
113 { static uint32_t bInitialized = 0;
114 if (bInitialized++)
115 { TRIGGER(quit_trigger);
116 SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Resetting [%d]\n",
117 bInitialized);
118 }
119
120 INIT(SDL_Init(SDL_FLAGS) < 0, SDL_GetError, SDL_Quit);
121 INIT(IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG, IMG_GetError, IMG_Quit);
122 INIT(TTF_Init() == -1, TTF_GetError, TTF_Quit);
123 INIT(state_init(), state_get_error, state_quit);
124 INIT(fs_init(), fs_get_error, fs_quit);
125
126 SDL_Log("Initialization Complete.");
127 return 0;
128 }
129
130 /*@
131 The main loop may be compiled in blocking or non-blocking mode, and
132 synchronizes time in ticks (milliseconds) as established by SDL anchored
133 on the state_tick() event.
134 */
135 void
136 main_loop()
137 { static uint32_t state_last_ticks = 0;
138 SDL_Event event;
139 uint32_t delta_ticks;
140
141 #ifndef NON_BLOCKING_LOOPS
142 loop:
143 #endif
144 /* user/system inputs */
145 while (SDL_PollEvent(&event))
146 state_handle_event(&event);
147
148 /* change in time since last loop */
149 delta_ticks = SDL_GetTicks() - state_last_ticks;
150 /* handle breakpoints (long pause likely a breakpoint) */
151 if (delta_ticks > 1000)
152 { SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "Recovering from long pause.");
153 delta_ticks = TARGET_DT;
154 }
155 /* tick the state manager and immediately save the time */
156 state_tick(delta_ticks);
157 state_last_ticks = SDL_GetTicks();
158
159 //TODO: render(screen)
160 //TODO: SDL_Flip(screen)::sdl_geterror
161
162 #ifndef NON_BLOCKING_LOOPS
163 #define DIV_UP(x,y) (((x) + ((y) / 2)) / (x))
164 /* yield if we have a substantial portion of time leftover */
165 delta_ticks += SDL_GetTicks() - state_last_ticks;
166 if (delta_ticks < (TARGET_DT - DIV_UP(TARGET_DT, 10)))
167 SDL_Delay(TARGET_DT - delta_ticks);
168 goto loop;
169 #endif
170 }
171