Initial import.
[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 <SDL_mixer.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <math.h>
22
23 #include "config.h"
24 #include "glext.h"
25 #include "vec3.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(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, CONFIG_OPTION_D_COUNT * sizeof (int));
65     memset(option_s, 0, CONFIG_OPTION_S_COUNT * sizeof (char *));
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_BACKGROUND,           DEFAULT_BACKGROUND);
76     config_set_d(CONFIG_SHADOW,               DEFAULT_SHADOW);
77     config_set_d(CONFIG_AUDIO_RATE,           DEFAULT_AUDIO_RATE);
78     config_set_d(CONFIG_AUDIO_BUFF,           DEFAULT_AUDIO_BUFF);
79     config_set_d(CONFIG_MOUSE_SENSE,          DEFAULT_MOUSE_SENSE);
80     config_set_d(CONFIG_MOUSE_INVERT,         DEFAULT_MOUSE_INVERT);
81     config_set_d(CONFIG_NICE,                 DEFAULT_NICE);
82     config_set_d(CONFIG_FPS,                  DEFAULT_FPS);
83     config_set_d(CONFIG_SOUND_VOLUME,         DEFAULT_SOUND_VOLUME);
84     config_set_d(CONFIG_MUSIC_VOLUME,         DEFAULT_MUSIC_VOLUME);
85     config_set_d(CONFIG_JOYSTICK,             DEFAULT_JOYSTICK);
86     config_set_d(CONFIG_JOYSTICK_DEVICE,      DEFAULT_JOYSTICK_DEVICE);
87     config_set_d(CONFIG_JOYSTICK_AXIS_X,      DEFAULT_JOYSTICK_AXIS_X);
88     config_set_d(CONFIG_JOYSTICK_AXIS_Y,      DEFAULT_JOYSTICK_AXIS_Y);
89     config_set_d(CONFIG_JOYSTICK_BUTTON_A,    DEFAULT_JOYSTICK_BUTTON_A);
90     config_set_d(CONFIG_JOYSTICK_BUTTON_B,    DEFAULT_JOYSTICK_BUTTON_B);
91     config_set_d(CONFIG_JOYSTICK_BUTTON_L,    DEFAULT_JOYSTICK_BUTTON_L);
92     config_set_d(CONFIG_JOYSTICK_BUTTON_R,    DEFAULT_JOYSTICK_BUTTON_R);
93     config_set_d(CONFIG_JOYSTICK_BUTTON_EXIT, DEFAULT_JOYSTICK_BUTTON_EXIT);
94     config_set_d(CONFIG_JOYSTICK_CAMERA_1,    DEFAULT_JOYSTICK_CAMERA_1);
95     config_set_d(CONFIG_JOYSTICK_CAMERA_2,    DEFAULT_JOYSTICK_CAMERA_2);
96     config_set_d(CONFIG_JOYSTICK_CAMERA_3,    DEFAULT_JOYSTICK_CAMERA_3);
97     config_set_d(CONFIG_KEY_CAMERA_1,         DEFAULT_KEY_CAMERA_1);
98     config_set_d(CONFIG_KEY_CAMERA_2,         DEFAULT_KEY_CAMERA_2);
99     config_set_d(CONFIG_KEY_CAMERA_3,         DEFAULT_KEY_CAMERA_3);
100     config_set_d(CONFIG_KEY_CAMERA_R,         DEFAULT_KEY_CAMERA_R);
101     config_set_d(CONFIG_KEY_CAMERA_L,         DEFAULT_KEY_CAMERA_L);
102     config_set_d(CONFIG_VIEW_FOV,             DEFAULT_VIEW_FOV);
103     config_set_d(CONFIG_VIEW_DP,              DEFAULT_VIEW_DP);
104     config_set_d(CONFIG_VIEW_DC,              DEFAULT_VIEW_DC);
105     config_set_d(CONFIG_VIEW_DZ,              DEFAULT_VIEW_DZ);
106     config_set_d(CONFIG_ROTATE_FAST,          DEFAULT_ROTATE_FAST);
107     config_set_d(CONFIG_ROTATE_SLOW,          DEFAULT_ROTATE_SLOW);
108     config_set_s(CONFIG_PLAYER,               DEFAULT_PLAYER);
109     config_set_s(CONFIG_BALL,                 DEFAULT_BALL);
110     config_set_s(CONFIG_COIN,                 DEFAULT_COIN);
111 }
112
113 void config_load(void)
114 {
115     FILE *fp;
116
117     if ((fp = fopen(config_user(USER_CONFIG_FILE), "r")))
118     {
119         char buf[MAXSTR];
120         char key[MAXSTR];
121         char val[MAXSTR];
122
123         while (fgets(buf, MAXSTR, fp))
124             if (sscanf(buf, "%s %s", key, val) == 2)
125             {
126                 if      (strcmp(key, "fullscreen")            == 0)
127                     config_set_d(CONFIG_FULLSCREEN,           atoi(val));
128                 else if (strcmp(key, "width")                 == 0)
129                     config_set_d(CONFIG_WIDTH,                atoi(val));
130                 else if (strcmp(key, "height")                == 0)
131                     config_set_d(CONFIG_HEIGHT,               atoi(val));
132                 else if (strcmp(key, "stereo")                == 0)
133                     config_set_d(CONFIG_STEREO,               atoi(val));
134                 else if (strcmp(key, "camera")                == 0)
135                     config_set_d(CONFIG_CAMERA,               atoi(val));
136                 else if (strcmp(key, "textures")              == 0)
137                     config_set_d(CONFIG_TEXTURES,             atoi(val));
138                 else if (strcmp(key, "geometry")              == 0)
139                     config_set_d(CONFIG_GEOMETRY,             atoi(val));
140                 else if (strcmp(key, "reflection")            == 0)
141                     config_set_d(CONFIG_REFLECTION,           atoi(val));
142                 else if (strcmp(key, "background")            == 0)
143                     config_set_d(CONFIG_BACKGROUND,           atoi(val));
144                 else if (strcmp(key, "shadow")                == 0)
145                     config_set_d(CONFIG_SHADOW,               atoi(val));
146                 else if (strcmp(key, "audio_rate")            == 0)
147                     config_set_d(CONFIG_AUDIO_RATE,           atoi(val));
148                 else if (strcmp(key, "audio_buff")            == 0)
149                     config_set_d(CONFIG_AUDIO_BUFF,           atoi(val));
150                 else if (strcmp(key, "mouse_sense")           == 0)
151                     config_set_d(CONFIG_MOUSE_SENSE,          atoi(val));
152                 else if (strcmp(key, "mouse_invert")          == 0)
153                     config_set_d(CONFIG_MOUSE_INVERT,         atoi(val));
154                 else if (strcmp(key, "nice")                  == 0)
155                     config_set_d(CONFIG_NICE,                 atoi(val));
156                 else if (strcmp(key, "fps")                   == 0)
157                     config_set_d(CONFIG_FPS,                  atoi(val));
158                 else if (strcmp(key, "sound_volume")          == 0)
159                     config_set_d(CONFIG_SOUND_VOLUME,         atoi(val));
160                 else if (strcmp(key, "music_volume")          == 0)
161                     config_set_d(CONFIG_MUSIC_VOLUME,         atoi(val));
162                 else if (strcmp(key, "joystick")              == 0)
163                     config_set_d(CONFIG_JOYSTICK,             atoi(val));
164                 else if (strcmp(key, "joystick_device")       == 0)
165                     config_set_d(CONFIG_JOYSTICK_DEVICE,      atoi(val));
166                 else if (strcmp(key, "joystick_axis_x")       == 0)
167                     config_set_d(CONFIG_JOYSTICK_AXIS_X,      atoi(val));
168                 else if (strcmp(key, "joystick_axis_y")       == 0)
169                     config_set_d(CONFIG_JOYSTICK_AXIS_Y,      atoi(val));
170                 else if (strcmp(key, "joystick_button_a")     == 0)
171                     config_set_d(CONFIG_JOYSTICK_BUTTON_A,    atoi(val));
172                 else if (strcmp(key, "joystick_button_b")     == 0)
173                     config_set_d(CONFIG_JOYSTICK_BUTTON_B,    atoi(val));
174                 else if (strcmp(key, "joystick_button_r")     == 0)
175                     config_set_d(CONFIG_JOYSTICK_BUTTON_R,    atoi(val));
176                 else if (strcmp(key, "joystick_button_l")     == 0)
177                     config_set_d(CONFIG_JOYSTICK_BUTTON_L,    atoi(val));
178                 else if (strcmp(key, "joystick_button_exit")  == 0)
179                     config_set_d(CONFIG_JOYSTICK_BUTTON_EXIT, atoi(val));
180                 else if (strcmp(key, "joystick_camera_1")     == 0)
181                     config_set_d(CONFIG_JOYSTICK_CAMERA_1,    atoi(val));
182                 else if (strcmp(key, "joystick_camera_2")     == 0)
183                     config_set_d(CONFIG_JOYSTICK_CAMERA_2,    atoi(val));
184                 else if (strcmp(key, "joystick_camera_3")     == 0)
185                     config_set_d(CONFIG_JOYSTICK_CAMERA_3,    atoi(val));
186                 else if (strcmp(key, "view_fov")              == 0)
187                     config_set_d(CONFIG_VIEW_FOV,             atoi(val));
188                 else if (strcmp(key, "view_dp")               == 0)
189                     config_set_d(CONFIG_VIEW_DP,              atoi(val));
190                 else if (strcmp(key, "view_dc")               == 0)
191                     config_set_d(CONFIG_VIEW_DC,              atoi(val));
192                 else if (strcmp(key, "view_dz")               == 0)
193                     config_set_d(CONFIG_VIEW_DZ,              atoi(val));
194                 else if (strcmp(key, "rotate_fast")           == 0)
195                     config_set_d(CONFIG_ROTATE_FAST,          atoi(val));
196                 else if (strcmp(key, "rotate_slow")           == 0)
197                     config_set_d(CONFIG_ROTATE_SLOW,          atoi(val));
198
199                 else if (strcmp(key, "key_camera_1")  == 0)
200                     config_key(val, CONFIG_KEY_CAMERA_1, DEFAULT_KEY_CAMERA_1);
201                 else if (strcmp(key, "key_camera_2")  == 0)
202                     config_key(val, CONFIG_KEY_CAMERA_2, DEFAULT_KEY_CAMERA_2);
203                 else if (strcmp(key, "key_camera_3")  == 0)
204                     config_key(val, CONFIG_KEY_CAMERA_3, DEFAULT_KEY_CAMERA_3);
205                 else if (strcmp(key, "key_camera_r")  == 0)
206                     config_key(val, CONFIG_KEY_CAMERA_R, DEFAULT_KEY_CAMERA_R);
207                 else if (strcmp(key, "key_camera_l")  == 0)
208                     config_key(val, CONFIG_KEY_CAMERA_L, DEFAULT_KEY_CAMERA_L);
209
210                 else if (strcmp(key, "player") == 0)
211                     config_set_s(CONFIG_PLAYER, val);
212                 else if (strcmp(key, "ball")   == 0)
213                     config_set_s(CONFIG_BALL,   val);
214                 else if (strcmp(key, "coin")   == 0)
215                     config_set_s(CONFIG_COIN,   val);
216             }
217
218         fclose(fp);
219
220         dirty = 0;
221     }
222 }
223
224 void config_save(void)
225 {
226     FILE *fp;
227
228     if (dirty && (fp = fopen(config_user(USER_CONFIG_FILE), "w")))
229     {
230         fprintf(fp, "fullscreen           %d\n",
231                 option_d[CONFIG_FULLSCREEN]);
232         fprintf(fp, "width                %d\n",
233                 option_d[CONFIG_WIDTH]);
234         fprintf(fp, "height               %d\n",
235                 option_d[CONFIG_HEIGHT]);
236         fprintf(fp, "stereo               %d\n",
237                 option_d[CONFIG_STEREO]);
238         fprintf(fp, "camera               %d\n",
239                 option_d[CONFIG_CAMERA]);
240         fprintf(fp, "textures             %d\n",
241                 option_d[CONFIG_TEXTURES]);
242         fprintf(fp, "geometry             %d\n",
243                 option_d[CONFIG_GEOMETRY]);
244         fprintf(fp, "reflection           %d\n",
245                 option_d[CONFIG_REFLECTION]);
246         fprintf(fp, "background           %d\n",
247                 option_d[CONFIG_BACKGROUND]);
248         fprintf(fp, "shadow               %d\n",
249                 option_d[CONFIG_SHADOW]);
250         fprintf(fp, "audio_rate           %d\n",
251                 option_d[CONFIG_AUDIO_RATE]);
252         fprintf(fp, "audio_buff           %d\n",
253                 option_d[CONFIG_AUDIO_BUFF]);
254         fprintf(fp, "mouse_sense          %d\n",
255                 option_d[CONFIG_MOUSE_SENSE]);
256         fprintf(fp, "mouse_invert         %d\n",
257                 option_d[CONFIG_MOUSE_INVERT]);
258         fprintf(fp, "nice                 %d\n",
259                 option_d[CONFIG_NICE]);
260         fprintf(fp, "fps                  %d\n",
261                 option_d[CONFIG_FPS]);
262         fprintf(fp, "sound_volume         %d\n",
263                 option_d[CONFIG_SOUND_VOLUME]);
264         fprintf(fp, "music_volume         %d\n",
265                 option_d[CONFIG_MUSIC_VOLUME]);
266         fprintf(fp, "joystick             %d\n",
267                 option_d[CONFIG_JOYSTICK]);
268         fprintf(fp, "joystick_device      %d\n",
269                 option_d[CONFIG_JOYSTICK_DEVICE]);
270         fprintf(fp, "joystick_axis_x      %d\n",
271                 option_d[CONFIG_JOYSTICK_AXIS_X]);
272         fprintf(fp, "joystick_axis_y      %d\n",
273                 option_d[CONFIG_JOYSTICK_AXIS_Y]);
274         fprintf(fp, "joystick_button_a    %d\n",
275                 option_d[CONFIG_JOYSTICK_BUTTON_A]);
276         fprintf(fp, "joystick_button_b    %d\n",
277                 option_d[CONFIG_JOYSTICK_BUTTON_B]);
278         fprintf(fp, "joystick_button_r    %d\n",
279                 option_d[CONFIG_JOYSTICK_BUTTON_R]);
280         fprintf(fp, "joystick_button_l    %d\n",
281                 option_d[CONFIG_JOYSTICK_BUTTON_L]);
282         fprintf(fp, "joystick_button_exit %d\n",
283                 option_d[CONFIG_JOYSTICK_BUTTON_EXIT]);
284         fprintf(fp, "joystick_camera_1    %d\n",
285                 option_d[CONFIG_JOYSTICK_CAMERA_1]);
286         fprintf(fp, "joystick_camera_2    %d\n",
287                 option_d[CONFIG_JOYSTICK_CAMERA_2]);
288         fprintf(fp, "joystick_camera_3    %d\n",
289                 option_d[CONFIG_JOYSTICK_CAMERA_3]);
290         fprintf(fp, "view_fov             %d\n",
291                 option_d[CONFIG_VIEW_FOV]);
292         fprintf(fp, "view_dp              %d\n",
293                 option_d[CONFIG_VIEW_DP]);
294         fprintf(fp, "view_dc              %d\n",
295                 option_d[CONFIG_VIEW_DC]);
296         fprintf(fp, "view_dz              %d\n",
297                 option_d[CONFIG_VIEW_DZ]);
298         fprintf(fp, "rotate_fast          %d\n",
299                 option_d[CONFIG_ROTATE_FAST]);
300         fprintf(fp, "rotate_slow          %d\n",
301                 option_d[CONFIG_ROTATE_SLOW]);
302
303         fprintf(fp, "key_camera_1         %s\n",
304                 SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_1]));
305         fprintf(fp, "key_camera_2         %s\n",
306                 SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_2]));
307         fprintf(fp, "key_camera_3         %s\n",
308                 SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_3]));
309         fprintf(fp, "key_camera_r         %s\n",
310                 SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_R]));
311         fprintf(fp, "key_camera_l         %s\n",
312                 SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_L]));
313
314         fprintf(fp, "player               %s\n", option_s[CONFIG_PLAYER]);
315         fprintf(fp, "ball                 %s\n", option_s[CONFIG_BALL]);
316         fprintf(fp, "coin                 %s\n", option_s[CONFIG_COIN]);
317
318         fclose(fp);
319     }
320
321     dirty = 0;
322 }
323
324 /*---------------------------------------------------------------------------*/
325
326 int config_mode(int f, int w, int h)
327 {
328     int stereo  = config_get_d(CONFIG_STEREO)     ? 1 : 0;
329     int stencil = config_get_d(CONFIG_REFLECTION) ? 1 : 0;
330
331     SDL_GL_SetAttribute(SDL_GL_STEREO,       stereo);
332     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencil);
333
334     /* Try to set the currently specified mode. */
335
336     if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL | (f ? SDL_FULLSCREEN : 0)))
337     {
338         option_d[CONFIG_FULLSCREEN] = f;
339         option_d[CONFIG_WIDTH]      = w;
340         option_d[CONFIG_HEIGHT]     = h;
341         option_d[CONFIG_SHADOW]     = option_d[CONFIG_SHADOW];
342
343         glViewport(0, 0, w, h);
344         glClearColor(0.0f, 0.0f, 0.1f, 0.0f);
345
346         glEnable(GL_NORMALIZE);
347         glEnable(GL_CULL_FACE);
348         glEnable(GL_DEPTH_TEST);
349         glEnable(GL_TEXTURE_2D);
350         glEnable(GL_LIGHTING);
351
352         return 1;
353     }
354
355     /* If the mode failed, try it without stereo. */
356
357     else if (stereo)
358     {
359         config_set_d(CONFIG_STEREO, 0);
360         return config_mode(f, w, h);
361     }
362
363     /* If that mode failed, try it without reflections. */
364
365     else if (stencil)
366     {
367         config_set_d(CONFIG_REFLECTION, 0);
368         return config_mode(f, w, h);
369     }
370
371     /* If THAT mode failed, punt. */
372
373     return 0;
374 }
375
376 /*---------------------------------------------------------------------------*/
377
378 static char data_path[MAXSTR];
379 static char user_path[MAXSTR];
380
381 /*
382  * Given  a path  and a  file name  relative to  that path,  create an
383  * absolute path name and return a temporary pointer to it.
384  */
385 static const char *config_file(const char *path, const char *file)
386 {
387     static char absolute[MAXSTR];
388
389     size_t d = strlen(path);
390
391     strncpy(absolute, path, MAXSTR - 1);
392     strncat(absolute, "/",  MAXSTR - d - 1);
393     strncat(absolute, file, MAXSTR - d - 2);
394
395     return absolute;
396 }
397
398 static int config_test(const char *path, const char *file)
399 {
400     if (file)
401     {
402         FILE *fp;
403
404         if ((fp = fopen(config_file(path, file), "r")))
405         {
406             fclose(fp);
407             return 1;
408         }
409         return 0;
410     }
411     return 1;
412 }
413
414 const char *config_data(const char *file)
415 {
416     return config_file(data_path, file);
417 }
418
419 const char *config_user(const char *file)
420 {
421     return config_file(user_path, file);
422 }
423
424 /*---------------------------------------------------------------------------*/
425
426 /*
427  * Attempt to find  the game data directory.  Search  the command line
428  * paramater,  the environment,  and the  hard-coded default,  in that
429  * order.  Confirm it by checking for presense of the named file.
430  */
431 int config_data_path(const char *path, const char *file)
432 {
433     char *dir;
434
435     if (path && config_test(path, file))
436     {
437         strncpy(data_path, path, MAXSTR);
438         return 1;
439     }
440
441     if ((dir = getenv("NEVERBALL_DATA")) && config_test(dir, file))
442     {
443         strncpy(data_path, dir, MAXSTR);
444         return 1;
445     }
446
447     if (CONFIG_DATA && config_test(CONFIG_DATA, file))
448     {
449         strncpy(data_path, CONFIG_DATA, MAXSTR);
450         return 1;
451     }
452
453     return 0;
454 }
455
456 /*
457  * Determine the location of  the user's home directory.  Ensure there
458  * is a  directory there for  storing configuration, high  scores, and
459  * replays.
460  *
461  * HACK: under Windows just assume the user has permission to write to
462  * the data  directory.  This is  more reliable than trying  to devine
463  * anything reasonable from the environment.
464  */
465 int config_user_path(const char *file)
466 {
467 #ifdef _WIN32
468     size_t d = strlen(CONFIG_USER);
469
470     strncpy(user_path, data_path,   MAXSTR - 1);
471     strncat(user_path, "\\",        MAXSTR - d - 1);
472     strncat(user_path, CONFIG_USER, MAXSTR - d - 2);
473
474     if ((mkdir(user_path) == 0) || (errno = EEXIST))
475         if (config_test(user_path, file))
476             return 1;
477 #else
478     char *dir;
479
480     if ((dir = getenv("HOME")))
481     {
482         size_t d = strlen(dir);
483
484         strncpy(user_path, getenv("HOME"), MAXSTR - 1);
485         strncat(user_path, "/",            MAXSTR - d - 1);
486         strncat(user_path, CONFIG_USER,    MAXSTR - d - 2);
487     }
488
489     if ((mkdir(user_path, 0777) == 0) || (errno = EEXIST))
490         if (config_test(user_path, file))
491             return 1;
492 #endif
493
494     return 0;
495 }
496
497 /*---------------------------------------------------------------------------*/
498
499 void config_set_d(int i, int d)
500 {
501     option_d[i] = d;
502     dirty = 1;
503 }
504
505 void config_tgl_d(int i)
506 {
507     option_d[i] = (option_d[i] ? 0 : 1);
508 }
509
510 int config_tst_d(int i, int d)
511 {
512     return (option_d[i] == d) ? 1 : 0;
513 }
514
515 int config_get_d(int i)
516 {
517     return option_d[i];
518 }
519
520 /*---------------------------------------------------------------------------*/
521
522 void config_set_s(int i, char *src)
523 {
524     int len = (int) strlen(src);
525
526     if (option_s[i])
527         free(option_s[i]);
528
529     if ((option_s[i] = (char *) malloc(len + 1)))
530         strncpy(option_s[i], src, len + 1);
531
532     dirty = 1;
533 }
534
535 void config_get_s(int i, char *dst, int len)
536 {
537     strncpy(dst, option_s[i], len);
538 }
539
540 /*---------------------------------------------------------------------------*/
541
542 static int grabbed = 0;
543 static int paused  = 0;
544
545 void config_set_grab(void)
546 {
547     SDL_WarpMouse(config_get_d(CONFIG_WIDTH)  / 2,
548                   config_get_d(CONFIG_HEIGHT) / 2);
549     SDL_WM_GrabInput(SDL_GRAB_ON);
550     SDL_ShowCursor(SDL_DISABLE);
551     grabbed = 1;
552 }
553
554 void config_clr_grab(void)
555 {
556     SDL_WM_GrabInput(SDL_GRAB_OFF);
557     SDL_ShowCursor(SDL_ENABLE);
558     grabbed = 0;
559 }
560
561 int  config_get_grab(void)
562 {
563     return grabbed;
564 }
565
566 int  config_get_pause(void)
567 {
568     return paused;
569 }
570
571 void config_set_pause(void)
572 {
573     Mix_PauseMusic();
574     paused = 1;
575
576     if (grabbed)
577     {
578         SDL_ShowCursor(SDL_ENABLE);
579         SDL_WM_GrabInput(SDL_GRAB_OFF);
580     }
581 }
582
583 void config_clr_pause(void)
584 {
585     Mix_ResumeMusic();
586     paused = 0;
587
588     if (grabbed)
589     {
590         SDL_WM_GrabInput(SDL_GRAB_ON);
591         SDL_ShowCursor(SDL_DISABLE);
592     }
593 }
594
595 void config_tgl_pause(void)
596 {
597     if (paused)
598         config_clr_pause();
599     else
600         config_set_pause();
601 }
602 /*---------------------------------------------------------------------------*/
603
604 void config_push_persp(float fov, float n, float f)
605 {
606     GLdouble m[4][4];
607
608     GLdouble r = fov / 2 * V_PI / 180;
609     GLdouble s = sin(r);
610     GLdouble c = cos(r) / s;
611
612     GLdouble a = ((GLdouble) option_d[CONFIG_WIDTH] / 
613                   (GLdouble) option_d[CONFIG_HEIGHT]);
614
615     glMatrixMode(GL_PROJECTION);
616     {
617         glPushMatrix();
618         glLoadIdentity();
619
620         m[0][0] =  c/a;
621         m[0][1] =  0.0;
622         m[0][2] =  0.0;
623         m[0][3] =  0.0;
624         m[1][0] =  0.0;
625         m[1][1] =    c;
626         m[1][2] =  0.0;
627         m[1][3] =  0.0;
628         m[2][0] =  0.0;
629         m[2][1] =  0.0;
630         m[2][2] = -(f + n) / (f - n);
631         m[2][3] = -1.0;
632         m[3][0] =  0.0;
633         m[3][1] =  0.0;
634         m[3][2] = -2.0 * n * f / (f - n);
635         m[3][3] =  0.0;
636
637         glMultMatrixd(&m[0][0]);
638     }
639     glMatrixMode(GL_MODELVIEW);
640 }
641
642 void config_push_ortho(void)
643 {
644     GLdouble w = (GLdouble) option_d[CONFIG_WIDTH];
645     GLdouble h = (GLdouble) option_d[CONFIG_HEIGHT];
646
647     glMatrixMode(GL_PROJECTION);
648     {
649         glPushMatrix();
650         glLoadIdentity();
651         glOrtho(0.0, w, 0.0, h, -1.0, +1.0);
652     }
653     glMatrixMode(GL_MODELVIEW);
654 }
655
656 void config_pop_matrix(void)
657 {
658     glMatrixMode(GL_PROJECTION);
659     {
660         glPopMatrix();
661     }
662     glMatrixMode(GL_MODELVIEW);
663 }
664
665 void config_clear(void)
666 {
667     if (option_d[CONFIG_REFLECTION])
668         glClear(GL_COLOR_BUFFER_BIT |
669                 GL_DEPTH_BUFFER_BIT |
670                 GL_STENCIL_BUFFER_BIT);
671     else
672         glClear(GL_COLOR_BUFFER_BIT |
673                 GL_DEPTH_BUFFER_BIT);
674 }
675
676 /*---------------------------------------------------------------------------*/