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/>.
28 #define GL3_PROTOTYPES 1
31 static int sdl_initialized = 0;
32 static int audio_initialized = 0;
33 static SDL_Window *gl_window = NULL;
34 static SDL_GLContext gl_context = NULL;
35 static void (*keyboard_sdl)(int down, enum keycode keycode) = NULL;
36 static void (*audio_sdl)(float *data, int len) = NULL;
37 static void (*resize_window_sdl)(int width, int height) = NULL;
39 static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int len)
41 float audio_data[len / sizeof(float)];
43 SDL_memset(stream, 0, len);
44 audio_sdl(audio_data, len / sizeof(float) / 2);
45 SDL_MixAudio(stream, (Uint8 *)audio_data, len, SDL_MIX_MAXVOLUME);
48 int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, enum keycode keycode), void (*audio)(float *data, int len), void (*resize_window)(int width, int height), int multisampling, int vbl_sync)
52 keyboard_sdl = keyboard;
54 resize_window_sdl = resize_window;
56 /* init SDL library */
57 rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
59 print_error("Failed to init SDL\n");
65 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
66 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
67 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
68 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
69 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
70 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
71 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisampling);
75 gl_window = SDL_CreateWindow(progname, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
77 print_error("Failed to open SDL window: %s (try without multisampling)\n", SDL_GetError());
82 /* create GL context */
83 gl_context = SDL_GL_CreateContext(gl_window);
85 print_error("Failed to create SDL's OpenGL context: %s\n", SDL_GetError());
90 rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
92 print_error("Failed to set SDL's OpenGL context profile\n");
96 rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
98 print_error("Failed to set SDL's OpenGL major version\n");
101 rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
103 print_error("Failed to set SDL's OpenGL minor version\n");
107 rc = SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
109 print_error("Failed to set SDL's OpenGL doublebuffer\n");
113 rc = SDL_GL_SetSwapInterval((vbl_sync) ? 1 : 0);
115 print_error("Failed to set SDL's OpenGL swap interval to VBLANK\n");
119 // seems like a hack to me. do we need this?
122 glewExperimental = GL_TRUE;
123 if (glewInit() != GLEW_OK) {
124 print_error("Failed to init GLEW\n");
131 glDisable(GL_DEPTH_TEST);
132 glDisable(GL_CULL_FACE);
134 glEnable(GL_MULTISAMPLE);
137 SDL_AudioSpec want, have;
138 SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */
139 want.freq = sound_samplerate;
140 want.format = AUDIO_F32; /* we always use float in this project */
142 want.samples = sound_chunk; /* must be a power of two */
143 want.callback = audio_cb;
144 rc = SDL_OpenAudio(&want, &have);
146 print_error("Failed to open audio! (No speaker connected?)\n");
148 } else if (have.format != want.format) {
149 print_error("Failed to open audio with desired audio format\n");
153 } else if (have.freq != want.freq) {
154 print_error("Failed to open audio with desired sample rate\n");
158 } else if (have.channels != want.channels) {
159 print_error("Failed to open audio with desired channels (got %d)\n", have.channels);
165 audio_initialized = 1;
175 static enum keycode sdl2keycode(SDL_Keycode sym)
178 case SDLK_LCTRL: return KEYCODE_LCTRL;
179 case SDLK_RCTRL: return KEYCODE_RCTRL;
180 case SDLK_LSHIFT: return KEYCODE_LSHIFT;
181 case SDLK_RSHIFT: return KEYCODE_RSHIFT;
182 case SDLK_PAUSE: return KEYCODE_PAUSE;
183 case SDLK_LEFT: return KEYCODE_LEFT;
184 case SDLK_RIGHT: return KEYCODE_RIGHT;
185 case SDLK_UP: return KEYCODE_UP;
186 case SDLK_DOWN: return KEYCODE_DOWN;
187 case SDLK_END: return KEYCODE_END;
188 case SDLK_a: return KEYCODE_a;
189 case SDLK_b: return KEYCODE_b;
190 case SDLK_c: return KEYCODE_c;
191 case SDLK_d: return KEYCODE_d;
192 case SDLK_e: return KEYCODE_e;
193 case SDLK_f: return KEYCODE_f;
194 case SDLK_g: return KEYCODE_g;
195 case SDLK_h: return KEYCODE_h;
196 case SDLK_i: return KEYCODE_i;
197 case SDLK_j: return KEYCODE_j;
198 case SDLK_k: return KEYCODE_k;
199 case SDLK_l: return KEYCODE_l;
200 case SDLK_m: return KEYCODE_m;
201 case SDLK_n: return KEYCODE_n;
202 case SDLK_o: return KEYCODE_o;
203 case SDLK_p: return KEYCODE_p;
204 case SDLK_q: return KEYCODE_q;
205 case SDLK_r: return KEYCODE_r;
206 case SDLK_s: return KEYCODE_s;
207 case SDLK_t: return KEYCODE_t;
208 case SDLK_u: return KEYCODE_u;
209 case SDLK_v: return KEYCODE_v;
210 case SDLK_w: return KEYCODE_w;
211 case SDLK_x: return KEYCODE_x;
212 case SDLK_y: return KEYCODE_y;
213 case SDLK_z: return KEYCODE_z;
214 case SDLK_0: return KEYCODE_0;
215 case SDLK_1: return KEYCODE_1;
216 case SDLK_2: return KEYCODE_2;
217 case SDLK_3: return KEYCODE_3;
218 case SDLK_4: return KEYCODE_4;
219 case SDLK_5: return KEYCODE_5;
220 case SDLK_6: return KEYCODE_6;
221 case SDLK_7: return KEYCODE_7;
222 case SDLK_8: return KEYCODE_8;
223 case SDLK_9: return KEYCODE_9;
224 case SDLK_KP_0: return KEYCODE_KP_0;
225 case SDLK_KP_1: return KEYCODE_KP_1;
226 case SDLK_KP_2: return KEYCODE_KP_2;
227 case SDLK_KP_3: return KEYCODE_KP_3;
228 case SDLK_KP_4: return KEYCODE_KP_4;
229 case SDLK_KP_5: return KEYCODE_KP_5;
230 case SDLK_KP_6: return KEYCODE_KP_6;
231 case SDLK_KP_7: return KEYCODE_KP_7;
232 case SDLK_KP_8: return KEYCODE_KP_8;
233 case SDLK_KP_9: return KEYCODE_KP_9;
234 case SDLK_KP_DIVIDE: return KEYCODE_KP_DIVIDE;
235 case SDLK_KP_MULTIPLY: return KEYCODE_KP_MULTIPLY;
236 case SDLK_KP_MINUS: return KEYCODE_KP_MINUS;
237 case SDLK_KP_PLUS: return KEYCODE_KP_PLUS;
238 case SDLK_KP_PERIOD: return KEYCODE_KP_PERIOD;
239 case SDLK_F1: return KEYCODE_F1;
240 case SDLK_F2: return KEYCODE_F2;
241 case SDLK_F3: return KEYCODE_F3;
242 case SDLK_F4: return KEYCODE_F4;
243 case SDLK_F5: return KEYCODE_F5;
244 case SDLK_F6: return KEYCODE_F6;
245 case SDLK_F7: return KEYCODE_F7;
246 case SDLK_F8: return KEYCODE_F8;
247 case SDLK_F9: return KEYCODE_F9;
248 case SDLK_F10: return KEYCODE_F10;
249 case SDLK_SPACE: return KEYCODE_SPACE;
250 case SDLK_BACKSPACE: return KEYCODE_BACKSPACE;
251 case SDLK_TAB: return KEYCODE_TAB;
252 case SDLK_KP_ENTER: return KEYCODE_KP_ENTER;
253 case SDLK_RETURN: return KEYCODE_RETURN;
254 case SDLK_ESCAPE: return KEYCODE_ESCAPE;
255 case SDLK_DELETE: return KEYCODE_DELETE;
256 case SDLK_INSERT: return KEYCODE_INSERT;
257 default: return KEYCODE_UNDEFINED;
261 static int key_ctrl = 0, key_f = 0, fullscreen = 0;
268 while (SDL_PollEvent(&event)) {
269 if (event.type == SDL_QUIT)
271 if (event.type == SDL_WINDOWEVENT) {
272 if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
273 resize_window_sdl(event.window.data1, event.window.data2);
275 if (event.type == SDL_KEYDOWN) {
276 switch (event.key.keysym.sym) {
278 if (key_ctrl && !key_f) {
281 SDL_SetWindowFullscreen(gl_window, 0);
282 SDL_ShowCursor(SDL_ENABLE);
284 SDL_SetWindowFullscreen(gl_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
285 SDL_ShowCursor(SDL_DISABLE);
296 keyboard_sdl(1, sdl2keycode(event.key.keysym.sym));
298 if (event.type == SDL_KEYUP) {
299 switch (event.key.keysym.sym) {
308 keyboard_sdl(0, sdl2keycode(event.key.keysym.sym));
317 SDL_GL_SwapWindow(gl_window);
324 SDL_DestroyWindow(gl_window);
328 /* clear OpenGL context */
330 SDL_GL_DeleteContext(gl_context);
334 /* exit SDL library */
335 if (audio_initialized) {
338 audio_initialized = 0;
340 if (sdl_initialized) {
346 uint32_t ticks_sdl(void)
348 return SDL_GetTicks();