Implement new shot name generation using a persistent index.
[neverball] / share / config.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <SDL.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <math.h>
21
22 #include "config.h"
23 #include "glext.h"
24 #include "vec3.h"
25 #include "sync.h"
26
27 /*---------------------------------------------------------------------------*/
28
29 /* Define the mkdir symbol. */
30
31 #ifdef _WIN32
32 #include <direct.h>
33 #else
34 #include <sys/stat.h>
35 #endif
36
37 /*---------------------------------------------------------------------------*/
38
39 static int   option_d[CONFIG_OPTION_D_COUNT];
40 static char *option_s[CONFIG_OPTION_S_COUNT];
41
42 static int dirty = 0;
43
44 /*---------------------------------------------------------------------------*/
45
46 static void config_key(const char *s, int i, int d)
47 {
48     int c;
49
50     config_set_d(i, d);
51
52     for (c = 0; c < SDLK_LAST; c++)
53         if (strcmp(s, SDL_GetKeyName((SDLKey) c)) == 0)
54         {
55             config_set_d(i, c);
56             break;
57         }
58 }
59
60 /*---------------------------------------------------------------------------*/
61
62 void config_init(void)
63 {
64     memset(option_d, 0, sizeof (option_d));
65     memset(option_s, 0, sizeof (option_s));
66
67     config_set_d(CONFIG_FULLSCREEN,           DEFAULT_FULLSCREEN);
68     config_set_d(CONFIG_WIDTH,                DEFAULT_WIDTH);
69     config_set_d(CONFIG_HEIGHT,               DEFAULT_HEIGHT);
70     config_set_d(CONFIG_STEREO,               DEFAULT_STEREO);
71     config_set_d(CONFIG_CAMERA,               DEFAULT_CAMERA);
72     config_set_d(CONFIG_TEXTURES,             DEFAULT_TEXTURES);
73     config_set_d(CONFIG_GEOMETRY,             DEFAULT_GEOMETRY);
74     config_set_d(CONFIG_REFLECTION,           DEFAULT_REFLECTION);
75     config_set_d(CONFIG_MULTISAMPLE,          DEFAULT_MULTISAMPLE);
76     config_set_d(CONFIG_MIPMAP,               DEFAULT_MIPMAP);
77     config_set_d(CONFIG_ANISO,                DEFAULT_ANISO);
78     config_set_d(CONFIG_BACKGROUND,           DEFAULT_BACKGROUND);
79     config_set_d(CONFIG_SHADOW,               DEFAULT_SHADOW);
80     config_set_d(CONFIG_AUDIO_BUFF,           DEFAULT_AUDIO_BUFF);
81     config_set_d(CONFIG_MOUSE_SENSE,          DEFAULT_MOUSE_SENSE);
82     config_set_d(CONFIG_MOUSE_INVERT,         DEFAULT_MOUSE_INVERT);
83     config_set_d(CONFIG_VSYNC,                DEFAULT_VSYNC);
84     config_set_d(CONFIG_NICE,                 DEFAULT_NICE);
85     config_set_d(CONFIG_FPS,                  DEFAULT_FPS);
86     config_set_d(CONFIG_SOUND_VOLUME,         DEFAULT_SOUND_VOLUME);
87     config_set_d(CONFIG_MUSIC_VOLUME,         DEFAULT_MUSIC_VOLUME);
88     config_set_d(CONFIG_JOYSTICK,             DEFAULT_JOYSTICK);
89     config_set_d(CONFIG_JOYSTICK_DEVICE,      DEFAULT_JOYSTICK_DEVICE);
90     config_set_d(CONFIG_JOYSTICK_AXIS_X,      DEFAULT_JOYSTICK_AXIS_X);
91     config_set_d(CONFIG_JOYSTICK_AXIS_Y,      DEFAULT_JOYSTICK_AXIS_Y);
92     config_set_d(CONFIG_JOYSTICK_BUTTON_A,    DEFAULT_JOYSTICK_BUTTON_A);
93     config_set_d(CONFIG_JOYSTICK_BUTTON_B,    DEFAULT_JOYSTICK_BUTTON_B);
94     config_set_d(CONFIG_JOYSTICK_BUTTON_L,    DEFAULT_JOYSTICK_BUTTON_L);
95     config_set_d(CONFIG_JOYSTICK_BUTTON_R,    DEFAULT_JOYSTICK_BUTTON_R);
96     config_set_d(CONFIG_JOYSTICK_BUTTON_EXIT, DEFAULT_JOYSTICK_BUTTON_EXIT);
97     config_set_d(CONFIG_JOYSTICK_CAMERA_1,    DEFAULT_JOYSTICK_CAMERA_1);
98     config_set_d(CONFIG_JOYSTICK_CAMERA_2,    DEFAULT_JOYSTICK_CAMERA_2);
99     config_set_d(CONFIG_JOYSTICK_CAMERA_3,    DEFAULT_JOYSTICK_CAMERA_3);
100     config_set_d(CONFIG_JOYSTICK_DPAD_L,      DEFAULT_JOYSTICK_DPAD_L);
101     config_set_d(CONFIG_JOYSTICK_DPAD_R,      DEFAULT_JOYSTICK_DPAD_R);
102     config_set_d(CONFIG_JOYSTICK_DPAD_U,      DEFAULT_JOYSTICK_DPAD_U);
103     config_set_d(CONFIG_JOYSTICK_DPAD_D,      DEFAULT_JOYSTICK_DPAD_D);
104     config_set_d(CONFIG_KEY_CAMERA_1,         DEFAULT_KEY_CAMERA_1);
105     config_set_d(CONFIG_KEY_CAMERA_2,         DEFAULT_KEY_CAMERA_2);
106     config_set_d(CONFIG_KEY_CAMERA_3,         DEFAULT_KEY_CAMERA_3);
107     config_set_d(CONFIG_KEY_CAMERA_R,         DEFAULT_KEY_CAMERA_R);
108     config_set_d(CONFIG_KEY_CAMERA_L,         DEFAULT_KEY_CAMERA_L);
109     config_set_d(CONFIG_VIEW_FOV,             DEFAULT_VIEW_FOV);
110     config_set_d(CONFIG_VIEW_DP,              DEFAULT_VIEW_DP);
111     config_set_d(CONFIG_VIEW_DC,              DEFAULT_VIEW_DC);
112     config_set_d(CONFIG_VIEW_DZ,              DEFAULT_VIEW_DZ);
113     config_set_d(CONFIG_ROTATE_FAST,          DEFAULT_ROTATE_FAST);
114     config_set_d(CONFIG_ROTATE_SLOW,          DEFAULT_ROTATE_SLOW);
115     config_set_s(CONFIG_PLAYER,               DEFAULT_PLAYER);
116     config_set_s(CONFIG_BALL,                 DEFAULT_BALL);
117     config_set_s(CONFIG_WIIMOTE_ADDR,         DEFAULT_WIIMOTE_ADDR);
118     config_set_d(CONFIG_CHEAT,                DEFAULT_CHEAT);
119     config_set_d(CONFIG_STATS,                DEFAULT_STATS);
120     config_set_d(CONFIG_UNIFORM,              DEFAULT_UNIFORM);
121     config_set_d(CONFIG_KEY_FORWARD,          DEFAULT_KEY_FORWARD);
122     config_set_d(CONFIG_KEY_BACKWARD,         DEFAULT_KEY_BACKWARD);
123     config_set_d(CONFIG_KEY_LEFT,             DEFAULT_KEY_LEFT);
124     config_set_d(CONFIG_KEY_RIGHT,            DEFAULT_KEY_RIGHT);
125     config_set_d(CONFIG_KEY_PAUSE,            DEFAULT_KEY_PAUSE);
126     config_set_d(CONFIG_KEY_RESTART,          DEFAULT_KEY_RESTART);
127     config_set_d(CONFIG_SCREENSHOT,           DEFAULT_SCREENSHOT);
128 }
129
130 void config_load(void)
131 {
132     FILE *fp;
133
134     if ((fp = fopen(config_user(USER_CONFIG_FILE), "r")))
135     {
136         char buf[MAXSTR];
137         char key[MAXSTR];
138         char val[MAXSTR];
139
140         while (fgets(buf, MAXSTR, fp))
141             if (sscanf(buf, "%s %s", key, val) == 2)
142             {
143                 if      (strcmp(key, "fullscreen")            == 0)
144                     config_set_d(CONFIG_FULLSCREEN,           atoi(val));
145                 else if (strcmp(key, "width")                 == 0)
146                     config_set_d(CONFIG_WIDTH,                atoi(val));
147                 else if (strcmp(key, "height")                == 0)
148                     config_set_d(CONFIG_HEIGHT,               atoi(val));
149                 else if (strcmp(key, "stereo")                == 0)
150                     config_set_d(CONFIG_STEREO,               atoi(val));
151                 else if (strcmp(key, "camera")                == 0)
152                     config_set_d(CONFIG_CAMERA,               atoi(val));
153                 else if (strcmp(key, "textures")              == 0)
154                     config_set_d(CONFIG_TEXTURES,             atoi(val));
155                 else if (strcmp(key, "geometry")              == 0)
156                     config_set_d(CONFIG_GEOMETRY,             atoi(val));
157                 else if (strcmp(key, "reflection")            == 0)
158                     config_set_d(CONFIG_REFLECTION,           atoi(val));
159                 else if (strcmp(key, "multisample")           == 0)
160                     config_set_d(CONFIG_MULTISAMPLE,          atoi(val));
161                 else if (strcmp(key, "mipmap")                == 0)
162                     config_set_d(CONFIG_MIPMAP,               atoi(val));
163                 else if (strcmp(key, "aniso")                 == 0)
164                     config_set_d(CONFIG_ANISO,                atoi(val));
165                 else if (strcmp(key, "background")            == 0)
166                     config_set_d(CONFIG_BACKGROUND,           atoi(val));
167                 else if (strcmp(key, "shadow")                == 0)
168                     config_set_d(CONFIG_SHADOW,               atoi(val));
169                 else if (strcmp(key, "audio_buff")            == 0)
170                     config_set_d(CONFIG_AUDIO_BUFF,           atoi(val));
171                 else if (strcmp(key, "mouse_sense")           == 0)
172                     config_set_d(CONFIG_MOUSE_SENSE,          atoi(val));
173                 else if (strcmp(key, "mouse_invert")          == 0)
174                     config_set_d(CONFIG_MOUSE_INVERT,         atoi(val));
175                 else if (strcmp(key, "vsync")                 == 0)
176                     config_set_d(CONFIG_VSYNC,                atoi(val));
177                 else if (strcmp(key, "nice")                  == 0)
178                     config_set_d(CONFIG_NICE,                 atoi(val));
179                 else if (strcmp(key, "fps")                   == 0)
180                     config_set_d(CONFIG_FPS,                  atoi(val));
181                 else if (strcmp(key, "sound_volume")          == 0)
182                     config_set_d(CONFIG_SOUND_VOLUME,         atoi(val));
183                 else if (strcmp(key, "music_volume")          == 0)
184                     config_set_d(CONFIG_MUSIC_VOLUME,         atoi(val));
185                 else if (strcmp(key, "joystick")              == 0)
186                     config_set_d(CONFIG_JOYSTICK,             atoi(val));
187                 else if (strcmp(key, "joystick_device")       == 0)
188                     config_set_d(CONFIG_JOYSTICK_DEVICE,      atoi(val));
189                 else if (strcmp(key, "joystick_axis_x")       == 0)
190                     config_set_d(CONFIG_JOYSTICK_AXIS_X,      atoi(val));
191                 else if (strcmp(key, "joystick_axis_y")       == 0)
192                     config_set_d(CONFIG_JOYSTICK_AXIS_Y,      atoi(val));
193                 else if (strcmp(key, "joystick_button_a")     == 0)
194                     config_set_d(CONFIG_JOYSTICK_BUTTON_A,    atoi(val));
195                 else if (strcmp(key, "joystick_button_b")     == 0)
196                     config_set_d(CONFIG_JOYSTICK_BUTTON_B,    atoi(val));
197                 else if (strcmp(key, "joystick_button_r")     == 0)
198                     config_set_d(CONFIG_JOYSTICK_BUTTON_R,    atoi(val));
199                 else if (strcmp(key, "joystick_button_l")     == 0)
200                     config_set_d(CONFIG_JOYSTICK_BUTTON_L,    atoi(val));
201                 else if (strcmp(key, "joystick_button_exit")  == 0)
202                     config_set_d(CONFIG_JOYSTICK_BUTTON_EXIT, atoi(val));
203                 else if (strcmp(key, "joystick_camera_1")     == 0)
204                     config_set_d(CONFIG_JOYSTICK_CAMERA_1,    atoi(val));
205                 else if (strcmp(key, "joystick_camera_2")     == 0)
206                     config_set_d(CONFIG_JOYSTICK_CAMERA_2,    atoi(val));
207                 else if (strcmp(key, "joystick_camera_3")     == 0)
208                     config_set_d(CONFIG_JOYSTICK_CAMERA_3,    atoi(val));
209                 else if (strcmp(key, "view_fov")              == 0)
210                     config_set_d(CONFIG_VIEW_FOV,             atoi(val));
211                 else if (strcmp(key, "view_dp")               == 0)
212                     config_set_d(CONFIG_VIEW_DP,              atoi(val));
213                 else if (strcmp(key, "view_dc")               == 0)
214                     config_set_d(CONFIG_VIEW_DC,              atoi(val));
215                 else if (strcmp(key, "view_dz")               == 0)
216                     config_set_d(CONFIG_VIEW_DZ,              atoi(val));
217                 else if (strcmp(key, "rotate_fast")           == 0)
218                     config_set_d(CONFIG_ROTATE_FAST,          atoi(val));
219                 else if (strcmp(key, "rotate_slow")           == 0)
220                     config_set_d(CONFIG_ROTATE_SLOW,          atoi(val));
221
222                 else if (strcmp(key, "key_forward")  == 0)
223                     config_key(val, CONFIG_KEY_FORWARD, DEFAULT_KEY_FORWARD);
224                 else if (strcmp(key, "key_backward")  == 0)
225                     config_key(val, CONFIG_KEY_BACKWARD, DEFAULT_KEY_BACKWARD);
226                 else if (strcmp(key, "key_left")  == 0)
227                     config_key(val, CONFIG_KEY_LEFT, DEFAULT_KEY_LEFT);
228                 else if (strcmp(key, "key_right")  == 0)
229                     config_key(val, CONFIG_KEY_RIGHT, DEFAULT_KEY_RIGHT);
230
231                 else if (strcmp(key, "key_camera_1")  == 0)
232                     config_key(val, CONFIG_KEY_CAMERA_1, DEFAULT_KEY_CAMERA_1);
233                 else if (strcmp(key, "key_camera_2")  == 0)
234                     config_key(val, CONFIG_KEY_CAMERA_2, DEFAULT_KEY_CAMERA_2);
235                 else if (strcmp(key, "key_camera_3")  == 0)
236                     config_key(val, CONFIG_KEY_CAMERA_3, DEFAULT_KEY_CAMERA_3);
237                 else if (strcmp(key, "key_camera_r")  == 0)
238                     config_key(val, CONFIG_KEY_CAMERA_R, DEFAULT_KEY_CAMERA_R);
239                 else if (strcmp(key, "key_camera_l")  == 0)
240                     config_key(val, CONFIG_KEY_CAMERA_L, DEFAULT_KEY_CAMERA_L);
241
242                 else if (strcmp(key, "key_pause")    == 0)
243                     config_key(val, CONFIG_KEY_PAUSE,   DEFAULT_KEY_PAUSE);
244                 else if (strcmp(key, "key_restart")  == 0)
245                     config_key(val, CONFIG_KEY_RESTART, DEFAULT_KEY_RESTART);
246
247                 else if (strcmp(key, "player") == 0)
248                     config_set_s(CONFIG_PLAYER, val);
249                 else if (strcmp(key, "ball_file") == 0)
250                     config_set_s(CONFIG_BALL, val);
251                 else if (strcmp(key, "wiimote_addr") == 0)
252                     config_set_s(CONFIG_WIIMOTE_ADDR, val);
253
254                 else if (strcmp(key, "cheat")   == 0)
255                     config_set_d(CONFIG_CHEAT, atoi(val));
256                 else if (strcmp(key, "stats")   == 0)
257                     config_set_d(CONFIG_STATS, atoi(val));
258                 else if (strcmp(key, "uniform") == 0)
259                     config_set_d(CONFIG_UNIFORM, atoi(val));
260                 else if (strcmp(key, "screenshot") == 0)
261                     config_set_d(CONFIG_SCREENSHOT, atoi(val));
262             }
263
264         fclose(fp);
265
266         dirty = 0;
267     }
268 }
269
270 void config_save(void)
271 {
272     FILE *fp;
273
274     if (dirty && (fp = fopen(config_user(USER_CONFIG_FILE), "w")))
275     {
276         fprintf(fp, "fullscreen           %d\n",
277                 option_d[CONFIG_FULLSCREEN]);
278         fprintf(fp, "width                %d\n",
279                 option_d[CONFIG_WIDTH]);
280         fprintf(fp, "height               %d\n",
281                 option_d[CONFIG_HEIGHT]);
282         fprintf(fp, "stereo               %d\n",
283                 option_d[CONFIG_STEREO]);
284         fprintf(fp, "camera               %d\n",
285                 option_d[CONFIG_CAMERA]);
286         fprintf(fp, "textures             %d\n",
287                 option_d[CONFIG_TEXTURES]);
288         fprintf(fp, "geometry             %d\n",
289                 option_d[CONFIG_GEOMETRY]);
290         fprintf(fp, "reflection           %d\n",
291                 option_d[CONFIG_REFLECTION]);
292         fprintf(fp, "multisample          %d\n",
293                 option_d[CONFIG_MULTISAMPLE]);
294         fprintf(fp, "mipmap               %d\n",
295                 option_d[CONFIG_MIPMAP]);
296         fprintf(fp, "aniso                %d\n",
297                 option_d[CONFIG_ANISO]);
298         fprintf(fp, "background           %d\n",
299                 option_d[CONFIG_BACKGROUND]);
300         fprintf(fp, "shadow               %d\n",
301                 option_d[CONFIG_SHADOW]);
302         fprintf(fp, "audio_buff           %d\n",
303                 option_d[CONFIG_AUDIO_BUFF]);
304         fprintf(fp, "mouse_sense          %d\n",
305                 option_d[CONFIG_MOUSE_SENSE]);
306         fprintf(fp, "mouse_invert         %d\n",
307                 option_d[CONFIG_MOUSE_INVERT]);
308         fprintf(fp, "vsync                %d\n",
309                 option_d[CONFIG_VSYNC]);
310         fprintf(fp, "nice                 %d\n",
311                 option_d[CONFIG_NICE]);
312         fprintf(fp, "fps                  %d\n",
313                 option_d[CONFIG_FPS]);
314         fprintf(fp, "sound_volume         %d\n",
315                 option_d[CONFIG_SOUND_VOLUME]);
316         fprintf(fp, "music_volume         %d\n",
317                 option_d[CONFIG_MUSIC_VOLUME]);
318         fprintf(fp, "joystick             %d\n",
319                 option_d[CONFIG_JOYSTICK]);
320         fprintf(fp, "joystick_device      %d\n",
321                 option_d[CONFIG_JOYSTICK_DEVICE]);
322         fprintf(fp, "joystick_axis_x      %d\n",
323                 option_d[CONFIG_JOYSTICK_AXIS_X]);
324         fprintf(fp, "joystick_axis_y      %d\n",
325                 option_d[CONFIG_JOYSTICK_AXIS_Y]);
326         fprintf(fp, "joystick_button_a    %d\n",
327                 option_d[CONFIG_JOYSTICK_BUTTON_A]);
328         fprintf(fp, "joystick_button_b    %d\n",
329                 option_d[CONFIG_JOYSTICK_BUTTON_B]);
330         fprintf(fp, "joystick_button_r    %d\n",
331                 option_d[CONFIG_JOYSTICK_BUTTON_R]);
332         fprintf(fp, "joystick_button_l    %d\n",
333                 option_d[CONFIG_JOYSTICK_BUTTON_L]);
334         fprintf(fp, "joystick_button_exit %d\n",
335                 option_d[CONFIG_JOYSTICK_BUTTON_EXIT]);
336         fprintf(fp, "joystick_camera_1    %d\n",
337                 option_d[CONFIG_JOYSTICK_CAMERA_1]);
338         fprintf(fp, "joystick_camera_2    %d\n",
339                 option_d[CONFIG_JOYSTICK_CAMERA_2]);
340         fprintf(fp, "joystick_camera_3    %d\n",
341                 option_d[CONFIG_JOYSTICK_CAMERA_3]);
342         fprintf(fp, "view_fov             %d\n",
343                 option_d[CONFIG_VIEW_FOV]);
344         fprintf(fp, "view_dp              %d\n",
345                 option_d[CONFIG_VIEW_DP]);
346         fprintf(fp, "view_dc              %d\n",
347                 option_d[CONFIG_VIEW_DC]);
348         fprintf(fp, "view_dz              %d\n",
349                 option_d[CONFIG_VIEW_DZ]);
350         fprintf(fp, "rotate_fast          %d\n",
351                 option_d[CONFIG_ROTATE_FAST]);
352         fprintf(fp, "rotate_slow          %d\n",
353                 option_d[CONFIG_ROTATE_SLOW]);
354         
355         fprintf(fp, "key_forward          %s\n",
356                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_FORWARD]));
357         fprintf(fp, "key_backward         %s\n",
358                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_BACKWARD]));
359         fprintf(fp, "key_left             %s\n",
360                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_LEFT]));
361         fprintf(fp, "key_right            %s\n",
362                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_RIGHT]));
363
364         fprintf(fp, "key_camera_1         %s\n",
365                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_1]));
366         fprintf(fp, "key_camera_2         %s\n",
367                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_2]));
368         fprintf(fp, "key_camera_3         %s\n",
369                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_3]));
370         fprintf(fp, "key_camera_r         %s\n",
371                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_R]));
372         fprintf(fp, "key_camera_l         %s\n",
373                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_L]));
374
375         fprintf(fp, "key_pause            %s\n",
376                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_PAUSE]));
377         fprintf(fp, "key_restart          %s\n",
378                 SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_RESTART]));
379
380         if (strlen(option_s[CONFIG_PLAYER]) > 0)
381             fprintf(fp, "player       %s\n", option_s[CONFIG_PLAYER]);
382         if (strlen(option_s[CONFIG_BALL]) > 0)
383             fprintf(fp, "ball_file    %s\n", option_s[CONFIG_BALL]);
384         if (strlen(option_s[CONFIG_WIIMOTE_ADDR]) > 0)
385             fprintf(fp, "wiimote_addr %s\n", option_s[CONFIG_WIIMOTE_ADDR]);
386
387         fprintf(fp, "stats                %d\n",
388                 option_d[CONFIG_STATS]);
389         fprintf(fp, "uniform              %d\n",
390                 option_d[CONFIG_UNIFORM]);
391         fprintf(fp, "screenshot           %d\n",
392             option_d[CONFIG_SCREENSHOT]);
393
394         if (config_cheat())
395             fprintf(fp, "cheat                %d\n", option_d[CONFIG_CHEAT]);
396
397         fclose(fp);
398     }
399
400     dirty = 0;
401 }
402
403 /*---------------------------------------------------------------------------*/
404
405 int check_extension(const char *needle)
406 {
407     const GLubyte *haystack, *c;
408
409     /* Search for the given string in the OpenGL extension strings. */
410
411     for (haystack = glGetString(GL_EXTENSIONS); *haystack; haystack++)
412     {
413         for (c = (const GLubyte *) needle; *c && *haystack; c++, haystack++)
414             if (*c != *haystack)
415                 break;
416
417         if ((*c == 0) && (*haystack == ' ' || *haystack == '\0'))
418             return 1;
419     }
420
421     return 0;
422 }
423
424 int config_mode(int f, int w, int h)
425 {
426     int stereo  = config_get_d(CONFIG_STEREO)      ? 1 : 0;
427     int stencil = config_get_d(CONFIG_REFLECTION)  ? 1 : 0;
428     int buffers = config_get_d(CONFIG_MULTISAMPLE) ? 1 : 0;
429     int samples = config_get_d(CONFIG_MULTISAMPLE);
430
431     SDL_GL_SetAttribute(SDL_GL_STEREO,             stereo);
432     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,       stencil);
433     SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, buffers);
434     SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
435
436     /* Try to set the currently specified mode. */
437
438     if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL | (f ? SDL_FULLSCREEN : 0)))
439     {
440         config_set_d(CONFIG_FULLSCREEN, f);
441         config_set_d(CONFIG_WIDTH,      w);
442         config_set_d(CONFIG_HEIGHT,     h);
443
444         glViewport(0, 0, w, h);
445         glClearColor(0.0f, 0.0f, 0.1f, 0.0f);
446
447         glEnable(GL_NORMALIZE);
448         glEnable(GL_CULL_FACE);
449         glEnable(GL_DEPTH_TEST);
450         glEnable(GL_TEXTURE_2D);
451         glEnable(GL_LIGHTING);
452         glEnable(GL_BLEND);
453
454         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,
455                       GL_SEPARATE_SPECULAR_COLOR);
456         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
457
458         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
459         glDepthFunc(GL_LEQUAL);
460
461         if (config_get_d(CONFIG_VSYNC))
462             sync_init();
463
464         /* If GL supports multisample, and SDL got a multisample buffer... */
465
466 #ifdef GL_ARB_multisample
467         if (check_extension("ARB_multisample"))
468         {
469             SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers);
470             if (buffers)
471                 glEnable(GL_MULTISAMPLE_ARB);
472         }
473 #endif
474
475         return 1;
476     }
477
478     /* If the mode failed, try it without stereo. */
479
480     else if (stereo)
481     {
482         config_set_d(CONFIG_STEREO, 0);
483         return config_mode(f, w, h);
484     }
485
486     /* If the mode failed, try decreasing the level of multisampling. */
487
488     else if (buffers)
489     {
490         config_set_d(CONFIG_MULTISAMPLE, samples / 2);
491         return config_mode(f, w, h);
492     }
493
494     /* If that mode failed, try it without reflections. */
495
496     else if (stencil)
497     {
498         config_set_d(CONFIG_REFLECTION, 0);
499         return config_mode(f, w, h);
500     }
501
502     /* If THAT mode failed, punt. */
503
504     return 0;
505 }
506
507 /*---------------------------------------------------------------------------*/
508
509 static float ms     = 0;
510 static int   fps    = 0;
511 static int   last   = 0;
512 static int   ticks  = 0;
513 static int   frames = 0;
514
515 int  config_perf(void)
516 {
517     return fps;
518 }
519
520 void config_swap(void)
521 {
522     int dt;
523
524     SDL_GL_SwapBuffers();
525
526     /* Accumulate time passed and frames rendered. */
527
528     dt = (int) SDL_GetTicks() - last;
529
530     frames +=  1;
531     ticks  += dt;
532     last   += dt;
533
534     /* Average over 250ms. */
535
536     if (ticks > 1000)
537     {
538         /* Round the frames-per-second value to the nearest integer. */
539
540         double k = 1000.0 * frames / ticks;
541         double f = floor(k);
542         double c = ceil (k);
543
544         /* Compute frame time and frames-per-second stats. */
545
546         fps = (int) ((c - k < k - f) ? c : f);
547         ms  = (float) ticks / (float) frames;
548
549         /* Reset the counters for the next update. */
550
551         frames = 0;
552         ticks  = 0;
553
554         /* Output statistics if configured. */
555
556         if (option_d[CONFIG_STATS])
557             fprintf(stdout, "%4d %8.4f\n", fps, ms);
558     }
559 }
560
561 /*---------------------------------------------------------------------------*/
562
563 void config_set_d(int i, int d)
564 {
565     option_d[i] = d;
566     dirty = 1;
567 }
568
569 void config_tgl_d(int i)
570 {
571     option_d[i] = (option_d[i] ? 0 : 1);
572     dirty = 1;
573 }
574
575 int config_tst_d(int i, int d)
576 {
577     return (option_d[i] == d) ? 1 : 0;
578 }
579
580 int config_get_d(int i)
581 {
582     return option_d[i];
583 }
584
585 /*---------------------------------------------------------------------------*/
586
587 void config_set_s(int i, const char *src)
588 {
589     int len = (int) strlen(src);
590
591     if (option_s[i])
592         free(option_s[i]);
593
594     if ((option_s[i] = (char *) malloc(len + 1)))
595         strncpy(option_s[i], src, len + 1);
596
597     dirty = 1;
598 }
599
600 void config_get_s(int i, char *dst, int len)
601 {
602     strncpy(dst, option_s[i], len);
603 }
604
605 /*---------------------------------------------------------------------------*/
606
607 static int grabbed = 0;
608
609 void config_set_grab(int w)
610 {
611     if (w)
612     {
613         SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
614
615         SDL_WarpMouse(config_get_d(CONFIG_WIDTH)  / 2,
616                       config_get_d(CONFIG_HEIGHT) / 2);
617
618         SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
619     }
620
621     SDL_WM_GrabInput(SDL_GRAB_ON);
622     SDL_ShowCursor(SDL_DISABLE);
623
624     grabbed = 1;
625 }
626
627 void config_clr_grab(void)
628 {
629     SDL_WM_GrabInput(SDL_GRAB_OFF);
630     SDL_ShowCursor(SDL_ENABLE);
631     grabbed = 0;
632 }
633
634 int  config_get_grab(void)
635 {
636     return grabbed;
637 }
638
639 /*---------------------------------------------------------------------------*/
640
641 int config_cheat(void)
642 {
643     return config_get_d(CONFIG_CHEAT);
644 }
645
646 void config_set_cheat(void)
647 {
648     config_set_d(CONFIG_CHEAT, 1);
649 }
650
651 void config_clr_cheat(void)
652 {
653     config_set_d(CONFIG_CHEAT, 0);
654 }
655
656 /*---------------------------------------------------------------------------*/
657
658 int config_screenshot(void)
659 {
660     return ++option_d[CONFIG_SCREENSHOT];
661 }
662
663 /*---------------------------------------------------------------------------*/
664
665 void config_push_persp(float fov, float n, float f)
666 {
667     GLdouble m[4][4];
668
669     GLdouble r = fov / 2 * V_PI / 180;
670     GLdouble s = sin(r);
671     GLdouble c = cos(r) / s;
672
673     GLdouble a = ((GLdouble) option_d[CONFIG_WIDTH] /
674                   (GLdouble) option_d[CONFIG_HEIGHT]);
675
676     glMatrixMode(GL_PROJECTION);
677     {
678         glPushMatrix();
679         glLoadIdentity();
680
681         m[0][0] =  c/a;
682         m[0][1] =  0.0;
683         m[0][2] =  0.0;
684         m[0][3] =  0.0;
685         m[1][0] =  0.0;
686         m[1][1] =    c;
687         m[1][2] =  0.0;
688         m[1][3] =  0.0;
689         m[2][0] =  0.0;
690         m[2][1] =  0.0;
691         m[2][2] = -(f + n) / (f - n);
692         m[2][3] = -1.0;
693         m[3][0] =  0.0;
694         m[3][1] =  0.0;
695         m[3][2] = -2.0 * n * f / (f - n);
696         m[3][3] =  0.0;
697
698         glMultMatrixd(&m[0][0]);
699     }
700     glMatrixMode(GL_MODELVIEW);
701 }
702
703 void config_push_ortho(void)
704 {
705     GLdouble w = (GLdouble) option_d[CONFIG_WIDTH];
706     GLdouble h = (GLdouble) option_d[CONFIG_HEIGHT];
707
708     glMatrixMode(GL_PROJECTION);
709     {
710         glPushMatrix();
711         glLoadIdentity();
712         glOrtho(0.0, w, 0.0, h, -1.0, +1.0);
713     }
714     glMatrixMode(GL_MODELVIEW);
715 }
716
717 void config_pop_matrix(void)
718 {
719     glMatrixMode(GL_PROJECTION);
720     {
721         glPopMatrix();
722     }
723     glMatrixMode(GL_MODELVIEW);
724 }
725
726 void config_clear(void)
727 {
728     if (option_d[CONFIG_REFLECTION])
729         glClear(GL_COLOR_BUFFER_BIT |
730                 GL_DEPTH_BUFFER_BIT |
731                 GL_STENCIL_BUFFER_BIT);
732     else
733         glClear(GL_COLOR_BUFFER_BIT |
734                 GL_DEPTH_BUFFER_BIT);
735 }
736
737 /*---------------------------------------------------------------------------*/