/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

// menu_video.c -- the video options menu

#include "client.h"
#include "qmenu.h"

extern cvar_t *vid_ref;
/*extern cvar_t *vid_fullscreen;
extern cvar_t *vid_gamma;
static cvar_t *gl_mode;
static cvar_t *gl_driver;
static cvar_t *gl_picmip;
static cvar_t *gl_texturemode;
static cvar_t *gl_anisotropic;
static cvar_t *gl_anisotropic_avail;
static cvar_t *gl_ext_texture_compression;
static cvar_t *gl_swapinterval;
static cvar_t *con_MENU_FONT_SIZE;*/

// Knightmare- cvars for advanced GL options menu
cvar_t	*intensity;
/*cvar_t	*gl_modulate;
cvar_t	*r_overbrightbits;
cvar_t	*gl_trans_lightmaps;
cvar_t	*gl_pixel_shader_warp;
cvar_t	*r_waterwave;
cvar_t	*gl_particle_overdraw;
cvar_t	*r_model_shading;
cvar_t	*gl_shadows;
cvar_t	*r_shelltype;
cvar_t	*gl_glass_envmaps;
cvar_t	*gl_screenshot_jpeg;
cvar_t	*gl_screenshot_jpeg_quality;
cvar_t	*r_saveshotsize;*/
// end Knightmare

extern void M_ForceMenuOff( void );
void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) );

/*
====================================================================

MENU INTERACTION

====================================================================
*/

#define OPENGL_MENU   0
#define OPENGL_ADVANCED_MENU   1

static menuframework_s	s_video_menu;
static menuframework_s	s_video_menu_advanced; // Knightmare added
static menuframework_s *s_current_menu;

static menulist_s		s_mode_list;
static menulist_s  		s_fs_box;
static menuslider_s		s_brightness_slider;
static menulist_s		s_texqual_box;
static menulist_s		s_texfilter_box;
static menulist_s		s_aniso_box;
static menulist_s  		s_texcompress_box;
static menulist_s  		s_vsync_box;
static menuaction_s		s_advanced_action; // Knightmare added
//Knightmare- replace cancel with apply, thnx to MrG
static menuaction_s		s_defaults_action;
static menuaction_s		s_apply_action;
static menuaction_s		s_backmain_action;


// Knightmare- items for advanced video options menu
static menuseparator_s	s_options_advanced_header;	
static menuslider_s		s_lightmapscale_slider;
static menuslider_s		s_textureintensity_slider;
static menulist_s  		s_overbrights_box;
static menulist_s  		s_trans_lightmap_box;
static menulist_s  		s_texshader_warp_box;
static menuslider_s  	s_waterwave_slider;
static menuslider_s		s_particle_comp_slider;
static menulist_s		s_particle_overdraw_box;
static menulist_s		s_lightbloom_box;
static menuslider_s		s_decal_slider;
static menulist_s		s_modelshading_box;
static menulist_s		s_glshadows_box;
//static menulist_s  	s_ent_envmap_box;
static menulist_s  		s_ent_shell_box;
static menulist_s  		s_glass_envmap_box;
static menulist_s  		s_screenshotjpeg_box;
static menuslider_s  	s_screenshotjpegquality_slider;
static menulist_s  		s_saveshotsize_box;
static menuaction_s		s_advanced_apply_action;
static menuaction_s		s_back_action;
// end Knightmare

static float ClampCvar( float min, float max, float value )
{
	if ( value < min ) return min;
	if ( value > max ) return max;
	return value;
}

static void CancelChanges( void *unused )
{
	extern void M_PopMenu( void );

	M_PopMenu();
}


