Initial Framework
[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 Ken
7 \date 2016
8 ------------------------------------------------------------------------------*/
9 #ifdef __Win32
10 #include <windows.h>
11 #endif
12 #ifdef __EMSCRIPTEN__
13 #define main em_main
14 #include <emscripten/emscripten.h>
15 #else
16 #define INFINITE_MAINLOOP
17 #endif
18 #include <SDL2/SDL.h>
19 #include <SDL2/SDL_image.h>
20 #include <SDL_ttf.h>
21 #include <stdint.h>
22 #include <setjmp.h>
23 #include <stdio.h>
24
25 /* debug level */
26 #define DEBUG 1
27
28 /* Exit Codes */
29 #define EXIT_GRACEFUL 1
30 #define EXIT_DEBUG 2
31 #define EXIT_PANIC 3
32
33 /* Target frames per second */
34 #ifndef TARGET_FPS
35 #define TARGET_FPS 60
36 #endif
37
38 /* Target milliseconds per frame */
39 #define TARGET_DT (1000 / TARGET_FPS)
40
41 /* precompiler round-up division */
42 #define DIV_UP(x,y) ((x + (y / 2)) / y)
43
44 /* internally exposed functions */
45 int main_init(void);
46 void main_loop(void);
47
48 /* unexposed externs *
49 extern int state_init(void);
50 extern void state_tick(uint32_t delta_ticks);
51 extern const char* state_get_error(void);
52 extern void state_quit(void);
53 extern void state_handle_event(SDL_Event event);
54 extern int io_init(void);
55 extern const char* io_get_error(void);
56 extern void io_quit(void);*/
57
58 /* Function trigger stack for "unwinding" initialization of modules */
59 #define MAX_TRIGGERS 16
60 struct call_trigger
61 { int num_funcs;
62 void (*func[MAX_TRIGGERS])(void);
63 } quit_trigger = {0};
64
65 #define TRIGGER_SET(TARG, FUNC) TARG.func[TARG.num_funcs++] = FUNC
66 #define TRIGGER(TARG) while(TARG.num_funcs) (TARG.func[--TARG.num_funcs])()
67
68 /* main jump buffer */
69 jmp_buf jmp_main;
70
71 /** initializes subsystems and calls main_loop(void)
72 @return (exit_status - 1), where a normal shutdown's exit_status = 1.
73
74 main sets a jump buffer for its primary switch, which may be jumped to
75 at any time. Jumping with a 0 return value is equivalent to calling
76 setjmp directly, which initializes the system and begins the main loop.
77 Jumping with any other value will process one of the directives associated
78 with the exit codes in core.h
79 *******************************************************************************/
80 int main (int argc, char** argv)
81 { switch(setjmp(jmp_main))
82 { case 0:
83 if (main_init())
84 return -1;
85 main_loop(); /* no return during native execution */
86 #ifdef __EMSCRIPTEN__
87 emscripten_set_main_loop(main_loop,0,0);
88 return 0;
89 #endif
90 case EXIT_GRACEFUL:
91 break;
92 default:
93 case EXIT_PANIC:
94 //dump some debug info
95 break;
96 }
97 TRIGGER(quit_trigger);
98 return 0;
99 }
100
101 /** initializer
102 @return 0 if successful, -1 SDL, -2 IMG, -3 TTF, -4 STATE.
103 SDL and logging is available after this is called
104 *******************************************************************************/
105 int main_init()
106 { static char bInitialized = 0;
107 if (bInitialized++)
108 { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Resetting [%d]\n", bInitialized);
109 return 0;
110 }
111
112 if (SDL_Init(SDL_INIT_EVERYTHING & ~(SDL_INIT_TIMER | SDL_INIT_HAPTIC)) < 0)
113 { fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
114 return - 1;
115 }
116 TRIGGER_SET(quit_trigger, SDL_Quit);
117
118 if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
119 { fprintf(stderr, "IMG_Init failed: %s\n", IMG_GetError());
120 return -2;
121 }
122 TRIGGER_SET(quit_trigger, IMG_Quit);
123
124 if (TTF_Init() == -1)
125 { fprintf(stderr, "TTF_Init failed: %s\n", TTF_GetError());
126 return -3;
127 }
128 TRIGGER_SET(quit_trigger, TTF_Quit);
129 /*
130 if (state_init())
131 { printf("state_init failed: %s\n", state_get_error());
132 return -4;
133 }
134 TRIGGER_SET(quit_trigger, state_quit);
135 if (renderer_init())
136 { printf("state_init failed: %s\n", renderer_get_error());
137 return -5;
138 }
139 TRIGGER_SET(quit_trigger, renderer_quit);
140 if (io_init())
141 { printf("io_init failed: %s\n", io_get_error());
142 return -6;
143 }
144 TRIGGER_SET(quit_trigger, io_quit);
145 */
146 SDL_Log("Initialization Complete.");
147 return 0;
148 }
149
150 /** main loop.
151 exits only during core_shutdown and core_panic if in an infinite loop
152 *******************************************************************************/
153 void main_loop()
154 { static uint32_t main_loop_last_ticks = 0;
155 static SDL_Event event;
156 uint32_t delta_ticks;
157 loop:
158 /* Poll events */
159 while (SDL_PollEvent(&event))
160 //state_handle_event(&event);
161 ;
162
163 /* change in time since last loop */
164 delta_ticks = SDL_GetTicks() - main_loop_last_ticks;
165
166 /* handle breakpoints (long pause likely a breakpoint) */
167 if (delta_ticks > 1000)
168 { SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "Recovering from long pause.");
169 delta_ticks = TARGET_DT;
170 }
171
172 /* tick the state manager forward by the change in time */
173 //state_tick(delta_ticks);
174 main_loop_last_ticks = SDL_GetTicks();
175
176 /* render the scene to backbuffer */
177 ////todo...
178 /* swap in the backbuffer for display */
179 ////todo...
180
181 /* cap the framerate if we're handling the loop mechanism directly, but only
182 yield if we have a substantial portion of time to yield (1/10th of the
183 target delta) */
184 printf("%d\n", main_loop_last_ticks);
185 #ifdef INFINITE_MAINLOOP
186 delta_ticks = SDL_GetTicks() - main_loop_last_ticks;
187 if ((delta_ticks + DIV_UP(TARGET_DT, 10)) < TARGET_DT)
188 SDL_Delay(TARGET_DT - delta_ticks);
189
190 goto loop;
191 #endif
192 }