Correct logic of BSP back/front tests
[neverball] / share / config.c
index 63f0e0c..7c112d0 100644 (file)
  */
 
 #include <SDL.h>
-#include <SDL_mixer.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
 #include <math.h>
+#include <ctype.h>
 
 #include "config.h"
 #include "glext.h"
 #include "vec3.h"
+#include "sync.h"
+#include "common.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -50,7 +52,7 @@ static void config_key(const char *s, int i, int d)
     config_set_d(i, d);
 
     for (c = 0; c < SDLK_LAST; c++)
-        if (strcmp(s, SDL_GetKeyName(c)) == 0)
+        if (strcmp(s, SDL_GetKeyName((SDLKey) c)) == 0)
         {
             config_set_d(i, c);
             break;
@@ -73,12 +75,14 @@ void config_init(void)
     config_set_d(CONFIG_GEOMETRY,             DEFAULT_GEOMETRY);
     config_set_d(CONFIG_REFLECTION,           DEFAULT_REFLECTION);
     config_set_d(CONFIG_MULTISAMPLE,          DEFAULT_MULTISAMPLE);
+    config_set_d(CONFIG_MIPMAP,               DEFAULT_MIPMAP);
+    config_set_d(CONFIG_ANISO,                DEFAULT_ANISO);
     config_set_d(CONFIG_BACKGROUND,           DEFAULT_BACKGROUND);
     config_set_d(CONFIG_SHADOW,               DEFAULT_SHADOW);
-    config_set_d(CONFIG_AUDIO_RATE,           DEFAULT_AUDIO_RATE);
     config_set_d(CONFIG_AUDIO_BUFF,           DEFAULT_AUDIO_BUFF);
     config_set_d(CONFIG_MOUSE_SENSE,          DEFAULT_MOUSE_SENSE);
     config_set_d(CONFIG_MOUSE_INVERT,         DEFAULT_MOUSE_INVERT);
+    config_set_d(CONFIG_VSYNC,                DEFAULT_VSYNC);
     config_set_d(CONFIG_NICE,                 DEFAULT_NICE);
     config_set_d(CONFIG_FPS,                  DEFAULT_FPS);
     config_set_d(CONFIG_SOUND_VOLUME,         DEFAULT_SOUND_VOLUME);
@@ -95,6 +99,10 @@ void config_init(void)
     config_set_d(CONFIG_JOYSTICK_CAMERA_1,    DEFAULT_JOYSTICK_CAMERA_1);
     config_set_d(CONFIG_JOYSTICK_CAMERA_2,    DEFAULT_JOYSTICK_CAMERA_2);
     config_set_d(CONFIG_JOYSTICK_CAMERA_3,    DEFAULT_JOYSTICK_CAMERA_3);
+    config_set_d(CONFIG_JOYSTICK_DPAD_L,      DEFAULT_JOYSTICK_DPAD_L);
+    config_set_d(CONFIG_JOYSTICK_DPAD_R,      DEFAULT_JOYSTICK_DPAD_R);
+    config_set_d(CONFIG_JOYSTICK_DPAD_U,      DEFAULT_JOYSTICK_DPAD_U);
+    config_set_d(CONFIG_JOYSTICK_DPAD_D,      DEFAULT_JOYSTICK_DPAD_D);
     config_set_d(CONFIG_KEY_CAMERA_1,         DEFAULT_KEY_CAMERA_1);
     config_set_d(CONFIG_KEY_CAMERA_2,         DEFAULT_KEY_CAMERA_2);
     config_set_d(CONFIG_KEY_CAMERA_3,         DEFAULT_KEY_CAMERA_3);
@@ -108,12 +116,77 @@ void config_init(void)
     config_set_d(CONFIG_ROTATE_SLOW,          DEFAULT_ROTATE_SLOW);
     config_set_s(CONFIG_PLAYER,               DEFAULT_PLAYER);
     config_set_s(CONFIG_BALL,                 DEFAULT_BALL);
+    config_set_s(CONFIG_WIIMOTE_ADDR,         DEFAULT_WIIMOTE_ADDR);
+    config_set_s(CONFIG_REPLAY_NAME,          DEFAULT_REPLAY_NAME);
+    config_set_d(CONFIG_CHEAT,                DEFAULT_CHEAT);
+    config_set_d(CONFIG_STATS,                DEFAULT_STATS);
+    config_set_d(CONFIG_UNIFORM,              DEFAULT_UNIFORM);
     config_set_d(CONFIG_KEY_FORWARD,          DEFAULT_KEY_FORWARD);
     config_set_d(CONFIG_KEY_BACKWARD,         DEFAULT_KEY_BACKWARD);
     config_set_d(CONFIG_KEY_LEFT,             DEFAULT_KEY_LEFT);
     config_set_d(CONFIG_KEY_RIGHT,            DEFAULT_KEY_RIGHT);
     config_set_d(CONFIG_KEY_PAUSE,            DEFAULT_KEY_PAUSE);
     config_set_d(CONFIG_KEY_RESTART,          DEFAULT_KEY_RESTART);
+    config_set_d(CONFIG_KEY_SCORE_NEXT,       DEFAULT_KEY_SCORE_NEXT);
+    config_set_d(CONFIG_SCREENSHOT,           DEFAULT_SCREENSHOT);
+    config_set_d(CONFIG_LOCK_GOALS,           DEFAULT_LOCK_GOALS);
+}
+
+/*
+ * Scan a NUL-terminated string LINE according to the format
+ * '^<space>?<key><space><value>$' and store pointers to the start of key and
+ * value at DST_KEY and DST_VAL, respectively.  No memory is allocated to store
+ * the strings;  instead, the memory pointed to by LINE modified in-place as
+ * needed.
+ *
+ * Return 1 if LINE matches the format, return 0 otherwise.
+ */
+
+static int scan_key_and_value(char **dst_key, char **dst_val, char *line)
+{
+    if (line)
+    {
+        char *key, *val, *space;
+
+        for (key = line; *key && isspace(*key); key++);
+
+        if (*key)
+        {
+            if (dst_key)
+                *dst_key = key;
+        }
+        else
+            return 0;
+
+        for (space = key; *space && !isspace(*space); space++);
+
+        if (*space)
+        {
+            /* NUL-terminate the key, if necessary. */
+
+            if (dst_key)
+            {
+                *space = '\0';
+                space++;
+            }
+        }
+        else
+            return 0;
+
+        for (val = space; *val && isspace(*val); val++);
+
+        if (*val)
+        {
+            if (dst_val)
+                *dst_val = val;
+        }
+        else
+            return 0;
+
+        return 1;
+    }
+
+    return 0;
 }
 
 void config_load(void)