/*
=======================================================================

ADVANCED VIDEO MENU

=======================================================================
*/
static void VID_MenuAdvancedSetValues ( void )
{
	Cvar_SetValue( "gl_modulate", ClampCvar( 1, 2, Cvar_VariableValue("gl_modulate") ) );
	s_lightmapscale_slider.curvalue = (Cvar_VariableValue("gl_modulate") -1) * 10;

	Cvar_SetValue( "intensity", ClampCvar( 1, 2, Cvar_VariableValue("intensity") ) );
	s_textureintensity_slider.curvalue = (Cvar_VariableValue("intensity") -1) * 10;

	Cvar_SetValue( "r_overbrightbits", ClampCvar( 1, 2, Cvar_VariableValue("r_overbrightbits") ) );
	if (Cvar_VariableValue("r_overbrightbits") == 1)
		s_overbrights_box.curvalue = 0;
	else
		s_overbrights_box.curvalue = 1;

	Cvar_SetValue( "gl_trans_lightmaps", ClampCvar( 0, 1, Cvar_VariableValue("gl_trans_lightmaps") ) );
	s_trans_lightmap_box.curvalue	= Cvar_VariableValue("gl_trans_lightmaps");

	Cvar_SetValue( "gl_glass_envmaps", ClampCvar( 0, 1, Cvar_VariableValue("gl_glass_envmaps") ) );
	s_glass_envmap_box.curvalue	= Cvar_VariableValue("gl_glass_envmaps");

	Cvar_SetValue( "gl_pixel_shader_warp", ClampCvar( 0, 1, Cvar_VariableValue("gl_pixel_shader_warp") ) );
	s_texshader_warp_box.curvalue	= Cvar_VariableValue("gl_pixel_shader_warp");

	s_waterwave_slider.curvalue		= Cvar_VariableValue("r_waterwave");

	Cvar_SetValue( "cl_particle_scale", ClampCvar( 0, 5, Cvar_VariableValue("cl_particle_scale") ) );
	s_particle_comp_slider.curvalue	= (Cvar_VariableValue("cl_particle_scale") -3)*-1+3;

	Cvar_SetValue( "gl_particle_overdraw", ClampCvar( 0, 1, Cvar_VariableValue("gl_particle_overdraw") ) );
	s_particle_overdraw_box.curvalue	= Cvar_VariableValue("gl_particle_overdraw");

	Cvar_SetValue( "r_bloom", ClampCvar( 0, 1, Cvar_VariableValue("r_bloom") ) );
	s_lightbloom_box.curvalue	= Cvar_VariableValue("r_bloom");

	Cvar_SetValue( "r_decals", ClampCvar (0, 1000, Cvar_VariableValue("r_decals")) );
	s_decal_slider.curvalue		= Cvar_VariableValue("r_decals") / 50;

	Cvar_SetValue( "r_model_shading", ClampCvar( 0, 2, Cvar_VariableValue("r_model_shading") ) );
	s_modelshading_box.curvalue	= Cvar_VariableValue("r_model_shading");

#ifdef PROJECTION_SHADOWS
	Cvar_SetValue( "gl_shadows", ClampCvar( 0, 3, Cvar_VariableValue("gl_shadows") ) );
#else
	Cvar_SetValue( "gl_shadows", ClampCvar( 0, 2, Cvar_VariableValue("gl_shadows") ) );
#endif
	s_glshadows_box.curvalue	= Cvar_VariableValue("gl_shadows");

	Cvar_SetValue( "r_shelltype", ClampCvar( 0, 2, Cvar_VariableValue("r_shelltype") ) );
	s_ent_shell_box.curvalue	= Cvar_VariableValue("r_shelltype");

	Cvar_SetValue( "gl_screenshot_jpeg", ClampCvar( 0, 1, Cvar_VariableValue("gl_screenshot_jpeg") ) );
	s_screenshotjpeg_box.curvalue	= Cvar_VariableValue("gl_screenshot_jpeg");

	Cvar_SetValue( "gl_screenshot_jpeg_quality", ClampCvar( 50, 100, Cvar_VariableValue("gl_screenshot_jpeg_quality") ) );
	s_screenshotjpegquality_slider.curvalue	= (Cvar_VariableValue("gl_screenshot_jpeg_quality") -50) / 5;

	Cvar_SetValue( "r_saveshotsize", ClampCvar( 0, 1, Cvar_VariableValue("r_saveshotsize") ) );
	s_saveshotsize_box.curvalue	= Cvar_VariableValue("r_saveshotsize");
}

static void LightMapScaleCallback ( void *unused )
{
	Cvar_SetValue( "gl_modulate", s_lightmapscale_slider.curvalue / 10 + 1);
}

static void TextureIntensCallback ( void *unused )
{
	Cvar_SetValue( "intensity", s_textureintensity_slider.curvalue / 10 + 1);
}

static void OverbrightsCallback ( void *unused )
{
	Cvar_SetValue( "r_overbrightbits", s_overbrights_box.curvalue + 1);
}

static void TransFullbrightCallback ( void *unused )
{
	Cvar_SetValue( "gl_trans_lightmaps", s_trans_lightmap_box.curvalue);
}

static void GlassEnvmapCallback ( void *unused )
{
	Cvar_SetValue( "gl_glass_envmaps", s_glass_envmap_box.curvalue);
}

static void TexShaderWarpCallback ( void *unused )
{
	Cvar_SetValue( "gl_pixel_shader_warp", s_texshader_warp_box.curvalue);
}

static void WaterWaveCallback ( void *unused )
{
	Cvar_SetValue( "r_waterwave", s_waterwave_slider.curvalue);
}

static void ParticleCompFunc( void *unused )
{
	Cvar_SetValue( "cl_particle_scale", (s_particle_comp_slider.curvalue-3)*-1+3);
}

static void ParticleOverdrawCallback( void *unused )
{
	Cvar_SetValue( "gl_particle_overdraw", s_particle_overdraw_box.curvalue);
}

static void LightBloomCallback( void *unused )
{
	Cvar_SetValue( "r_bloom", s_lightbloom_box.curvalue);
}

// Knightmare- decal option
static void DecalFunc( void *unused )
{
	Cvar_SetValue( "r_decals", s_decal_slider.curvalue * 50);
}

static void ModelShadingCallback ( void *unused )
{
	Cvar_SetValue( "r_model_shading", s_modelshading_box.curvalue);
}

static void GLShadowsCallback ( void *unused )
{
	Cvar_SetValue( "gl_shadows", s_glshadows_box.curvalue);
}

static void EntShellCallback ( void *unused )
{
	Cvar_SetValue( "r_shelltype", s_ent_shell_box.curvalue);
}

static void JPEGScreenshotCallback ( void *unused )
{
	Cvar_SetValue( "gl_screenshot_jpeg", s_screenshotjpeg_box.curvalue);
}

static void JPEGScreenshotQualityCallback ( void *unused )
{
	Cvar_SetValue( "gl_screenshot_jpeg_quality", (s_screenshotjpegquality_slider.curvalue * 5 + 50));
}

