/*
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.

*/

// ui_video.c -- the video options menu

#include "../client/client.h"
#include "ui_local.h"

extern cvar_t *vid_ref;

void Menu_Video_Init (void);

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

VIDEO MENU

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

static menuframework_s	s_video_menu;
static menulist_s		s_mode_list;
static menuseparator_s	s_customwidth_title;
static menuseparator_s	s_customheight_title;
static menufield_s		s_customwidth_field;
static menufield_s		s_customheight_field;
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_npot_mipmap_box;
//static menulist_s  		s_texcompress_box;
static menulist_s  		s_vsync_box;
static menulist_s		s_refresh_box;	// Knightmare- refresh rate option
static menulist_s  		s_adjust_fov_box;
static menuaction_s		s_advanced_action;
static menuaction_s		s_defaults_action;
static menuaction_s		s_apply_action;
static menuaction_s		s_backmain_action;

static void VidModeCallback ( void *unused )
{
	s_customwidth_title.generic.flags	= (s_mode_list.curvalue != 0) ? QMF_HIDDEN : 0;
	s_customwidth_field.generic.flags	= (s_mode_list.curvalue != 0) ? (QMF_NUMBERSONLY|QMF_HIDDEN) : QMF_NUMBERSONLY;
	s_customheight_title.generic.flags	= (s_mode_list.curvalue != 0) ? QMF_HIDDEN : 0;
	s_customheight_field.generic.flags	= (s_mode_list.curvalue != 0) ? (QMF_NUMBERSONLY|QMF_HIDDEN) : QMF_NUMBERSONLY;
}

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

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

static void AdjustFOVCallback ( void *unused )
{
	Cvar_SetValue( "cl_widescreen_fov", s_adjust_fov_box.curvalue);
}

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

static void ResetVideoDefaults ( void *unused )
{
	Cvar_SetToDefault ("vid_fullscreen");
	Cvar_SetToDefault ("vid_gamma");
	Cvar_SetToDefault ("r_mode");
	Cvar_SetToDefault ("r_texturemode");
	Cvar_SetToDefault ("r_anisotropic");
	Cvar_SetToDefault ("r_picmip");
	Cvar_SetToDefault ("r_ext_texture_compression");
	Cvar_SetToDefault ("r_swapinterval");
	Cvar_SetToDefault ("r_displayrefresh");
	Cvar_SetToDefault ("cl_widescreen_fov");

	Cvar_SetToDefault ("r_modulate");
	Cvar_SetToDefault ("r_intensity");
	Cvar_SetToDefault ("r_rgbscale");
	Cvar_SetToDefault ("r_trans_lighting");
	Cvar_SetToDefault ("r_warp_lighting");
	Cvar_SetToDefault ("r_lightcutoff");
	Cvar_SetToDefault ("r_glass_envmaps");
	Cvar_SetToDefault ("r_solidalpha");
	Cvar_SetToDefault ("r_pixel_shader_warp");
	Cvar_SetToDefault ("r_waterwave");
	Cvar_SetToDefault ("r_caustics");
	Cvar_SetToDefault ("r_particle_overdraw");
	Cvar_SetToDefault ("r_bloom");
	Cvar_SetToDefault ("r_model_shading");
	Cvar_SetToDefault ("r_shadows");
	Cvar_SetToDefault ("r_stencilTwoSide");
	Cvar_SetToDefault ("r_shelltype");
//	Cvar_SetToDefault ("r_screenshot_jpeg");
	Cvar_SetToDefault ("r_screenshot_format");
	Cvar_SetToDefault ("r_screenshot_jpeg_quality");
	Cvar_SetToDefault ("r_saveshotsize");

	Menu_Video_Init();
}

static void prepareVideoRefresh( void )
{
	// set the right mode for refresh
	Cvar_Set( "vid_ref", "gl" );
	Cvar_Set( "gl_driver", "opengl32" );

	// tell them they're modified so they refresh
	vid_ref->modified = true;
}


