3 * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../../include/keycodes.h"
28 #define GL3_PROTOTYPES 1
31 static int sdl_initialized = 0;
32 static int audio_initialized = 0;
33 static const char *device_string = NULL;
34 static SDL_AudioDeviceID audio_devid = 0;
35 static SDL_Window *gl_window = NULL;
36 static SDL_GLContext gl_context = NULL;
37 static SDL_Joystick *sdl_joystick = NULL;
38 static void (*keyboard_sdl)(int down, enum keycode keycode) = NULL;
39 static void (*joystick_sdl)(double x, double y, int fire) = NULL;
40 static void (*audio_sdl)(float *data, int len) = NULL;
41 static void (*resize_window_sdl)(int width, int height) = NULL;
42 static int joystick_y_axis_sdl = 1, joystick_x_axis_sdl = 0, joystick_fire_button_sdl = -1;
44 static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int len)
46 float audio_data[len / sizeof(float)];
48 SDL_memset(stream, 0, len);
49 audio_sdl(audio_data, len / sizeof(float) / 2);
50 SDL_MixAudioFormat(stream, (Uint8 *)audio_data, AUDIO_F32, len, SDL_MIX_MAXVOLUME / 2.0);
53 void sdl_list_joysticks(void)
57 rc = SDL_Init(SDL_INIT_JOYSTICK);
59 print_error("Failed to init SDL\n");
63 num = SDL_NumJoysticks();
64 for (i = 0; i < num; i++)
65 printf("#%d: %s\n", i, SDL_JoystickNameForIndex(i));
70 int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, enum keycode keycode), int joysticknum, int joystick_x_axis, int joystick_y_axis, int joystick_fire_button, void (*joystick)(double x, double y, int fire), void (*audio)(float *data, int len), void (*resize_window)(int width, int height), int multisampling, int vbl_sync, int rift)
74 keyboard_sdl = keyboard;
75 joystick_sdl = joystick;
77 resize_window_sdl = resize_window;
78 if (joystick_x_axis >= 0)
79 joystick_x_axis_sdl = joystick_x_axis;
80 if (joystick_y_axis >= 0)
81 joystick_y_axis_sdl = joystick_y_axis;
82 if (joystick_fire_button >= 0)
83 joystick_fire_button_sdl = joystick_fire_button;
85 /* init SDL library */
86 rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
88 print_error("Failed to init SDL\n");
93 SDL_JoystickEventState(SDL_ENABLE);
94 sdl_joystick = SDL_JoystickOpen((joysticknum < 0) ? 0 : joysticknum);
95 if (!sdl_joystick && joysticknum >= 0) {
97 print_error("Failed to open joystick #%d, see help!\n", joysticknum);
101 retry_without_multisampling:
102 if (multisampling > 1) {
103 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
104 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
105 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
106 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
107 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
108 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
109 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisampling);
113 gl_window = SDL_CreateWindow(progname, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
116 print_info("Failed to open SDL window: %s (retrying without multisampling)\n", SDL_GetError());
117 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
118 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
120 goto retry_without_multisampling;
122 print_error("Failed to open SDL window: %s\n", SDL_GetError());
123 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
124 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisampling);
129 /* create GL context */
130 gl_context = SDL_GL_CreateContext(gl_window);
132 print_error("Failed to create SDL's OpenGL context: %s\n", SDL_GetError());
137 rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
139 print_error("Failed to set SDL's OpenGL context profile\n");
143 rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
145 print_error("Failed to set SDL's OpenGL major version\n");
148 rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
150 print_error("Failed to set SDL's OpenGL minor version\n");
154 rc = SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
156 print_error("Failed to set SDL's OpenGL doublebuffer\n");
160 rc = SDL_GL_SetSwapInterval((vbl_sync) ? 1 : 0);
162 print_error("Failed to set SDL's OpenGL swap interval to VBLANK\n");
166 // seems like a hack to me. do we need this?
169 glewExperimental = GL_TRUE;
170 if (glewInit() != GLEW_OK) {
171 print_error("Failed to init GLEW\n");
178 glDisable(GL_DEPTH_TEST);
179 glDisable(GL_CULL_FACE);
180 if (multisampling > 1)
181 glEnable(GL_MULTISAMPLE);
185 count = SDL_GetNumAudioDevices(0);
187 for(i = 0; i < count; i++) {
188 string = SDL_GetAudioDeviceName(i, 0);
189 if (strstr(string, "Rift"))
190 device_string = string;
193 print_error("Oculus Rift headset not found, falling back to default audio device.\n");
197 SDL_AudioSpec want, have;
198 SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */
199 want.freq = sound_samplerate;
200 want.format = AUDIO_F32; /* we always use float in this project */
202 want.samples = sound_chunk; /* must be a power of two */
203 want.callback = audio_cb;
204 audio_devid = SDL_OpenAudioDevice(device_string, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
205 if (audio_devid <= 0) {
206 print_error("Failed to open audio! (No speaker connected?)\n");
209 } else if (have.format != want.format) {
210 print_error("Failed to open audio with desired audio format (want %d, got %d)\n", want.format, have.format);
213 } else if (have.freq != want.freq) {
214 print_error("Failed to open audio with desired sample rate (want %d, got %d)\n", want.freq, have.freq);
217 } else if (have.channels != want.channels) {
218 print_error("Failed to open audio with desired number of channels (want %d, got %d)\n", want.channels, have.channels);
222 SDL_PauseAudioDevice(audio_devid, 0);
223 audio_initialized = 1;
233 static enum keycode sdl2keycode(SDL_Keycode sym)
236 case SDLK_LCTRL: return KEYCODE_LCTRL;
237 case SDLK_RCTRL: return KEYCODE_RCTRL;
238 case SDLK_LSHIFT: return KEYCODE_LSHIFT;
239 case SDLK_RSHIFT: return KEYCODE_RSHIFT;
240 case SDLK_LALT: return KEYCODE_LALT;
241 case SDLK_RALT: return KEYCODE_RALT;
242 case SDLK_PAUSE: return KEYCODE_PAUSE;
243 case SDLK_LEFT: return KEYCODE_LEFT;
244 case SDLK_RIGHT: return KEYCODE_RIGHT;
245 case SDLK_UP: return KEYCODE_UP;
246 case SDLK_DOWN: return KEYCODE_DOWN;
247 case SDLK_END: return KEYCODE_END;
248 case SDLK_a: return KEYCODE_a;
249 case SDLK_b: return KEYCODE_b;
250 case SDLK_c: return KEYCODE_c;
251 case SDLK_d: return KEYCODE_d;
252 case SDLK_e: return KEYCODE_e;
253 case SDLK_f: return KEYCODE_f;
254 case SDLK_g: return KEYCODE_g;
255 case SDLK_h: return KEYCODE_h;
256 case SDLK_i: return KEYCODE_i;
257 case SDLK_j: return KEYCODE_j;
258 case SDLK_k: return KEYCODE_k;
259 case SDLK_l: return KEYCODE_l;
260 case SDLK_m: return KEYCODE_m;
261 case SDLK_n: return KEYCODE_n;
262 case SDLK_o: return KEYCODE_o;
263 case SDLK_p: return KEYCODE_p;
264 case SDLK_q: return KEYCODE_q;
265 case SDLK_r: return KEYCODE_r;
266 case SDLK_s: return KEYCODE_s;
267 case SDLK_t: return KEYCODE_t;
268 case SDLK_u: return KEYCODE_u;
269 case SDLK_v: return KEYCODE_v;
270 case SDLK_w: return KEYCODE_w;
271 case SDLK_x: return KEYCODE_x;
272 case SDLK_y: return KEYCODE_y;
273 case SDLK_z: return KEYCODE_z;
274 case SDLK_0: return KEYCODE_0;
275 case SDLK_1: return KEYCODE_1;
276 case SDLK_2: return KEYCODE_2;
277 case SDLK_3: return KEYCODE_3;
278 case SDLK_4: return KEYCODE_4;
279 case SDLK_5: return KEYCODE_5;
280 case SDLK_6: return KEYCODE_6;
281 case SDLK_7: return KEYCODE_7;
282 case SDLK_8: return KEYCODE_8;
283 case SDLK_9: return KEYCODE_9;
284 case SDLK_KP_0: return KEYCODE_KP_0;
285 case SDLK_KP_1: return KEYCODE_KP_1;
286 case SDLK_KP_2: return KEYCODE_KP_2;
287 case SDLK_KP_3: return KEYCODE_KP_3;
288 case SDLK_KP_4: return KEYCODE_KP_4;
289 case SDLK_KP_5: return KEYCODE_KP_5;
290 case SDLK_KP_6: return KEYCODE_KP_6;
291 case SDLK_KP_7: return KEYCODE_KP_7;
292 case SDLK_KP_8: return KEYCODE_KP_8;
293 case SDLK_KP_9: return KEYCODE_KP_9;
294 case SDLK_KP_DIVIDE: return KEYCODE_KP_DIVIDE;
295 case SDLK_KP_MULTIPLY: return KEYCODE_KP_MULTIPLY;
296 case SDLK_KP_MINUS: return KEYCODE_KP_MINUS;
297 case SDLK_KP_PLUS: return KEYCODE_KP_PLUS;
298 case SDLK_KP_PERIOD: return KEYCODE_KP_PERIOD;
299 case SDLK_KP_ENTER: return KEYCODE_KP_ENTER;
300 case SDLK_F1: return KEYCODE_F1;
301 case SDLK_F2: return KEYCODE_F2;
302 case SDLK_F3: return KEYCODE_F3;
303 case SDLK_F4: return KEYCODE_F4;
304 case SDLK_F5: return KEYCODE_F5;
305 case SDLK_F6: return KEYCODE_F6;
306 case SDLK_F7: return KEYCODE_F7;
307 case SDLK_F8: return KEYCODE_F8;
308 case SDLK_F9: return KEYCODE_F9;
309 case SDLK_F10: return KEYCODE_F10;
310 case SDLK_SPACE: return KEYCODE_SPACE;
311 case SDLK_BACKSPACE: return KEYCODE_BACKSPACE;
312 case SDLK_TAB: return KEYCODE_TAB;
313 case SDLK_RETURN: return KEYCODE_RETURN;
314 case SDLK_ESCAPE: return KEYCODE_ESCAPE;
315 case SDLK_DELETE: return KEYCODE_DELETE;
316 case SDLK_INSERT: return KEYCODE_INSERT;
317 case SDLK_COMMA: return KEYCODE_COMMA;
318 case SDLK_PERIOD: return KEYCODE_PERIOD;
319 default: return KEYCODE_UNDEFINED;
323 static double joystick_x = 0, joystick_y = 0;
324 static int joystick_fire = 0;
326 static void joystick_event(int axis, int value)
328 double v = (double)value / 32767.0;
331 case 0: joystick_y = v; break;
332 case 1: joystick_x = v; break;
333 case 2: joystick_fire = value; break;
336 joystick_sdl(joystick_x, joystick_y, joystick_fire);
339 static int key_ctrl = 0, key_f = 0, fullscreen = 0;
346 while (SDL_PollEvent(&event)) {
347 switch (event.type) {
351 case SDL_WINDOWEVENT:
352 if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
353 resize_window_sdl(event.window.data1, event.window.data2);
356 switch (event.key.keysym.sym) {
358 if (key_ctrl && !key_f) {
361 SDL_SetWindowFullscreen(gl_window, 0);
362 SDL_ShowCursor(SDL_ENABLE);
364 SDL_SetWindowFullscreen(gl_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
365 SDL_ShowCursor(SDL_DISABLE);
376 keyboard_sdl(1, sdl2keycode(event.key.keysym.sym));
379 switch (event.key.keysym.sym) {
388 keyboard_sdl(0, sdl2keycode(event.key.keysym.sym));
390 case SDL_JOYAXISMOTION:
391 if (event.jaxis.axis == joystick_y_axis_sdl)
392 joystick_event(0, event.jaxis.value);
393 if (event.jaxis.axis == joystick_x_axis_sdl)
394 joystick_event(1, event.jaxis.value);
396 case SDL_JOYBUTTONDOWN:
397 if (joystick_fire_button_sdl < 0 || event.jbutton.button == joystick_fire_button_sdl)
398 joystick_event(2, 1);
400 case SDL_JOYBUTTONUP:
401 if (joystick_fire_button_sdl < 0 || event.jbutton.button == joystick_fire_button_sdl)
402 joystick_event(2, 0);
412 SDL_GL_SwapWindow(gl_window);
419 SDL_JoystickClose(sdl_joystick);
424 SDL_DestroyWindow(gl_window);
428 /* clear OpenGL context */
430 SDL_GL_DeleteContext(gl_context);
434 /* exit SDL library */
435 if (audio_initialized) {
436 SDL_PauseAudioDevice(audio_devid, 1);
437 audio_initialized = 0;
439 if (audio_devid > 0) {
440 SDL_CloseAudioDevice(audio_devid);
443 if (sdl_initialized) {
449 uint32_t ticks_sdl(void)
451 return SDL_GetTicks();