static void SaveshotSizeCallback ( void *unused )
{
	Cvar_SetValue( "r_saveshotsize", s_saveshotsize_box.curvalue);
}

static void AdvancedMenuApplyChanges ( void *unused )
{
//	extern void M_PopMenu( void );
	// update for modified intensity
	if ( intensity->modified )
		vid_ref->modified = true;
//	M_PopMenu();
}

/*
** VID_MenuAdvancedInit
*/
void VID_MenuAdvancedInit (void)
{
	static const char *yesno_names[] =
	{
		"no",
		"yes",
		0
	};
	static const char *shading_names[] =
	{
		"off",
		"low",
		"high",
		0
	};
#ifdef PROJECTION_SHADOWS
	static const char *shadow_names[] =
	{
		"no",
		"static planar",
		"dynamic planar",
		"projection",
		0
	};
#else
	static const char *shadow_names[] =
	{
		"no",
		"static",
		"dynamic",
		0
	};
#endif
	static const char *ifsupported_names[] =
	{
		"no",
		"if supported",
		0
	};
	static const char *shell_names[] =
	{
		"solid",
		"flowing",
		"envmap",
		0
	};
	int y = 0;

	intensity = Cvar_Get ("intensity", "1", 0);
	/*gl_modulate = Cvar_Get( "gl_modulate", "1", CVAR_ARCHIVE );
	r_overbrightbits = Cvar_Get ("r_overbrightbits", "2", CVAR_ARCHIVE);
	gl_trans_lightmaps = Cvar_Get( "gl_trans_lightmaps", "1", CVAR_ARCHIVE );
	gl_pixel_shader_warp = Cvar_Get( "gl_pixel_shader_warp", "1", CVAR_ARCHIVE );
	r_waterwave = Cvar_Get ("r_waterwave", "0", CVAR_ARCHIVE );
	gl_particle_overdraw = Cvar_Get ("gl_particle_overdraw", "0", CVAR_ARCHIVE );
	r_model_shading = Cvar_Get ("r_model_shading", "1", CVAR_ARCHIVE );
	gl_shadows = Cvar_Get ("gl_shadows", "0", CVAR_ARCHIVE );
	r_shelltype = Cvar_Get( "r_shelltype", "1", CVAR_ARCHIVE );
	gl_glass_envmaps = Cvar_Get( "gl_glass_envmaps", "1", CVAR_ARCHIVE );
	gl_screenshot_jpeg = Cvar_Get( "gl_screenshot_jpeg", "1", CVAR_ARCHIVE );
	gl_screenshot_jpeg_quality = Cvar_Get( "gl_screenshot_jpeg_quality", "85", CVAR_ARCHIVE );	// Heffo - JPEG Screenshots
	r_saveshotsize = Cvar_Get( "r_saveshotsize", "1", CVAR_ARCHIVE );*/

	s_video_menu_advanced.x = viddef.width * 0.50;
	s_video_menu_advanced.y = 0;
	s_video_menu_advanced.nitems = 0;

	s_options_advanced_header.generic.type	= MTYPE_SEPARATOR;
	s_options_advanced_header.generic.name	= "Advanced Options";
	s_options_advanced_header.generic.x		= MENU_FONT_SIZE/2 * strlen(s_options_advanced_header.generic.name);
	s_options_advanced_header.generic.y		= y += 2*(MENU_FONT_SIZE+2);

	s_lightmapscale_slider.generic.type		= MTYPE_SLIDER;
	s_lightmapscale_slider.generic.x		= 0;
	s_lightmapscale_slider.generic.y		= y += 3*(MENU_FONT_SIZE+2); //10
	s_lightmapscale_slider.generic.name		= "lightmap scale";
	s_lightmapscale_slider.generic.callback = LightMapScaleCallback;
	s_lightmapscale_slider.minvalue			= 0;
	s_lightmapscale_slider.maxvalue			= 10;

	s_textureintensity_slider.generic.type		= MTYPE_SLIDER;
	s_textureintensity_slider.generic.x			= 0;
	s_textureintensity_slider.generic.y			= y += (MENU_FONT_SIZE+2); //20
	s_textureintensity_slider.generic.name		= "texture intensity";
	s_textureintensity_slider.generic.callback	= TextureIntensCallback;
	s_textureintensity_slider.minvalue			= 0;
	s_textureintensity_slider.maxvalue			= 10;

	s_overbrights_box.generic.type		= MTYPE_SPINCONTROL;
	s_overbrights_box.generic.x			= 0;
	s_overbrights_box.generic.y			= y += (MENU_FONT_SIZE+2); //30
	s_overbrights_box.generic.name		= "overbrights";
	s_overbrights_box.generic.callback	= OverbrightsCallback;
	s_overbrights_box.itemnames			= yesno_names;

	s_trans_lightmap_box.generic.type		= MTYPE_SPINCONTROL;
	s_trans_lightmap_box.generic.x			= 0;
	s_trans_lightmap_box.generic.y			= y += (MENU_FONT_SIZE+2); //40
	s_trans_lightmap_box.generic.name		= "translucent lighting";
	s_trans_lightmap_box.generic.callback	= TransFullbrightCallback;
	s_trans_lightmap_box.itemnames			= yesno_names;

	s_glass_envmap_box.generic.type		= MTYPE_SPINCONTROL;
	s_glass_envmap_box.generic.x		= 0;
	s_glass_envmap_box.generic.y		= y += (MENU_FONT_SIZE+2); //50
	s_glass_envmap_box.generic.name		= "glass envmaps";
	s_glass_envmap_box.generic.callback	= GlassEnvmapCallback;
	s_glass_envmap_box.itemnames		= yesno_names;
	s_glass_envmap_box.generic.statusbar	= "enable environment mapping on transparent surfaces";

	s_texshader_warp_box.generic.type		= MTYPE_SPINCONTROL;
	s_texshader_warp_box.generic.x			= 0;
	s_texshader_warp_box.generic.y			= y += (MENU_FONT_SIZE+2); //60
	s_texshader_warp_box.generic.name		= "texture shader warp";
	s_texshader_warp_box.generic.callback	= TexShaderWarpCallback;
	s_texshader_warp_box.itemnames			= ifsupported_names;

	s_waterwave_slider.generic.type		= MTYPE_SLIDER;
	s_waterwave_slider.generic.x		= 0;
	s_waterwave_slider.generic.y		= y += (MENU_FONT_SIZE+2); //70
	s_waterwave_slider.generic.name		= "water wave size";
	s_waterwave_slider.generic.callback	= WaterWaveCallback;
	s_waterwave_slider.minvalue			= 0;
	s_waterwave_slider.maxvalue			= 24;
	s_waterwave_slider.generic.statusbar = "size of waves on flat water surfaces";

	s_particle_comp_slider.generic.type			= MTYPE_SLIDER;
	s_particle_comp_slider.generic.x			= 0;
	s_particle_comp_slider.generic.y			= y += 2*(MENU_FONT_SIZE+2); //90
	s_particle_comp_slider.generic.name			= "particle effect complexity";
	s_particle_comp_slider.generic.callback		= ParticleCompFunc;
	s_particle_comp_slider.minvalue				= 1;
	s_particle_comp_slider.maxvalue				= 5;
	s_particle_comp_slider.generic.statusbar	= "lower = faster performance";

	s_particle_overdraw_box.generic.type		= MTYPE_SPINCONTROL;
	s_particle_overdraw_box.generic.x			= 0;
	s_particle_overdraw_box.generic.y			= y += (MENU_FONT_SIZE+2); //100
	s_particle_overdraw_box.generic.name		= "particle overdraw";
	s_particle_overdraw_box.generic.callback	= ParticleOverdrawCallback;
	s_particle_overdraw_box.itemnames			= yesno_names;
	s_particle_overdraw_box.generic.statusbar	= "redraw particles over trans surfaces";

	s_lightbloom_box.generic.type		= MTYPE_SPINCONTROL;
	s_lightbloom_box.generic.x			= 0;
	s_lightbloom_box.generic.y			= y += (MENU_FONT_SIZE+2); //110
	s_lightbloom_box.generic.name		= "light blooms";
	s_lightbloom_box.generic.callback	= LightBloomCallback;
	s_lightbloom_box.itemnames			= yesno_names;

	s_decal_slider.generic.type			= MTYPE_SLIDER;
	s_decal_slider.generic.x			= 0;
	s_decal_slider.generic.y			= y += (MENU_FONT_SIZE+2); //120
	s_decal_slider.generic.name			= "decal quantity";
	s_decal_slider.generic.callback		= DecalFunc;
	s_decal_slider.minvalue				= 0;
	s_decal_slider.maxvalue				= 20;
	s_decal_slider.generic.statusbar	= "how many decals to display at once (max = 1000)";

	s_modelshading_box.generic.type		= MTYPE_SPINCONTROL;
	s_modelshading_box.generic.x		= 0;
	s_modelshading_box.generic.y		= y += (MENU_FONT_SIZE+2); //130
	s_modelshading_box.generic.name		= "model shading";
	s_modelshading_box.generic.callback	= ModelShadingCallback;
	s_modelshading_box.itemnames		= shading_names;
	s_modelshading_box.generic.statusbar	= "level of shading to use on models";

	s_glshadows_box.generic.type		= MTYPE_SPINCONTROL;
	s_glshadows_box.generic.x			= 0;
	s_glshadows_box.generic.y			= y += (MENU_FONT_SIZE+2); //140
	s_glshadows_box.generic.name		= "entity shadows";
	s_glshadows_box.generic.callback	= GLShadowsCallback;
	s_glshadows_box.itemnames			= shadow_names;
	s_glshadows_box.generic.statusbar	= "type of model shadows to draw";

	s_ent_shell_box.generic.type		= MTYPE_SPINCONTROL;
	s_ent_shell_box.generic.x			= 0;
	s_ent_shell_box.generic.y			= y += (MENU_FONT_SIZE+2); //150
	s_ent_shell_box.generic.name		= "entity shell type";
	s_ent_shell_box.generic.callback	= EntShellCallback;
	s_ent_shell_box.itemnames			= shell_names;
	s_ent_shell_box.generic.statusbar	= "envmap effect may cause instability on ATI cards";

	s_screenshotjpeg_box.generic.type		= MTYPE_SPINCONTROL;
	s_screenshotjpeg_box.generic.x			= 0;
	s_screenshotjpeg_box.generic.y			= y += 2*(MENU_FONT_SIZE+2); //170
	s_screenshotjpeg_box.generic.name		= "JPEG screenshots";
	s_screenshotjpeg_box.generic.callback	= JPEGScreenshotCallback;
	s_screenshotjpeg_box.itemnames			= yesno_names;
	s_screenshotjpeg_box.generic.statusbar	= "whether to take JPG screenshots instead of TGA";

	s_screenshotjpegquality_slider.generic.type	= MTYPE_SLIDER;
	s_screenshotjpegquality_slider.generic.x	= 0;
	s_screenshotjpegquality_slider.generic.y	= y += (MENU_FONT_SIZE+2); //180
	s_screenshotjpegquality_slider.generic.name	= "JPEG screenshot quality";
	s_screenshotjpegquality_slider.generic.callback		= JPEGScreenshotQualityCallback;
	s_screenshotjpegquality_slider.minvalue		= 0;
	s_screenshotjpegquality_slider.maxvalue		= 10;
	s_screenshotjpegquality_slider.generic.statusbar = "quality of JPG screenshots, 50-100%";

	s_saveshotsize_box.generic.type			= MTYPE_SPINCONTROL;
	s_saveshotsize_box.generic.x			= 0;
	s_saveshotsize_box.generic.y			= y += (MENU_FONT_SIZE+2); //190
	s_saveshotsize_box.generic.name			= "hi-res saveshots";
	s_saveshotsize_box.generic.callback		= SaveshotSizeCallback;
	s_saveshotsize_box.itemnames			= yesno_names;
	s_saveshotsize_box.generic.statusbar	= "hi-res saveshots when running at 800x600 or higher";

	s_advanced_apply_action.generic.type		= MTYPE_ACTION;
	s_advanced_apply_action.generic.name		= "apply changes";
	s_advanced_apply_action.generic.x			= 0;
	s_advanced_apply_action.generic.y			= y += 2*(MENU_FONT_SIZE+2); //210
	s_advanced_apply_action.generic.callback	= AdvancedMenuApplyChanges;

	s_back_action.generic.type = MTYPE_ACTION;
	s_back_action.generic.name = "back";
	s_back_action.generic.x    = 0;
	s_back_action.generic.y    = y += 2*(MENU_FONT_SIZE+2); //230
	s_back_action.generic.callback = CancelChanges;

	VID_MenuAdvancedSetValues();

	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_options_advanced_header );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_lightmapscale_slider );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_textureintensity_slider );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_overbrights_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_trans_lightmap_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_glass_envmap_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_texshader_warp_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_waterwave_slider );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_particle_comp_slider );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_particle_overdraw_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_lightbloom_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_decal_slider );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_modelshading_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_glshadows_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_ent_shell_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_screenshotjpeg_box );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_screenshotjpegquality_slider );
	Menu_AddItem( &s_video_menu_advanced, ( void * ) &	s_saveshotsize_box );

	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_advanced_apply_action );

	Menu_AddItem( &s_video_menu_advanced, ( void * ) &s_back_action );

	Menu_Center( &s_video_menu_advanced );

	s_video_menu_advanced.x -= MENU_FONT_SIZE;	
}
// end Knightmare

