more elaborate keyboard input handling, and debug gui improvements
[laserbrain_demo] / src / main.cc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <GL/glew.h>
5 #include <SDL2/SDL.h>
6 #include "app.h"
7
8 static bool init(int argc, char **argv);
9 static void process_event(SDL_Event *ev);
10 static void proc_modkeys();
11 static int translate_keysym(SDL_Keycode sym);
12
13 static SDL_Window *win;
14 static SDL_GLContext ctx;
15 static bool fullscreen, mouse_grabbed;
16 static bool quit;
17
18 static unsigned int start_time;
19 static unsigned int modkeys;
20
21 SDL_GameController *gamepad;
22
23 static int scale_factor = 1;
24
25 int main(int argc, char **argv)
26 {
27         if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
28                 fprintf(stderr, "failed to initialize SDL\n");
29                 return 1;
30         }
31
32         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
33         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
34         SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
35
36         int defpos = SDL_WINDOWPOS_UNDEFINED;
37         unsigned int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
38
39         if(!(win = SDL_CreateWindow("demo", defpos, defpos, 1024, 768, sdlflags))) {
40                 // try again without sRGB capability
41                 SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 0);
42                 if(!(win = SDL_CreateWindow("demo", defpos, defpos, 1024, 768, sdlflags))) {
43                         fprintf(stderr, "failed to create window\n");
44                         SDL_Quit();
45                         return 1;
46                 }
47                 fprintf(stderr, "failed to get an sRGB framebuffer.\n");
48         }
49         int val;
50         SDL_GL_GetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &val);
51         printf("SDL says we %s an sRGB framebuffer\n", val ? "got" : "didn't get");
52         fb_srgb = val;
53
54         if(!(ctx = SDL_GL_CreateContext(win))) {
55                 fprintf(stderr, "failed to create OpenGL context\n");
56                 SDL_Quit();
57                 return 1;
58         }
59         SDL_GL_GetDrawableSize(win, &win_width, &win_height);
60         win_aspect = (float)win_width / (float)win_height;
61
62         printf("detected %d joysticks\n", SDL_NumJoysticks());
63         for(int i=0; i<SDL_NumJoysticks(); i++) {
64                 if(SDL_IsGameController(i)) {
65                         if(!(gamepad = SDL_GameControllerOpen(i))) {
66                                 fprintf(stderr, "failed to open game controller %i: %s\n", i, SDL_GetError());
67                                 continue;
68                         }
69                         printf("Using gamepad: %s\n", SDL_GameControllerNameForIndex(i));
70                 }
71         }
72
73         if(!init(argc, argv)) {
74                 SDL_Quit();
75                 return 1;
76         }
77         app_reshape(win_width, win_height);
78
79         while(!quit) {
80                 SDL_Event ev;
81
82                 time_msec = SDL_GetTicks() - start_time;
83                 while(SDL_PollEvent(&ev)) {
84                         process_event(&ev);
85                         if(quit) goto break_evloop;
86                 }
87
88                 app_display();
89         }
90 break_evloop:
91
92         app_cleanup();
93         SDL_Quit();
94         return 0;
95 }
96
97 void app_swap_buffers()
98 {
99         SDL_GL_SwapWindow(win);
100 }
101
102 void app_quit()
103 {
104         quit = true;
105 }
106
107 unsigned int app_get_modifiers()
108 {
109         return modkeys;
110 }
111
112 void app_resize(int x, int y)
113 {
114         SDL_SetWindowSize(win, x, y);
115 }
116
117 void app_fullscreen(bool fs)
118 {
119         SDL_SetWindowFullscreen(win, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
120         fullscreen = fs;
121 }
122
123 void app_toggle_fullscreen()
124 {
125         app_fullscreen(!fullscreen);
126 }
127
128 bool app_is_fullscreen()
129 {
130         return fullscreen;
131 }
132
133 void app_grab_mouse(bool grab)
134 {
135         if(grab) {
136                 SDL_WarpMouseInWindow(win, win_width / 2, win_height / 2);
137         }
138         //SDL_SetWindowGrab(win, grab ? SDL_TRUE : SDL_FALSE);
139         //SDL_ShowCursor(grab ? 1 : 0);
140         SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
141         mouse_grabbed = grab;
142 }
143
144 void app_toggle_grab_mouse()
145 {
146         app_grab_mouse(!mouse_grabbed);
147 }
148
149 bool app_is_mouse_grabbed()
150 {
151         return mouse_grabbed;
152 }
153
154
155 static bool init(int argc, char **argv)
156 {
157         glewInit();
158
159         if(!app_init(argc, argv)) {
160                 return false;
161         }
162
163         start_time = SDL_GetTicks();
164         return true;
165 }
166
167 static void process_event(SDL_Event *ev)
168 {
169         int key;
170
171         switch(ev->type) {
172         case SDL_QUIT:
173                 quit = true;
174                 break;
175
176         case SDL_KEYDOWN:
177         case SDL_KEYUP:
178                 proc_modkeys();
179                 if((key = translate_keysym(ev->key.keysym.sym)) != -1) {
180                         app_keyboard(key, ev->key.state == SDL_PRESSED);
181                 }
182                 break;
183
184         case SDL_MOUSEBUTTONDOWN:
185         case SDL_MOUSEBUTTONUP:
186                 proc_modkeys();
187                 app_mouse_button(ev->button.button - SDL_BUTTON_LEFT, ev->button.state == SDL_PRESSED,
188                                 ev->button.x * scale_factor, ev->button.y * scale_factor);
189                 break;
190
191         case SDL_MOUSEMOTION:
192                 if(mouse_grabbed) {
193                         app_mouse_delta(ev->motion.xrel, ev->motion.yrel);
194                 } else {
195                         app_mouse_motion(ev->motion.x * scale_factor, ev->motion.y * scale_factor);
196                 }
197                 break;
198
199         case SDL_MOUSEWHEEL:
200                 app_mouse_wheel(ev->wheel.y);
201                 break;
202
203         case SDL_WINDOWEVENT:
204                 if(ev->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
205                         SDL_GL_GetDrawableSize(win, &win_width, &win_height);
206                         win_aspect = (float)win_width / (float)win_height;
207                         scale_factor = win_width / ev->window.data1;
208                         app_reshape(win_width, win_height);
209                 }
210                 break;
211
212         case SDL_CONTROLLERAXISMOTION:
213                 app_gamepad_axis(ev->caxis.axis, ev->caxis.value / 32768.0f);
214                 break;
215
216         case SDL_CONTROLLERBUTTONDOWN:
217         case SDL_CONTROLLERBUTTONUP:
218                 app_gamepad_button(ev->cbutton.button, ev->type == SDL_CONTROLLERBUTTONDOWN);
219                 break;
220         }
221 }
222
223 static void proc_modkeys()
224 {
225         modkeys = 0;
226         SDL_Keymod sdlmod = SDL_GetModState();
227         if(sdlmod & KMOD_SHIFT) {
228                 modkeys |= MOD_SHIFT;
229         }
230         if(sdlmod & KMOD_ALT) {
231                 modkeys |= MOD_ALT;
232         }
233         if(sdlmod & KMOD_CTRL) {
234                 modkeys |= MOD_CTRL;
235         }
236 }
237
238 static int translate_keysym(SDL_Keycode sym)
239 {
240         switch(sym) {
241         case SDLK_RETURN:
242                 return '\n';
243         case SDLK_DELETE:
244                 return KEY_DEL;
245         case SDLK_LEFT:
246                 return KEY_LEFT;
247         case SDLK_RIGHT:
248                 return KEY_RIGHT;
249         case SDLK_UP:
250                 return KEY_UP;
251         case SDLK_DOWN:
252                 return KEY_DOWN;
253         case SDLK_PAGEUP:
254                 return KEY_PGUP;
255         case SDLK_PAGEDOWN:
256                 return KEY_PGDOWN;
257         case SDLK_HOME:
258                 return KEY_HOME;
259         case SDLK_END:
260                 return KEY_END;
261         default:
262                 break;
263         }
264
265         if(sym < 127) {
266                 return sym;
267         }
268         if(sym >= SDLK_F1 && sym <= SDLK_F12) {
269                 return KEY_F1 + sym - SDLK_F1;
270         }
271         return -1;
272 }