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