/*
================
VID_MenuAdvancedDraw
================
*/
void VID_MenuAdvancedDraw (void)
{
	//int w, h;

	s_current_menu = &s_video_menu_advanced;

	// draw the banner
	//R_DrawGetPicSize( &w, &h, "m_banner_video" );
	//R_DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
	M_Banner("m_banner_video");

	// move cursor to a reasonable starting position
	Menu_AdjustCursor( &s_video_menu_advanced, 1 );

	// draw the menu
	Menu_Draw( &s_video_menu_advanced );
}

void M_Menu_Video_Advanced_f (void)
{
	VID_MenuAdvancedInit();
	M_PushMenu( VID_MenuAdvancedDraw, VID_MenuKey );
}

static void AdvancedOptions( void *s )
{
	M_Menu_Video_Advanced_f ();
}


/*
=======================================================================

VIDEO MENU

=======================================================================
*/


static void BrightnessCallback( void *s )
{
	// invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
	Cvar_SetValue( "vid_gamma", ( 0.8 - ( s_brightness_slider.curvalue/20.0 - 0.5 ) ) + 0.5 ); // was /10
}

static void VsyncCallback ( void *unused )
{
	Cvar_SetValue( "gl_swapinterval", s_vsync_box.curvalue);
}

static void ResetDefaults ( void *unused )
{
	Cvar_SetToDefault  ("vid_fullscreen");
	Cvar_SetToDefault  ("vid_gamma");
	Cvar_SetToDefault  ("gl_mode");
	Cvar_SetToDefault  ("gl_texturemode");
	Cvar_SetToDefault  ("gl_anisotropic");
	Cvar_SetToDefault  ("gl_picmip");
	Cvar_SetToDefault  ("gl_ext_texture_compression");
	Cvar_SetToDefault  ("gl_swapinterval");

	Cvar_SetToDefault  ("gl_modulate");
	Cvar_SetToDefault  ("intensity");
	Cvar_SetToDefault  ("r_overbrightbits");
	Cvar_SetToDefault  ("gl_trans_lightmaps");
	Cvar_SetToDefault  ("gl_pixel_shader_warp");
	Cvar_SetToDefault  ("r_waterwave");
	Cvar_SetToDefault  ("cl_particle_scale");
	Cvar_SetToDefault  ("gl_particle_overdraw");
	Cvar_SetToDefault  ("r_decals");
	Cvar_SetToDefault  ("r_model_shading");
	Cvar_SetToDefault  ("gl_shadows");
	Cvar_SetToDefault  ("r_shelltype");
	Cvar_SetToDefault  ("gl_glass_envmaps");
	Cvar_SetToDefault  ("gl_screenshot_jpeg");
	Cvar_SetToDefault  ("gl_screenshot_jpeg_quality");
	Cvar_SetToDefault  ("r_saveshotsize");

	VID_MenuInit();
}

