Replace printf/fprintf with own print_info() / print_error() using SDL_log
[mercenary-reloaded.git] / src / libsdl / sdl.c
1 /* SDL handling
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <errno.h>
23 #include "print.h"
24 #include "sdl.h"
25 #include "opengl.h"
26
27 #define GL3_PROTOTYPES 1
28 #include <GL/glew.h>
29
30 static int sdl_initialized = 0;
31 static int audio_initialized = 0;
32 static SDL_Window *gl_window = NULL;
33 static SDL_GLContext gl_context = NULL;
34 static void (*keyboard_sdl)(int down, SDL_Keycode sym) = NULL;
35 static void (*audio_sdl)(float *data, int len) = NULL;
36
37 static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int len)
38 {
39         float audio_data[len / sizeof(float)];
40
41         SDL_memset(stream, 0, len);
42         audio_sdl(audio_data, len / sizeof(float));
43         SDL_MixAudio(stream, (Uint8 *)audio_data, len, SDL_MIX_MAXVOLUME);
44 }
45
46 int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, SDL_Keycode sym), void (*audio)(float *data, int len))
47 {
48         int rc;
49
50         keyboard_sdl = keyboard;
51         audio_sdl = audio;
52
53         /* init SDL library */
54         rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
55         if (rc < 0) {
56                 print_error("Failed to init SDL\n");
57                 goto error;
58         }
59         sdl_initialized = 1;
60
61         /* open window */
62         gl_window = SDL_CreateWindow(progname, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
63         if (!gl_window) {
64                 print_error("Failed to open SDL window: %s\n", SDL_GetError());
65                 rc = EIO;
66                 goto error;
67         }
68
69         /* create GL context */
70         gl_context = SDL_GL_CreateContext(gl_window);
71         if (!gl_context) {
72                 print_error("Failed to create SDL's OpenGL context: %s\n", SDL_GetError());
73                 rc = EIO;
74                 goto error;
75         }
76
77         rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
78         if (rc < 0) {
79                 print_error("Failed to set SDL's OpenGL context profile\n");
80                 goto error;
81         }
82
83         rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
84         if (rc < 0) {
85                 print_error("Failed to set SDL's OpenGL major version\n");
86                 goto error;
87         }
88         rc = SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
89         if (rc < 0) {
90                 print_error("Failed to set SDL's OpenGL minor version\n");
91                 goto error;
92         }
93
94         rc = SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
95         if (rc < 0) {
96                 print_error("Failed to set SDL's OpenGL doublebuffer\n");
97                 goto error;
98         }
99
100         rc = SDL_GL_SetSwapInterval(1);
101         if (rc < 0) {
102                 print_error("Failed to set SDL's OpenGL swap interval to VBLANK\n");
103                 goto error;
104         }
105
106 #ifndef __APPLE__
107         glewExperimental = GL_TRUE;
108         if (glewInit() != GLEW_OK) {
109                 print_error("Failed to init GLEW\n");
110                 goto error;
111         }
112 #endif
113
114         /* just in case */
115         glDisable(GL_DEPTH_TEST);
116         glDisable(GL_CULL_FACE);
117
118         /* open audio */
119         SDL_AudioSpec want, have;
120         SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */
121         want.freq = sound_samplerate;
122         want.format = AUDIO_F32; /* we always use float in this project */
123         want.channels = 1;
124         want.samples = sound_chunk; /* must be a power of two */
125         want.callback = audio_cb;
126         rc = SDL_OpenAudio(&want, &have);
127         if (rc < 0) {
128                 print_error("Failed to open audio\n");
129                 goto error;
130         } else if (have.format != want.format) {
131                 print_error("Failed to open audio with desired audio format\n");
132                 SDL_CloseAudio();
133                 rc = -EIO;
134                 goto error;
135         } else if (have.freq != want.freq) {
136                 print_error("Failed to open audio with desired sample rate\n");
137                 SDL_CloseAudio();
138                 rc = -EIO;
139                 goto error;
140         } else {
141                 SDL_PauseAudio(0);
142                 audio_initialized = 1;
143         }
144
145         return 0;
146
147 error:
148         exit_sdl();
149         return rc;
150 }
151
152 static int key_ctrl = 0, fullscreen = 0;
153
154 int event_sdl(void)
155 {
156         int quit = 0;
157         SDL_Event event;
158
159         while (SDL_PollEvent(&event)) {
160                 if (event.type == SDL_QUIT)
161                         quit = 1;
162                 if (event.type == SDL_WINDOWEVENT) {
163                         if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
164                                 resize_opengl(event.window.data1, event.window.data2);
165                 }
166                 if (event.type == SDL_KEYDOWN) {
167                         switch (event.key.keysym.sym) {
168                         case SDLK_f:
169                                 if (key_ctrl) {
170                                         if (fullscreen) {
171                                                 fullscreen = 0;
172                                                 SDL_SetWindowFullscreen(gl_window, 0);
173                                         } else {
174                                                 SDL_SetWindowFullscreen(gl_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
175                                                 fullscreen = 1;
176                                         }
177                                 }
178                                 break;
179                         case SDLK_LCTRL:
180                         case SDLK_RCTRL:
181                                 key_ctrl = 1;
182                                 break;
183                         }
184                         keyboard_sdl(1, event.key.keysym.sym);
185                 }
186                 if (event.type == SDL_KEYUP) {
187                         switch (event.key.keysym.sym) {
188                         case SDLK_LCTRL:
189                         case SDLK_RCTRL:
190                                 key_ctrl = 0;
191                                 break;
192                         }
193                         keyboard_sdl(0, event.key.keysym.sym);
194                 }
195         }
196
197         return quit;
198 }
199
200 void swap_sdl(void)
201 {
202         SDL_GL_SwapWindow(gl_window);
203 }
204
205 void exit_sdl(void)
206 {
207         /* close window */
208         if (gl_window) {
209                 SDL_DestroyWindow(gl_window);
210                 gl_window = NULL;
211         }
212
213         /* clear OpenGL context */
214         if (gl_context) {
215                 SDL_GL_DeleteContext(gl_context);
216                 gl_context = NULL;
217         }
218
219         /* exit SDL library */
220         if (audio_initialized) {
221                 SDL_PauseAudio(1);
222                 SDL_CloseAudio();
223                 audio_initialized = 0;
224         }
225         if (sdl_initialized) {
226                 SDL_Quit();
227                 sdl_initialized = 0;
228         }
229 }
230