@@ -122,12 +195,11 @@ void config_load(void)
 
     if ((fp = fopen(config_user(USER_CONFIG_FILE), "r")))
     {
-        char buf[MAXSTR];
-        char key[MAXSTR];
-        char val[MAXSTR];
+        char *line, *key, *val;
 
-        while (fgets(buf, MAXSTR, fp))
-            if (sscanf(buf, "%s %s", key, val) == 2)
+        while (read_line(&line, fp))
+        {
+            if (scan_key_and_value(&key, &val, line))
             {
                 if      (strcmp(key, "fullscreen")            == 0)
                     config_set_d(CONFIG_FULLSCREEN,           atoi(val));
@@ -147,18 +219,22 @@ void config_load(void)
                     config_set_d(CONFIG_REFLECTION,           atoi(val));
                 else if (strcmp(key, "multisample")           == 0)
                     config_set_d(CONFIG_MULTISAMPLE,          atoi(val));
+                else if (strcmp(key, "mipmap")                == 0)
+                    config_set_d(CONFIG_MIPMAP,               atoi(val));
+                else if (strcmp(key, "aniso")                 == 0)
+                    config_set_d(CONFIG_ANISO,                atoi(val));
                 else if (strcmp(key, "background")            == 0)
                     config_set_d(CONFIG_BACKGROUND,           atoi(val));
                 else if (strcmp(key, "shadow")                == 0)
                     config_set_d(CONFIG_SHADOW,               atoi(val));
-                else if (strcmp(key, "audio_rate")            == 0)
-                    config_set_d(CONFIG_AUDIO_RATE,           atoi(val));
                 else if (strcmp(key, "audio_buff")            == 0)
                     config_set_d(CONFIG_AUDIO_BUFF,           atoi(val));
                 else if (strcmp(key, "mouse_sense")           == 0)
                     config_set_d(CONFIG_MOUSE_SENSE,          atoi(val));
                 else if (strcmp(key, "mouse_invert")          == 0)
                     config_set_d(CONFIG_MOUSE_INVERT,         atoi(val));
+                else if (strcmp(key, "vsync")                 == 0)
+                    config_set_d(CONFIG_VSYNC,                atoi(val));
                 else if (strcmp(key, "nice")                  == 0)
                     config_set_d(CONFIG_NICE,                 atoi(val));
                 else if (strcmp(key, "fps")                   == 0)
@@ -224,17 +300,38 @@ void config_load(void)
                 else if (strcmp(key, "key_camera_l")  == 0)
                     config_key(val, CONFIG_KEY_CAMERA_L, DEFAULT_KEY_CAMERA_L);
 
-                else if (strcmp(key, "key_pause")  == 0)
-                    config_key(val, CONFIG_KEY_PAUSE,    DEFAULT_KEY_PAUSE);
+                else if (strcmp(key, "key_pause")    == 0)
+                    config_key(val, CONFIG_KEY_PAUSE,   DEFAULT_KEY_PAUSE);
                 else if (strcmp(key, "key_restart")  == 0)
-                    config_key(val, CONFIG_KEY_RESTART,    DEFAULT_KEY_RESTART);
-
-                else if (strcmp(key, "player")     == 0)
-                    config_set_s(CONFIG_PLAYER,     val);
-                else if (strcmp(key, "ball")       == 0)
-                    config_set_s(CONFIG_BALL,       val);
+                    config_key(val, CONFIG_KEY_RESTART, DEFAULT_KEY_RESTART);
+
+                else if (strcmp(key, "key_score_next") == 0)
+                    config_key(val, CONFIG_KEY_SCORE_NEXT, DEFAULT_KEY_SCORE_NEXT);
+
+                else if (strcmp(key, "player") == 0)
+                    config_set_s(CONFIG_PLAYER, val);
+                else if (strcmp(key, "ball_file") == 0)
+                    config_set_s(CONFIG_BALL, val);
+                else if (strcmp(key, "wiimote_addr") == 0)
+                    config_set_s(CONFIG_WIIMOTE_ADDR, val);
+                else if (strcmp(key, "replay_name") == 0)
+                    config_set_s(CONFIG_REPLAY_NAME, val);
+
+                else if (strcmp(key, "cheat")   == 0)
+                    config_set_d(CONFIG_CHEAT, atoi(val));
+                else if (strcmp(key, "stats")   == 0)
+                    config_set_d(CONFIG_STATS, atoi(val));
+                else if (strcmp(key, "uniform") == 0)
+                    config_set_d(CONFIG_UNIFORM, atoi(val));
+                else if (strcmp(key, "screenshot") == 0)
+                    config_set_d(CONFIG_SCREENSHOT, atoi(val));
+                else if (strcmp(key, "lock_goals") == 0)
+                    config_set_d(CONFIG_LOCK_GOALS, atoi(val));
             }
 
+            free(line);
+        }
+
         fclose(fp);
 
         dirty = 0;
@@ -265,18 +362,22 @@ void config_save(void)
                 option_d[CONFIG_REFLECTION]);
         fprintf(fp, "multisample          %d\n",
                 option_d[CONFIG_MULTISAMPLE]);