static void prepareVideoRefresh( void )
{
	//set the right mode for refresh
#ifdef _WIN32
	Cvar_Set( "vid_ref", "gl" );
	Cvar_Set( "gl_driver", "opengl32" );
#else
	Cvar_Set( "vid_ref", "kmglx" ); /* Backward compatibility with kmquake2 0.16 */
	Cvar_Set( "gl_driver", "libGL.so" );
#endif
	//tell them theyr're modified so they refresh
	//if ( vid_gamma->modified )
	//	vid_ref->modified = true;
	//if ( gl_driver->modified )
	//	vid_ref->modified = true;
}


static void ApplyChanges( void *unused )
{
	if (s_texfilter_box.curvalue == 0)
		Cvar_Set("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST");
	else if (s_texfilter_box.curvalue == 1)
		Cvar_Set("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR");

	/*if (s_texfilter_box.curvalue == 0)
		Cvar_Set("gl_texturemode", "GL_NEAREST");
	else if (s_texfilter_box.curvalue == 1)
		Cvar_Set("gl_texturemode", "GL_NEAREST_MIPMAP_NEAREST");
	else if (s_texfilter_box.curvalue == 2)
		Cvar_Set("gl_texturemode", "GL_LINEAR");
	else if (s_texfilter_box.curvalue == 3)
		Cvar_Set("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST");
	else if (s_texfilter_box.curvalue == 4)
		Cvar_Set("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR");*/

	Cvar_SetValue( "gl_mode", s_mode_list.curvalue + 3 ); // offset for eliminating < 640x480 modes
	Cvar_SetValue( "vid_fullscreen", s_fs_box.curvalue );
	// invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
	Cvar_SetValue( "vid_gamma", ( 0.8 - ( s_brightness_slider.curvalue/20.0 - 0.5 ) ) + 0.5 ); // was /10
	Cvar_SetValue( "gl_picmip", 3-s_texqual_box.curvalue );

	switch ((int)s_aniso_box.curvalue)
	{
		case 1: Cvar_SetValue( "gl_anisotropic", 2.0 ); break;
		case 2: Cvar_SetValue( "gl_anisotropic", 4.0 ); break;
		case 3: Cvar_SetValue( "gl_anisotropic", 8.0 ); break;
		case 4: Cvar_SetValue( "gl_anisotropic", 16.0 ); break;
		default:
		case 0: Cvar_SetValue( "gl_anisotropic", 0.0 ); break;
	}

	Cvar_SetValue( "gl_ext_texture_compression", s_texcompress_box.curvalue );
	Cvar_SetValue( "gl_swapinterval", s_vsync_box.curvalue );

	prepareVideoRefresh ();

	M_ForceMenuOff();
}


