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