static void ApplyChanges( void *unused )
{
	int		temp, customW, customH;
	char	*customStr;

	temp = s_mode_list.curvalue;
	Cvar_SetValue( "r_mode", (temp == 0) ? -1 : temp + 2 ); // offset for eliminating < 640x480 modes
	if (temp == 0)	// Knightmare- use custom mode fields
	{
		customW  = atoi( s_customwidth_field.buffer );
		customH	= atoi( s_customheight_field.buffer );
		Cvar_SetValue( "r_customwidth", ClampCvar( 640, 99999, customW ) );
		Cvar_SetValue ("r_customheight", ClampCvar( 480, 99999, customH ) );

		// update fields in case values were clamped
		customStr = Cvar_VariableString("r_customwidth");
		Q_strncpyz( s_customwidth_field.buffer, customStr, sizeof(s_customwidth_field.buffer) );
		s_customwidth_field.cursor = strlen( customStr );
		
		customStr = Cvar_VariableString("r_customheight");
		Q_strncpyz(s_customheight_field.buffer, customStr, sizeof(s_customwidth_field.buffer) );
		s_customheight_field.cursor = strlen( customStr );
	}
	Cvar_SetValue( "vid_fullscreen", s_fs_box.curvalue );
	// invert sense so greater = brighter, and scale to a range of 0.3 to 1.3
	Cvar_SetValue( "vid_gamma", (1.3 - (s_brightness_slider.curvalue/20.0)) );
	Cvar_SetValue( "r_picmip", 3-s_texqual_box.curvalue );

	// Knightmare- refesh rate option
	switch (s_refresh_box.curvalue)
	{
	case 10:
		Cvar_SetValue ("r_displayrefresh", 150);
		break;
	case 9:
		Cvar_SetValue ("r_displayrefresh", 144);
		break;
	case 8:
		Cvar_SetValue ("r_displayrefresh", 120);
		break;
	case 7:
		Cvar_SetValue ("r_displayrefresh", 110);
		break;
	case 6:
		Cvar_SetValue ("r_displayrefresh", 100);
		break;
	case 5:
		Cvar_SetValue ("r_displayrefresh", 85);
		break;
	case 4:
		Cvar_SetValue ("r_displayrefresh", 75);
		break;
	case 3:
		Cvar_SetValue ("r_displayrefresh", 72);
		break;
	case 2:
		Cvar_SetValue ("r_displayrefresh", 70);
		break;
	case 1:
		Cvar_SetValue ("r_displayrefresh", 60);
		break;
	case 0:
	default:
		Cvar_SetValue ("r_displayrefresh", 0);
		break;
	}

	if (s_texfilter_box.curvalue == 0)
		Cvar_Set("r_texturemode", "GL_LINEAR_MIPMAP_NEAREST");
	else if (s_texfilter_box.curvalue == 1)
		Cvar_Set("r_texturemode", "GL_LINEAR_MIPMAP_LINEAR");

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

	Cvar_SetValue( "r_nonpoweroftwo_mipmaps", s_npot_mipmap_box.curvalue );
//	Cvar_SetValue( "r_ext_texture_compression", s_texcompress_box.curvalue );

	Cvar_SetValue( "r_swapinterval", s_vsync_box.curvalue );
	Cvar_SetValue( "cl_widescreen_fov", s_adjust_fov_box.curvalue );

	prepareVideoRefresh ();

	//UI_ForceMenuOff();
}


// Knightmare added
int texfilter_box_setval (void)
{
	char *texmode = Cvar_VariableString("r_texturemode");
	if (!Q_strcasecmp(texmode, "GL_LINEAR_MIPMAP_NEAREST"))
		return 0;
	else
		return 1;
}