// Knightmare added
int texfilter_box_setval (void)
{
	char *texmode = Cvar_VariableString("gl_texturemode");
	if (!Q_strcasecmp(texmode, "GL_LINEAR_MIPMAP_NEAREST"))
		return 0;
	else // if (!Q_strcasecmp(texmode, "GL_LINEAR_MIPMAP_LINEAR"))
		return 1;
	/*if (!Q_strcasecmp(texmode, "GL_NEAREST"))
		return 0;
	else if (!Q_strcasecmp(texmode, "GL_NEAREST_MIPMAP_NEAREST"))
		return 1;
	else if (!Q_strcasecmp(texmode, "GL_LINEAR"))
		return 2;
	else if (!Q_strcasecmp(texmode, "GL_LINEAR_MIPMAP_NEAREST"))
		return 3;
	else // if (!Q_strcasecmp(texmode, "GL_LINEAR_MIPMAP_LINEAR"))
		return 4;*/
}


static const char *aniso0_names[] =
{
	"not supported",
	0
};

static const char *aniso2_names[] =
{
	"off",
	"2x",
	0
};

static const char *aniso4_names[] =
{
	"off",
	"2x",
	"4x",
	0
};

static const char *aniso8_names[] =
{
	"off",
	"2x",
	"4x",
	"8x",
	0
};

static const char *aniso16_names[] =
{
	"off",
	"2x",
	"4x",
	"8x",
	"16x",
	0
};

static const char **GetAnisoNames ()
{
	float aniso_avail = Cvar_VariableValue("gl_anisotropic_avail");
	if (aniso_avail < 2.0)
		return aniso0_names;
	else if (aniso_avail < 4.0)
		return aniso2_names;
	else if (aniso_avail < 8.0)
		return aniso4_names;
	else if (aniso_avail < 16.0)
		return aniso8_names;
	else // >= 16.0
		return aniso16_names;
}


float GetAnisoCurValue ()
{
	float aniso_avail = Cvar_VariableValue("gl_anisotropic_avail");
	float anisoValue = ClampCvar (0, aniso_avail, Cvar_VariableValue("gl_anisotropic"));
	if (aniso_avail == 0) // not available
		return 0;
	if (anisoValue < 2.0)
		return 0;
	else if (anisoValue < 4.0)
		return 1;
	else if (anisoValue < 8.0)
		return 2;
	else if (anisoValue < 16.0)
		return 3;
	else // >= 16.0
		return 4;
}