+        fprintf(fp, "mipmap               %d\n",
+                option_d[CONFIG_MIPMAP]);
+        fprintf(fp, "aniso                %d\n",
+                option_d[CONFIG_ANISO]);
         fprintf(fp, "background           %d\n",
                 option_d[CONFIG_BACKGROUND]);
         fprintf(fp, "shadow               %d\n",
                 option_d[CONFIG_SHADOW]);
-        fprintf(fp, "audio_rate           %d\n",
-                option_d[CONFIG_AUDIO_RATE]);
         fprintf(fp, "audio_buff           %d\n",
                 option_d[CONFIG_AUDIO_BUFF]);
         fprintf(fp, "mouse_sense          %d\n",
                 option_d[CONFIG_MOUSE_SENSE]);
         fprintf(fp, "mouse_invert         %d\n",
                 option_d[CONFIG_MOUSE_INVERT]);
+        fprintf(fp, "vsync                %d\n",
+                option_d[CONFIG_VSYNC]);
         fprintf(fp, "nice                 %d\n",
                 option_d[CONFIG_NICE]);
         fprintf(fp, "fps                  %d\n",
@@ -323,32 +424,49 @@ void config_save(void)
                 option_d[CONFIG_ROTATE_SLOW]);
 
         fprintf(fp, "key_forward          %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_FORWARD]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_FORWARD]));
         fprintf(fp, "key_backward         %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_BACKWARD]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_BACKWARD]));
         fprintf(fp, "key_left             %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_LEFT]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_LEFT]));
         fprintf(fp, "key_right            %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_RIGHT]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_RIGHT]));
 
         fprintf(fp, "key_camera_1         %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_1]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_1]));
         fprintf(fp, "key_camera_2         %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_2]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_2]));
         fprintf(fp, "key_camera_3         %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_3]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_3]));
         fprintf(fp, "key_camera_r         %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_R]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_R]));
         fprintf(fp, "key_camera_l         %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_CAMERA_L]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_CAMERA_L]));
 
         fprintf(fp, "key_pause            %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_PAUSE]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_PAUSE]));
         fprintf(fp, "key_restart          %s\n",
-                SDL_GetKeyName(option_d[CONFIG_KEY_RESTART]));
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_RESTART]));
 
-        fprintf(fp, "player               %s\n", option_s[CONFIG_PLAYER]);
-        fprintf(fp, "ball                 %s\n", option_s[CONFIG_BALL]);
+        fprintf(fp, "key_score_next       %s\n",
+                SDL_GetKeyName((SDLKey) option_d[CONFIG_KEY_SCORE_NEXT]));
+
+        if (strlen(option_s[CONFIG_PLAYER]) > 0)
+            fprintf(fp, "player       %s\n", option_s[CONFIG_PLAYER]);
+        if (strlen(option_s[CONFIG_BALL]) > 0)
+            fprintf(fp, "ball_file    %s\n", option_s[CONFIG_BALL]);
+        if (strlen(option_s[CONFIG_WIIMOTE_ADDR]) > 0)
+            fprintf(fp, "wiimote_addr %s\n", option_s[CONFIG_WIIMOTE_ADDR]);
+        if (strlen(option_s[CONFIG_REPLAY_NAME]) > 0)
+            fprintf(fp, "replay_name  %s\n", option_s[CONFIG_REPLAY_NAME]);
+
+        fprintf(fp, "stats                %d\n", option_d[CONFIG_STATS]);
+        fprintf(fp, "uniform              %d\n", option_d[CONFIG_UNIFORM]);
+        fprintf(fp, "screenshot           %d\n", option_d[CONFIG_SCREENSHOT]);
+        fprintf(fp, "lock_goals           %d\n", option_d[CONFIG_LOCK_GOALS]);
+
+        if (config_cheat())
+            fprintf(fp, "cheat                %d\n", option_d[CONFIG_CHEAT]);
 
         fclose(fp);
     }
@@ -383,19 +501,21 @@ int config_mode(int f, int w, int h)
     int stencil = config_get_d(CONFIG_REFLECTION)  ? 1 : 0;
     int buffers = config_get_d(CONFIG_MULTISAMPLE) ? 1 : 0;
     int samples = config_get_d(CONFIG_MULTISAMPLE);
+    int vsync   = config_get_d(CONFIG_VSYNC)       ? 1 : 0;
 
     SDL_GL_SetAttribute(SDL_GL_STEREO,             stereo);
     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,       stencil);
     SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, buffers);
     SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
+    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL,       vsync);
 
     /* Try to set the currently specified mode. */
 
     if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL | (f ? SDL_FULLSCREEN : 0)))
     {
         config_set_d(CONFIG_FULLSCREEN, f);
-        config_set_d(CONFIG_WIDTH, w);
-        config_set_d(CONFIG_HEIGHT, h);
+        config_set_d(CONFIG_WIDTH,      w);
+        config_set_d(CONFIG_HEIGHT,     h);
 
         glViewport(0, 0, w, h);
         glClearColor(0.0f, 0.0f, 0.1f, 0.0f);
@@ -405,6 +525,22 @@ int config_mode(int f, int w, int h)
         glEnable(GL_DEPTH_TEST);
         glEnable(GL_TEXTURE_2D);
         glEnable(GL_LIGHTING);
+        glEnable(GL_BLEND);
+
+        glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,
+                      GL_SEPARATE_SPECULAR_COLOR);
+        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
+
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glDepthFunc(GL_LEQUAL);
+
+        /*
+         * Mac OS X might still need this, because apparently SDL doesn't do
+         * SDL_GL_SWAP_CONTROL on OS X.  TODO: investigate.
+         */
+#if 0
+        if (vsync) sync_init();
+#endif
 
         /* If GL supports multisample, and SDL got a multisample buffer... */
 
@@ -451,6 +587,60 @@ int config_mode(int f, int w, int h)
 
 /*---------------------------------------------------------------------------*/
 
+static float ms     = 0;
+static int   fps    = 0;
+static int   last   = 0;
+static int   ticks  = 0;
+static int   frames = 0;
+
+int  config_perf(void)
+{
+    return fps;
+}
+
+void config_swap(void)
+{
+    int dt;
+
+    SDL_GL_SwapBuffers();
+
+    /* Accumulate time passed and frames rendered. */
+
+    dt = (int) SDL_GetTicks() - last;
+
+    frames +=  1;
+    ticks  += dt;
+    last   += dt;
+
+    /* Average over 250ms. */
+
+    if (ticks > 1000)
+    {
+        /* Round the frames-per-second value to the nearest integer. */
+
+        double k = 1000.0 * frames / ticks;
+        double f = floor(k);
+        double c = ceil (k);
+
+        /* Compute frame time and frames-per-second stats. */
+
+        fps = (int) ((c - k < k - f) ? c : f);
+        ms  = (float) ticks / (float) frames;
+
+        /* Reset the counters for the next update. */
+
+        frames = 0;
+        ticks  = 0;
+
+        /* Output statistics if configured. */
+
+        if (option_d[CONFIG_STATS])
+            fprintf(stdout, "%4d %8.4f\n", fps, ms);
+    }
+}
+
+/*---------------------------------------------------------------------------*/
+
 void config_set_d(int i, int d)
 {
     option_d[i] = d;
@@ -500,10 +690,18 @@ static int grabbed = 0;
 void config_set_grab(int w)
 {
     if (w)
+    {
+        SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
+
         SDL_WarpMouse(config_get_d(CONFIG_WIDTH)  / 2,
                       config_get_d(CONFIG_HEIGHT) / 2);
+
+        SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
+    }
+
     SDL_WM_GrabInput(SDL_GRAB_ON);
     SDL_ShowCursor(SDL_DISABLE);
+
     grabbed = 1;
 }
 
@@ -523,11 +721,24 @@ int  config_get_grab(void)
 
 int config_cheat(void)
 {
-#if CHEATER
-    return strcmp(option_s[CONFIG_PLAYER], "CHEATER") == 0;
-#else
-    return 0;
-#endif
+    return config_get_d(CONFIG_CHEAT);
+}
+
+void config_set_cheat(void)
+{
+    config_set_d(CONFIG_CHEAT, 1);
+}
+
+void config_clr_cheat(void)
+{
+    config_set_d(CONFIG_CHEAT, 0);
+}
+
+/*---------------------------------------------------------------------------*/
+
+int config_screenshot(void)
+{
+    return ++option_d[CONFIG_SCREENSHOT];
 }
 
 /*---------------------------------------------------------------------------*/