// Knightmare- refresh rate option
int refresh_box_setval (void)
{
	int refreshVar = (int)Cvar_VariableValue ("r_displayrefresh");

	if (refreshVar == 150)
		return 10;
	else if (refreshVar == 144)
		return 9;
	else if (refreshVar == 120)
		return 8;
	else if (refreshVar == 110)
		return 7;
	else if (refreshVar == 100)
		return 6;
	else if (refreshVar == 85)
		return 5;
	else if (refreshVar == 75)
		return 4;
	else if (refreshVar == 72)
		return 3;
	else if (refreshVar == 70)
		return 2;
	else if (refreshVar == 60)
		return 1;
	else
		return 0;
}

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("r_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("r_anisotropic_avail");
	float anisoValue = ClampCvar (0, aniso_avail, Cvar_VariableValue("r_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;
}


/*
================
Menu_Video_Init
================
*/
void Menu_Video_Init (void)
{
	// Knightmare- added 1280x1024, 1400x1050, 856x480, 1024x480 modes, removed 320x240, 400x300, 512x384 modes
	static const char *resolutions[] = 
	{
#include "../qcommon/vid_resolutions.h"
	};
	static const char *refreshrate_names[] = 
	{
		"[default]",
		"[60Hz   ]",
		"[70Hz   ]",
		"[72Hz   ]",
		"[75Hz   ]",
		"[85Hz   ]",
		"[100Hz  ]",
		"[110Hz  ]",
		"[120Hz  ]",
		"[144Hz  ]",
		"[150Hz  ]",
		0
	};
	static const char *yesno_names[] =
	{
		"no",
		"yes",
		0
	};
	static const char *mip_names[] =
	{
		"bilinear",
		"trilinear",
		0
	};
	static const char *lmh_names[] =
	{
		"low",
		"medium",
		"high",
		"highest",
		0
	};

	int		y = 0;
	float	temp;
	char	*customStr;

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

	s_video_menu.x = SCREEN_WIDTH*0.5;
//	s_video_menu.x = viddef.width * 0.50;
	s_video_menu.y = SCREEN_HEIGHT*0.5 - 80;
	s_video_menu.nitems = 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_mode_list.generic.callback	= VidModeCallback;
	temp = Cvar_VariableValue("r_mode");
	s_mode_list.curvalue			= (temp == -1) ? 0 : max(temp - 2, 1); // offset for getting rid of < 640x480 resolutions
	s_mode_list.generic.statusbar	= "changes screen resolution";

	s_customwidth_title.generic.type	= MTYPE_SEPARATOR;
	s_customwidth_title.generic.flags	= (s_mode_list.curvalue != 0) ? QMF_HIDDEN : 0;
	s_customwidth_title.generic.name	= "custom width";
	s_customwidth_title.generic.x		= -2*MENU_FONT_SIZE;
	s_customwidth_title.generic.y		= y += 1.5*MENU_LINE_SIZE;

	s_customwidth_field.generic.type		= MTYPE_FIELD;
	s_customwidth_field.generic.flags		= (s_mode_list.curvalue != 0) ? (QMF_NUMBERSONLY|QMF_HIDDEN) : QMF_NUMBERSONLY;
//	s_customwidth_field.generic.name		= "custom width";
	s_customwidth_field.generic.callback	= 0;
	s_customwidth_field.generic.x			= -14*MENU_FONT_SIZE;
	s_customwidth_field.generic.y			= y + 1.5*MENU_LINE_SIZE;
	s_customwidth_field.length				= 5;
	s_customwidth_field.visible_length		= 6;
	customStr = Cvar_VariableString("r_customwidth");
	Q_strncpyz( s_customwidth_field.buffer, customStr, sizeof(s_customwidth_field.buffer) );
	s_customwidth_field.cursor				= strlen( customStr );

	s_customheight_title.generic.type	= MTYPE_SEPARATOR;
	s_customheight_title.generic.flags	= (s_mode_list.curvalue != 0) ? QMF_HIDDEN : 0;
	s_customheight_title.generic.name	= "custom height";
	s_customheight_title.generic.x		= 14.5*MENU_FONT_SIZE;
	s_customheight_title.generic.y		= y;

	s_customheight_field.generic.type		= MTYPE_FIELD;
	s_customheight_field.generic.flags		= (s_mode_list.curvalue != 0) ? (QMF_NUMBERSONLY|QMF_HIDDEN) : QMF_NUMBERSONLY;
//	s_customheight_field.generic.name		= "custom height";
	s_customheight_field.generic.callback	= 0;
	s_customheight_field.generic.x			= 2*MENU_FONT_SIZE;
	s_customheight_field.generic.y			= y + 1.5*MENU_LINE_SIZE;
	s_customheight_field.length				= 5;
	s_customheight_field.visible_length		= 6;
	customStr = Cvar_VariableString("r_customheight");
	Q_strncpyz(s_customheight_field.buffer, customStr, sizeof(s_customheight_field.buffer) );
	s_customheight_field.cursor				= strlen( customStr );

	s_fs_box.generic.type			= MTYPE_SPINCONTROL;
	s_fs_box.generic.x				= 0;
	s_fs_box.generic.y				= y += 3.5*MENU_LINE_SIZE;
	s_fs_box.generic.name			= "fullscreen";
	s_fs_box.itemnames				= yesno_names;
	s_fs_box.curvalue				= Cvar_VariableValue("vid_fullscreen");
	s_fs_box.generic.statusbar		= "changes bettween fullscreen and windowed display";

	s_brightness_slider.generic.type		= MTYPE_SLIDER;
	s_brightness_slider.generic.x			= 0;
	s_brightness_slider.generic.y			= y += MENU_LINE_SIZE;
	s_brightness_slider.generic.name		= "brightness";
	s_brightness_slider.generic.callback	= BrightnessCallback;
	s_brightness_slider.minvalue			= 0;
	s_brightness_slider.maxvalue			= 20;
	s_brightness_slider.curvalue			= (1.3 - Cvar_VariableValue("vid_gamma")) * 20;
	s_brightness_slider.generic.statusbar	= "changes display brightness";

	s_texfilter_box.generic.type		= MTYPE_SPINCONTROL;
	s_texfilter_box.generic.x			= 0;
	s_texfilter_box.generic.y			= y += 2*MENU_LINE_SIZE;
	s_texfilter_box.generic.name		= "texture filter";
	s_texfilter_box.curvalue			= texfilter_box_setval();
	s_texfilter_box.itemnames			= mip_names;
	s_texfilter_box.generic.statusbar	= "changes texture filtering mode";

	s_aniso_box.generic.type		= MTYPE_SPINCONTROL;
	s_aniso_box.generic.x			= 0;
	s_aniso_box.generic.y			= y += MENU_LINE_SIZE;
	s_aniso_box.generic.name		= "anisotropic filter";
	s_aniso_box.curvalue			= GetAnisoCurValue();
	s_aniso_box.itemnames			= GetAnisoNames();
	s_aniso_box.generic.statusbar	= "changes level of anisotropic mipmap filtering";

	s_texqual_box.generic.type		= MTYPE_SPINCONTROL;
	s_texqual_box.generic.x			= 0;
	s_texqual_box.generic.y			= y += MENU_LINE_SIZE;
	s_texqual_box.generic.name		= "texture quality";
	s_texqual_box.curvalue			= ClampCvar (0, 3, 3-Cvar_VariableValue("r_picmip"));
	s_texqual_box.itemnames			= lmh_names;
	s_texqual_box.generic.statusbar	= "changes maximum texture size (highest = no limit)";

	s_npot_mipmap_box.generic.type		= MTYPE_SPINCONTROL;
	s_npot_mipmap_box.generic.x			= 0;
	s_npot_mipmap_box.generic.y			= y += MENU_LINE_SIZE;
	s_npot_mipmap_box.generic.name		= "non-power-of-2 mipmaps";
	s_npot_mipmap_box.itemnames			= yesno_names;
	s_npot_mipmap_box.curvalue			= Cvar_VariableValue("r_nonpoweroftwo_mipmaps");
	s_npot_mipmap_box.generic.statusbar	= "enables non-power-of-2 mipmapped textures (requires driver support)";
/*
	s_texcompress_box.generic.type		= MTYPE_SPINCONTROL;
	s_texcompress_box.generic.x			= 0;
	s_texcompress_box.generic.y			= y += MENU_LINE_SIZE;
	s_texcompress_box.generic.name		= "texture compression";
	s_texcompress_box.curvalue			= Cvar_VariableValue("r_ext_texture_compression");
	s_texcompress_box.itemnames			= yesno_names;
	s_texcompress_box.generic.statusbar	= "reduces quality, increases performance (leave off unless needed)";
*/
	s_vsync_box.generic.type			= MTYPE_SPINCONTROL;
	s_vsync_box.generic.x				= 0;
	s_vsync_box.generic.y				= y += 2*MENU_LINE_SIZE;
	s_vsync_box.generic.name			= "video sync";
	s_vsync_box.generic.callback		= VsyncCallback;
	s_vsync_box.curvalue				= Cvar_VariableValue("r_swapinterval");
	s_vsync_box.itemnames				= yesno_names;
	s_vsync_box.generic.statusbar		= "sync framerate with monitor refresh";

	// Knightmare- refresh rate option
	s_refresh_box.generic.type			= MTYPE_SPINCONTROL;
	s_refresh_box.generic.x				= 0;
	s_refresh_box.generic.y				= y += MENU_LINE_SIZE;
	s_refresh_box.generic.name			= "refresh rate";
	s_refresh_box.curvalue				= refresh_box_setval();
	s_refresh_box.itemnames				= refreshrate_names;
	s_refresh_box.generic.statusbar		= "sets refresh rate for fullscreen modes";

	s_adjust_fov_box.generic.type		= MTYPE_SPINCONTROL;
	s_adjust_fov_box.generic.x			= 0;
	s_adjust_fov_box.generic.y			= y += MENU_LINE_SIZE;
	s_adjust_fov_box.generic.name		= "fov autoscaling";
	s_adjust_fov_box.generic.callback	= AdjustFOVCallback;
	s_adjust_fov_box.curvalue			= Cvar_VariableValue("cl_widescreen_fov");
	s_adjust_fov_box.itemnames			= yesno_names;
	s_adjust_fov_box.generic.statusbar	= "automatic scaling of fov for widescreen modes";

	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_LINE_SIZE;
	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_LINE_SIZE;
	s_defaults_action.generic.callback	= ResetVideoDefaults;
	s_defaults_action.generic.statusbar	= "resets all video settings to internal defaults";

	// 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_LINE_SIZE;
	s_apply_action.generic.callback		= ApplyChanges;

	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_LINE_SIZE;
	s_backmain_action.generic.callback	= UI_BackMenu;

	Menu_AddItem( &s_video_menu, ( void * ) &s_mode_list );

	Menu_AddItem( &s_video_menu, ( void * ) &s_customwidth_title );
	Menu_AddItem( &s_video_menu, ( void * ) &s_customwidth_field );
	Menu_AddItem( &s_video_menu, ( void * ) &s_customheight_title );
	Menu_AddItem( &s_video_menu, ( void * ) &s_customheight_field );

	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_npot_mipmap_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_refresh_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_adjust_fov_box );
	Menu_AddItem( &s_video_menu, ( void * ) &s_advanced_action );
	Menu_AddItem( &s_video_menu, ( void * ) &s_defaults_action );
	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;
}

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

	// draw the banner
	Menu_DrawBanner("m_banner_video");

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

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

/*
================
Video_MenuKey
================
*/
const char *Video_MenuKey( int key )
{
	return Default_MenuKey( &s_video_menu, key );
}

void M_Menu_Video_f (void)
{
	Menu_Video_Init();
	UI_PushMenu( Menu_Video_Draw, Video_MenuKey );
}