/*
** VID_MenuInit
*/
void VID_MenuInit (void)
{
	// Knightmare- added 1280x1024, 1400x1050, 856x480, 1024x480 modes, removed 320x240, 400x300, 512x384 modes
	static const char *resolutions[] = 
	{
		"[640x480  ]",
		"[800x600  ]",
		"[960x720  ]",
		"[1024x768 ]",
		"[1152x864 ]",
		"[1280x960 ]",
		"[1280x1024]", // Knightmare added
		"[1400x1050]", // Knightmare added
		"[1600x1200]",
		"[1920x1440]", // Knightmare added
		"[2048x1536]",
		"[856x480  ]", // Knightmare added
		"[1024x480 ]", // Knightmare added
		"[1280x800 ]", // Knightmare added
		"[1680x1050]", // Knightmare added
		"[1920x1200]", // Knightmare added
		0
	};
	static const char *yesno_names[] =
	{
		"no",
		"yes",
		0
	};
	static const char *mip_names[] =
	{
		//"none",
		//"nearest",
		//"linear",
		"bilinear",
		"trilinear",
		0
	};
	static const char *lmh_names[] =
	{
		"low",
		"medium",
		"high",
		"highest",
		0
	};

	int  y;

	/*if ( !gl_driver )
		gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
	if ( !gl_picmip )
		gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
	if ( !gl_mode )
		gl_mode = Cvar_Get( "gl_mode", "3", 0 ); // default to 640x480
	if ( !gl_swapinterval )
		gl_swapinterval = Cvar_Get( "gl_swapinterval", "1", CVAR_ARCHIVE );
	if ( !gl_texturemode )
		gl_texturemode = Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
	if ( !gl_anisotropic )
		gl_anisotropic = Cvar_Get( "gl_anisotropic", "0", CVAR_ARCHIVE );
	if ( !gl_anisotropic_avail )
		gl_anisotropic_avail = Cvar_Get( "gl_anisotropic_avail", "0", 0 );
	if ( !gl_ext_texture_compression )
		gl_ext_texture_compression = Cvar_Get( "gl_ext_texture_compression", "0", CVAR_ARCHIVE );*/

	s_mode_list.curvalue = Cvar_VariableValue("gl_mode") - 3; // offset for getting rid of < 640x480 resolutions
	if (s_mode_list.curvalue < 0) s_mode_list.curvalue = 0; // clamp to minimum

	if ( !con_font_size )
		con_font_size = Cvar_Get ("con_font_size", "8", CVAR_ARCHIVE);

	s_video_menu.x = viddef.width * 0.50;
	s_video_menu.y =  0;
	s_video_menu.nitems = 0;


	y = 0;
	s_mode_list.generic.type = MTYPE_SPINCONTROL;
	s_mode_list.generic.name = "video mode";
	s_mode_list.generic.x = 0;
	s_mode_list.generic.y = y;
	s_mode_list.itemnames = resolutions;

	s_fs_box.generic.type = MTYPE_SPINCONTROL;
	s_fs_box.generic.x	= 0;
	s_fs_box.generic.y	= y += (MENU_FONT_SIZE+2); //10
	s_fs_box.generic.name	= "fullscreen";
	s_fs_box.itemnames = yesno_names;
	s_fs_box.curvalue = Cvar_VariableValue("vid_fullscreen");

	s_brightness_slider.generic.type	= MTYPE_SLIDER;
	s_brightness_slider.generic.x	= 0;
	s_brightness_slider.generic.y	= y += (MENU_FONT_SIZE+2); //20
	s_brightness_slider.generic.name	= "brightness";
	s_brightness_slider.generic.callback = BrightnessCallback;
	s_brightness_slider.minvalue = 10; // was 5
	s_brightness_slider.maxvalue = 26; // was 13
	s_brightness_slider.curvalue = ( 1.3 - Cvar_VariableValue("vid_gamma") + 0.5 ) * 20; // was * 10

	s_texfilter_box.generic.type	= MTYPE_SPINCONTROL;
	s_texfilter_box.generic.x		= 0;
	s_texfilter_box.generic.y		= y += 2*(MENU_FONT_SIZE+2); //40
	s_texfilter_box.generic.name	= "texture filter";
	s_texfilter_box.curvalue		= texfilter_box_setval();
	s_texfilter_box.itemnames		= mip_names;

	s_aniso_box.generic.type	= MTYPE_SPINCONTROL;
	s_aniso_box.generic.x		= 0;
	s_aniso_box.generic.y		= y += (MENU_FONT_SIZE+2); //50
	s_aniso_box.generic.name	= "anisotropic filter";
	s_aniso_box.curvalue		= GetAnisoCurValue();
	s_aniso_box.itemnames		= GetAnisoNames();

	s_texqual_box.generic.type	= MTYPE_SPINCONTROL;
	s_texqual_box.generic.x		= 0;
	s_texqual_box.generic.y		= y += (MENU_FONT_SIZE+2); //60
	s_texqual_box.generic.name	= "texture quality";
	s_texqual_box.curvalue		= ClampCvar (0, 3, 3-Cvar_VariableValue("gl_picmip"));
	s_texqual_box.itemnames		= lmh_names;

	s_texcompress_box.generic.type		= MTYPE_SPINCONTROL;
	s_texcompress_box.generic.x			= 0;
	s_texcompress_box.generic.y			= y += (MENU_FONT_SIZE+2); //70
	s_texcompress_box.generic.name		= "texture compression";
	s_texcompress_box.itemnames			= yesno_names;
	s_texcompress_box.curvalue			= Cvar_VariableValue("gl_ext_texture_compression");

	s_vsync_box.generic.type	= MTYPE_SPINCONTROL;
	s_vsync_box.generic.x		= 0;
	s_vsync_box.generic.y		= y += 2*(MENU_FONT_SIZE+2); //90
	s_vsync_box.generic.name	= "video sync";
	s_vsync_box.generic.callback = VsyncCallback;
	s_vsync_box.curvalue		= Cvar_VariableValue("gl_swapinterval");
	s_vsync_box.itemnames		= yesno_names;
	s_vsync_box.generic.statusbar	= "sync framerate with monitor refresh";

	// Knightmare added
	s_advanced_action.generic.type = MTYPE_ACTION;
	s_advanced_action.generic.name = "advanced options";
	s_advanced_action.generic.x    = 0;
	s_advanced_action.generic.y    = y += 3*(MENU_FONT_SIZE+2); //120
	s_advanced_action.generic.callback = AdvancedOptions;

	s_defaults_action.generic.type = MTYPE_ACTION;
	s_defaults_action.generic.name = "reset to defaults";
	s_defaults_action.generic.x    = 0;
	s_defaults_action.generic.y    = y += 3*(MENU_FONT_SIZE+2); //150
	s_defaults_action.generic.callback = ResetDefaults;
	s_defaults_action.generic.statusbar	= "reset all video settings to internal defaults";

	//Knightmare- changed cancel to apply changes, thanx to MrG
	s_apply_action.generic.type = MTYPE_ACTION;
	s_apply_action.generic.name = "apply changes";
	s_apply_action.generic.x    = 0;
	s_apply_action.generic.y    = y += 2*(MENU_FONT_SIZE+2); //170
	s_apply_action.generic.callback = ApplyChanges;
	//end Knightmare

	s_backmain_action.generic.type = MTYPE_ACTION;
	s_backmain_action.generic.name = "back to main";
	s_backmain_action.generic.x    = 0;
	s_backmain_action.generic.y    = y += 2*(MENU_FONT_SIZE+2); //190
	s_backmain_action.generic.callback = M_BackMenu;

	Menu_AddItem( &s_video_menu, ( void * ) &s_mode_list );
	Menu_AddItem( &s_video_menu, ( void * ) &s_fs_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_brightness_slider );
	Menu_AddItem( &s_video_menu, ( void * ) &s_texfilter_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_aniso_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_texqual_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_texcompress_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_vsync_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_advanced_action ); // Knightmare added

	Menu_AddItem( &s_video_menu, ( void * ) &s_defaults_action );
	//Knightmare- changed cancel to apply changes, thanx to MrG
	Menu_AddItem( &s_video_menu, ( void * ) &s_apply_action );
	Menu_AddItem( &s_video_menu, ( void * ) &s_backmain_action );

	Menu_Center( &s_video_menu );
	s_video_menu.x -= MENU_FONT_SIZE;
}

