Added gamma correction option to the setup menu; bug #977; some work from Nic

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3645 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2011-07-14 21:36:36 +00:00
parent 9649e30f33
commit c0bc500620
9 changed files with 227 additions and 16 deletions
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.8: Changes towards version 0.8:
- Added gamma correction to the setup menu (bug #977) - Alex, Nic
- Refactor Melnorme comm code to make modding easier; step 1 (bug #1128), - Refactor Melnorme comm code to make modding easier; step 1 (bug #1128),
from Scott A. Colcord from Scott A. Colcord
- Added aspect ratio option to the setup menu - Alex - Added aspect ratio option to the setup menu - Alex
+5
View File
@@ -455,6 +455,7 @@ Currently only meaningful in OpenGL mode.
Music Volume Music Volume
SFX Volume SFX Volume
Speech Volume Speech Volume
Gamma Correction
#(SLIDER_0_DESC) #(SLIDER_0_DESC)
Sets the music volume. Sets the music volume.
@@ -465,6 +466,10 @@ Sets the sound effects volume.
#(SLIDER_2_DESC) #(SLIDER_2_DESC)
Sets the speech volume. Sets the speech volume.
#(SLIDER_3_DESC)
Sets the gamma correction.
May not work on all hardware.
#(BUTTONS) #(BUTTONS)
Quit Setup Menu Quit Setup Menu
Return to Main Menu Return to Main Menu
+1 -1
View File
@@ -67,7 +67,7 @@ int TFB_InitGraphics (int driver, int flags, int width, int height);
int TFB_ReInitGraphics (int driver, int flags, int width, int height); int TFB_ReInitGraphics (int driver, int flags, int width, int height);
void TFB_UninitGraphics (void); void TFB_UninitGraphics (void);
void TFB_ProcessEvents (void); void TFB_ProcessEvents (void);
void TFB_SetGamma (float gamma); bool TFB_SetGamma (float gamma);
void TFB_UploadTransitionScreen (void); void TFB_UploadTransitionScreen (void);
// This function should not be called directly // This function should not be called directly
void TFB_SwapBuffers (int force_full_redraw); void TFB_SwapBuffers (int force_full_redraw);
+2 -10
View File
@@ -592,16 +592,8 @@ TFB_UploadTransitionScreen (void)
#endif #endif
} }
void bool
TFB_SetGamma (float gamma) TFB_SetGamma (float gamma)
{ {
if (SDL_SetGamma (gamma, gamma, gamma) == -1) return (SDL_SetGamma (gamma, gamma, gamma) == 0);
{
log_add (log_Warning, "Unable to set gamma correction.");
}
else
{
log_add (log_Info, "Gamma correction set to %1.4f.", gamma);
}
} }
+14
View File
@@ -58,6 +58,9 @@ BOOLEAN optSpeech;
BOOLEAN optSubtitles; BOOLEAN optSubtitles;
BOOLEAN optStereoSFX; BOOLEAN optStereoSFX;
BOOLEAN optKeepAspectRatio; BOOLEAN optKeepAspectRatio;
float optGamma;
uio_DirHandle *contentDir; uio_DirHandle *contentDir;
uio_DirHandle *configDir; uio_DirHandle *configDir;
uio_DirHandle *saveDir; uio_DirHandle *saveDir;
@@ -584,3 +587,14 @@ prepareAddons (const char **addons)
} }
} }
} }
bool
setGammaCorrection (float gamma)
{
bool set = TFB_SetGamma (gamma);
if (set)
log_add (log_Info, "Gamma correction set to %.4f.", gamma);
else
log_add (log_Warning, "Unable to set gamma correction.");
return set;
}
+5
View File
@@ -45,6 +45,9 @@ extern BOOLEAN optSubtitles;
extern BOOLEAN optStereoSFX; extern BOOLEAN optStereoSFX;
extern BOOLEAN optKeepAspectRatio; extern BOOLEAN optKeepAspectRatio;
#define GAMMA_SCALE 1000
extern float optGamma;
extern uio_DirHandle *contentDir; extern uio_DirHandle *contentDir;
extern uio_DirHandle *configDir; extern uio_DirHandle *configDir;
extern uio_DirHandle *saveDir; extern uio_DirHandle *saveDir;
@@ -76,5 +79,7 @@ void prepareShadowAddons (const char **addons);
BOOLEAN loadAddon (const char *addon); BOOLEAN loadAddon (const char *addon);
int loadIndices (uio_DirHandle *baseDir); int loadIndices (uio_DirHandle *baseDir);
bool setGammaCorrection (float gamma);
#endif #endif
+26 -3
View File
@@ -243,7 +243,7 @@ main (int argc, char *argv[])
INIT_CONFIG_OPTION( scaler, 0 ), INIT_CONFIG_OPTION( scaler, 0 ),
INIT_CONFIG_OPTION( showFps, false ), INIT_CONFIG_OPTION( showFps, false ),
INIT_CONFIG_OPTION( keepAspectRatio, false ), INIT_CONFIG_OPTION( keepAspectRatio, false ),
INIT_CONFIG_OPTION( gamma, 0.0f ), INIT_CONFIG_OPTION( gamma, 1.0f ),
INIT_CONFIG_OPTION( soundDriver, audio_DRIVER_MIXSDL ), INIT_CONFIG_OPTION( soundDriver, audio_DRIVER_MIXSDL ),
INIT_CONFIG_OPTION( soundQuality, audio_QUALITY_MEDIUM ), INIT_CONFIG_OPTION( soundQuality, audio_QUALITY_MEDIUM ),
INIT_CONFIG_OPTION( use3doMusic, true ), INIT_CONFIG_OPTION( use3doMusic, true ),
@@ -418,8 +418,11 @@ main (int argc, char *argv[])
gfxFlags |= TFB_GFXFLAGS_SHOWFPS; gfxFlags |= TFB_GFXFLAGS_SHOWFPS;
TFB_InitGraphics (gfxDriver, gfxFlags, options.resolution.width, TFB_InitGraphics (gfxDriver, gfxFlags, options.resolution.width,
options.resolution.height); options.resolution.height);
if (options.gamma.set) if (options.gamma.set && setGammaCorrection (options.gamma.value))
TFB_SetGamma (options.gamma.value); optGamma = options.gamma.value;
else
optGamma = 1.0f; // failed or default
InitColorMaps (); InitColorMaps ();
init_communication (); init_communication ();
/* TODO: Once threading is gone, restore initAudio here. /* TODO: Once threading is gone, restore initAudio here.
@@ -557,6 +560,25 @@ getVolumeConfigValue (struct float_option *option, const char *config_val)
option->set = true; option->set = true;
} }
static void
getGammaConfigValue (struct float_option *option, const char *config_val)
{
int val;
if (option->set || !res_IsInteger (config_val))
return;
val = res_GetInteger (config_val);
// gamma config option is a fixed-point number
// ignore ridiculously out-of-range values
if (val < (int)(0.03 * GAMMA_SCALE) || val > (int)(9.9 * GAMMA_SCALE))
return;
option->value = val / (float)GAMMA_SCALE;
// avoid setting gamma when not necessary
if (option->value != 1.0f)
option->set = true;
}
static bool static bool
getListConfigValue (struct int_option *option, const char *config_val, getListConfigValue (struct int_option *option, const char *config_val,
const struct option_list_value *list) const struct option_list_value *list)
@@ -605,6 +627,7 @@ getUserConfigOptions (struct options_struct *options)
getBoolConfigValue (&options->scanlines, "config.scanlines"); getBoolConfigValue (&options->scanlines, "config.scanlines");
getBoolConfigValue (&options->showFps, "config.showfps"); getBoolConfigValue (&options->showFps, "config.showfps");
getBoolConfigValue (&options->keepAspectRatio, "config.keepaspectratio"); getBoolConfigValue (&options->keepAspectRatio, "config.keepaspectratio");
getGammaConfigValue (&options->gamma, "config.gamma");
getBoolConfigValue (&options->subtitles, "config.subtitles"); getBoolConfigValue (&options->subtitles, "config.subtitles");
+172 -2
View File
@@ -37,6 +37,8 @@
#include "libs/memlib.h" #include "libs/memlib.h"
#include "resinst.h" #include "resinst.h"
#include "nameref.h" #include "nameref.h"
#include <math.h>
static STRING SetupTab; static STRING SetupTab;
@@ -74,7 +76,7 @@ static void clear_control (WIDGET_CONTROLENTRY *widget);
#define MENU_COUNT 8 #define MENU_COUNT 8
#define CHOICE_COUNT 24 #define CHOICE_COUNT 24
#define SLIDER_COUNT 3 #define SLIDER_COUNT 4
#define BUTTON_COUNT 10 #define BUTTON_COUNT 10
#define LABEL_COUNT 4 #define LABEL_COUNT 4
#define TEXTENTRY_COUNT 1 #define TEXTENTRY_COUNT 1
@@ -119,6 +121,7 @@ static WIDGET *graphics_widgets[] = {
(WIDGET *)(&choices[0]), (WIDGET *)(&choices[0]),
(WIDGET *)(&choices[23]), (WIDGET *)(&choices[23]),
(WIDGET *)(&choices[10]), (WIDGET *)(&choices[10]),
(WIDGET *)(&sliders[3]),
(WIDGET *)(&choices[2]), (WIDGET *)(&choices[2]),
(WIDGET *)(&choices[3]), (WIDGET *)(&choices[3]),
(WIDGET *)(&buttons[1]), (WIDGET *)(&buttons[1]),
@@ -202,6 +205,18 @@ menu_defs[] =
{NULL, 0} {NULL, 0}
}; };
// Start with reasonable gamma bounds. These will get updated
// as we find out the actual bounds.
static float minGamma = 0.4f;
static float maxGamma = 2.5f;
// The gamma slider uses an exponential curve
// We use y = e^(2.1972*(x-1)) curve to give us a nice spread of
// gamma values 0.11 < g < 9.0 centered at g=1.0
#define GAMMA_CURVE_B 2.1972f
static float minGammaX;
static float maxGammaX;
static int static int
quit_main_menu (WIDGET *self, int event) quit_main_menu (WIDGET *self, int event)
{ {
@@ -405,6 +420,7 @@ SetDefaults (void)
sliders[0].value = opts.musicvol; sliders[0].value = opts.musicvol;
sliders[1].value = opts.sfxvol; sliders[1].value = opts.sfxvol;
sliders[2].value = opts.speechvol; sliders[2].value = opts.speechvol;
sliders[3].value = opts.gamma;
} }
static void static void
@@ -438,6 +454,7 @@ PropagateResults (void)
opts.musicvol = sliders[0].value; opts.musicvol = sliders[0].value;
opts.sfxvol = sliders[1].value; opts.sfxvol = sliders[1].value;
opts.speechvol = sliders[2].value; opts.speechvol = sliders[2].value;
opts.gamma = sliders[3].value;
SetGlobalOptions (&opts); SetGlobalOptions (&opts);
} }
@@ -594,6 +611,135 @@ OnTextEntryEvent (WIDGET_TEXTENTRY *widget)
return TRUE; // event handled return TRUE; // event handled
} }
static inline float
gammaCurve (float x)
{
// The slider uses an exponential curve
return exp ((x - 1) * GAMMA_CURVE_B);
}
static inline float
solveGammaCurve (float y)
{
return log (y) / GAMMA_CURVE_B + 1;
}
static int
gammaToSlider (float gamma)
{
const float x = solveGammaCurve (gamma);
const float step = (maxGammaX - minGammaX) / 100;
return (int) ((x - minGammaX) / step + 0.5);
}
static float
sliderToGamma (int value)
{
const float step = (maxGammaX - minGammaX) / 100;
const float x = minGammaX + step * value;
const float g = gammaCurve (x);
// report any value that is close enough as 1.0
return (fabs (g - 1.0f) < 0.001f) ? 1.0f : g;
}
static void
updateGammaBounds (bool useUpper)
{
float g, x;
int slider;
// The slider uses an exponential curve.
// Calculate where on the curve the min and max gamma values are
minGammaX = solveGammaCurve (minGamma);
maxGammaX = solveGammaCurve (maxGamma);
// We have 100 discrete steps through the range, so the slider may
// skip over a 1.0 gamma. We need to ensure that there always is
// a 1.0 on the slider by tweaking the range (expanding/contracting).
slider = gammaToSlider (1.0f);
g = sliderToGamma (slider);
if (g == 1.0f)
return; // no adjustment needed
x = solveGammaCurve (g);
if (useUpper)
{ // Move the upper bound up or down to land on 1.0
const float d = (x - 1.0f) * 100 / slider;
maxGammaX -= d;
maxGamma = gammaCurve (maxGammaX);
}
else
{ // Move the lower bound up or down to land on 1.0
const float d = (x - 1.0f) * 100 / (100 - slider);
minGammaX -= d;
minGamma = gammaCurve (minGammaX);
}
}
static int
gamma_HandleEventSlider (WIDGET *_self, int event)
{
WIDGET_SLIDER *self = (WIDGET_SLIDER *)_self;
int prevValue = self->value;
float gamma;
bool set;
switch (event)
{
case WIDGET_EVENT_LEFT:
self->value -= self->step;
break;
case WIDGET_EVENT_RIGHT:
self->value += self->step;
break;
default:
return FALSE;
}
// Limit the slider to values accepted by gfx subsys
gamma = sliderToGamma (self->value);
set = TFB_SetGamma (gamma);
if (!set)
{ // revert
self->value = prevValue;
gamma = sliderToGamma (self->value);
}
// Grow or shrink the range based on accepted values
if (gamma < minGamma || (!set && event == WIDGET_EVENT_LEFT))
{
minGamma = gamma;
updateGammaBounds (true);
// at the lowest end
self->value = 0;
}
else if (gamma > maxGamma || (!set && event == WIDGET_EVENT_RIGHT))
{
maxGamma = gamma;
updateGammaBounds (false);
// at the highest end
self->value = 100;
}
return TRUE;
}
static void
gamma_DrawValue (WIDGET_SLIDER *self, int x, int y)
{
TEXT t;
char buf[16];
float gamma = sliderToGamma (self->value);
snprintf (buf, sizeof buf, "%.4f", gamma);
t.baseline.x = x;
t.baseline.y = y;
t.align = ALIGN_CENTER;
t.CharCount = ~0;
t.pStr = buf;
font_DrawText (&t);
}
static void static void
rebind_control (WIDGET_CONTROLENTRY *widget) rebind_control (WIDGET_CONTROLENTRY *widget)
{ {
@@ -804,6 +950,10 @@ init_widgets (void)
sliders[i].tooltip[1] = ""; sliders[i].tooltip[1] = "";
sliders[i].tooltip[2] = ""; sliders[i].tooltip[2] = "";
} }
// gamma is a special case
sliders[3].step = 1;
sliders[3].handleEvent = gamma_HandleEventSlider;
sliders[3].draw_value = gamma_DrawValue;
for (i = 0; i < SLIDER_COUNT; i++) for (i = 0; i < SLIDER_COUNT; i++)
{ {
@@ -1080,6 +1230,8 @@ SetupMenu (void)
void void
GetGlobalOptions (GLOBALOPTS *opts) GetGlobalOptions (GLOBALOPTS *opts)
{ {
bool whichBound;
if (GfxFlags & TFB_GFXFLAGS_SCALE_BILINEAR) if (GfxFlags & TFB_GFXFLAGS_SCALE_BILINEAR)
{ {
opts->scaler = OPTVAL_BILINEAR_SCALE; opts->scaler = OPTVAL_BILINEAR_SCALE;
@@ -1227,13 +1379,22 @@ GetGlobalOptions (GLOBALOPTS *opts)
} }
} }
whichBound = (optGamma < maxGamma);
// The option supplied by the user may be beyond our starting range
// but valid nonetheless. We need to account for that.
if (optGamma <= minGamma)
minGamma = optGamma - 0.03f;
else if (optGamma >= maxGamma)
maxGamma = optGamma + 0.3f;
updateGammaBounds (whichBound);
opts->gamma = gammaToSlider (optGamma);
opts->player1 = PlayerControls[0]; opts->player1 = PlayerControls[0];
opts->player2 = PlayerControls[1]; opts->player2 = PlayerControls[1];
opts->musicvol = (((int)(musicVolumeScale * 100.0f) + 2) / 5) * 5; opts->musicvol = (((int)(musicVolumeScale * 100.0f) + 2) / 5) * 5;
opts->sfxvol = (((int)(sfxVolumeScale * 100.0f) + 2) / 5) * 5; opts->sfxvol = (((int)(sfxVolumeScale * 100.0f) + 2) / 5) * 5;
opts->speechvol = (((int)(speechVolumeScale * 100.0f) + 2) / 5) * 5; opts->speechvol = (((int)(speechVolumeScale * 100.0f) + 2) / 5) * 5;
} }
void void
@@ -1336,6 +1497,14 @@ SetGlobalOptions (GLOBALOPTS *opts)
FlushGraphics (); FlushGraphics ();
InitVideoPlayer (TRUE); InitVideoPlayer (TRUE);
} }
// Avoid setting gamma when it is not necessary
if (optGamma != 1.0f || sliderToGamma (opts->gamma) != 1.0f)
{
optGamma = sliderToGamma (opts->gamma);
setGammaCorrection (optGamma);
}
optSubtitles = (opts->subtitles == OPTVAL_ENABLED) ? TRUE : FALSE; optSubtitles = (opts->subtitles == OPTVAL_ENABLED) ? TRUE : FALSE;
// optWhichMusic = (opts->music == OPTVAL_3DO) ? OPT_3DO : OPT_PC; // optWhichMusic = (opts->music == OPTVAL_3DO) ? OPT_3DO : OPT_PC;
optWhichMenu = (opts->menu == OPTVAL_3DO) ? OPT_3DO : OPT_PC; optWhichMenu = (opts->menu == OPTVAL_3DO) ? OPT_3DO : OPT_PC;
@@ -1366,6 +1535,7 @@ SetGlobalOptions (GLOBALOPTS *opts)
res_PutBoolean ("config.positionalsfx", opts->stereo == OPTVAL_ENABLED); res_PutBoolean ("config.positionalsfx", opts->stereo == OPTVAL_ENABLED);
res_PutBoolean ("config.pulseshield", opts->shield == OPTVAL_3DO); res_PutBoolean ("config.pulseshield", opts->shield == OPTVAL_3DO);
res_PutBoolean ("config.keepaspectratio", opts->keepaspect == OPTVAL_ENABLED); res_PutBoolean ("config.keepaspectratio", opts->keepaspect == OPTVAL_ENABLED);
res_PutInteger ("config.gamma", (int) (optGamma * GAMMA_SCALE + 0.5));
res_PutInteger ("config.player1control", opts->player1); res_PutInteger ("config.player1control", opts->player1);
res_PutInteger ("config.player2control", opts->player2); res_PutInteger ("config.player2control", opts->player2);
+1
View File
@@ -80,6 +80,7 @@ typedef struct globalopts_struct {
OPT_CONSOLETYPE menu, text, cscan, scroll, intro, meleezoom, shield; OPT_CONSOLETYPE menu, text, cscan, scroll, intro, meleezoom, shield;
CONTROL_TEMPLATE player1, player2; CONTROL_TEMPLATE player1, player2;
int speechvol, musicvol, sfxvol; int speechvol, musicvol, sfxvol;
int gamma;
} GLOBALOPTS; } GLOBALOPTS;
void SetupMenu (void); void SetupMenu (void);