/*
================
VID_MenuDraw
================
*/
void M_Banner( char *name );

void VID_MenuDraw (void)
{
	//int w, h;

	s_current_menu = &s_video_menu;

	// draw the banner
	//R_DrawGetPicSize( &w, &h, "m_banner_video" );
	//R_DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
	M_Banner("m_banner_video");

	// move cursor to a reasonable starting position
	Menu_AdjustCursor( &s_video_menu, 1 );

	// draw the menu
	Menu_Draw( &s_video_menu );
}


/*
================
VID_MenuKey
================
*/
const char *VID_MenuKey( int key )
{
	menuframework_s *m = s_current_menu;
	char *sound = NULL;

	switch ( key )
	{
	case K_ESCAPE:
		//Knightmare- changed to cancel on exit, thanx to MrG
		//ApplyChanges( 0 );
		CancelChanges(NULL);
		return NULL;
	case K_KP_UPARROW:
	case K_UPARROW:
		m->cursor--;
		Menu_AdjustCursor( m, -1 );
		sound = "misc/menu1.wav";
		break;
	case K_KP_DOWNARROW:
	case K_DOWNARROW:
		m->cursor++;
		Menu_AdjustCursor( m, 1 );
		sound = "misc/menu1.wav";
		break;
	case K_KP_LEFTARROW:
	case K_LEFTARROW:
		Menu_SlideItem( m, -1 );
		sound = "misc/menu1.wav";
		break;
	case K_KP_RIGHTARROW:
	case K_RIGHTARROW:
		Menu_SlideItem( m, 1 );
		sound = "misc/menu1.wav";
		break;
	case K_KP_ENTER:
	case K_ENTER:
		if ( !Menu_SelectItem( m ) )
			ApplyChanges( NULL );
		//sound = "misc/menu1.wav";
		break;
	}

	return sound;
}

void M_Menu_Video_f (void)
{
	VID_MenuInit();
	M_PushMenu( VID_MenuDraw, VID_MenuKey );
}
