From 67ade644b3fba7d13ea37be5106b89b59938dae3 Mon Sep 17 00:00:00 2001
From: Andrei Drexler <makro@rq3.com>
Date: Mon, 7 Mar 2011 15:55:01 +0000
Subject: [PATCH] Custom resolution list. Post-vid_restart menu. New uiScripts.
 And stuff.

---
 reaction/code/ui/ui_atoms.c  |   5 +
 reaction/code/ui/ui_local.h  |   8 +
 reaction/code/ui/ui_main.c   | 305 +++++++++++++++++++++++++++++++++--
 reaction/code/ui/ui_public.h |  12 +-
 reaction/code/ui/ui_shared.c |  13 +-
 reaction/code/ui/ui_shared.h |  12 +-
 6 files changed, 335 insertions(+), 20 deletions(-)

diff --git a/reaction/code/ui/ui_atoms.c b/reaction/code/ui/ui_atoms.c
index 354b7b85..c7ab0573 100644
--- a/reaction/code/ui/ui_atoms.c
+++ b/reaction/code/ui/ui_atoms.c
@@ -579,6 +579,11 @@ qboolean UI_ConsoleCommand(int realTime)
 	}
 	*/
 
+	if (Q_stricmp(cmd, "ui_RQ3_postVidRestart") == 0) {
+		_UI_SetActiveMenu(UIMENU_RQ3_POST_VID_RESTART);
+		return qtrue;
+	}
+
 	return qfalse;
 }
 
diff --git a/reaction/code/ui/ui_local.h b/reaction/code/ui/ui_local.h
index fa2d2247..6f3eb6ad 100644
--- a/reaction/code/ui/ui_local.h
+++ b/reaction/code/ui/ui_local.h
@@ -280,6 +280,14 @@ extern vmCvar_t ui_maxpolyverts;
 
 //Makro - player gender; irrelevant actually
 extern vmCvar_t ui_RQ3_gender;
+
+extern vmCvar_t ui_RQ3_old_r_mode;
+extern vmCvar_t ui_RQ3_old_r_customWidth;
+extern vmCvar_t ui_RQ3_old_r_customHeight;
+extern vmCvar_t ui_RQ3_old_r_fullScreen;
+extern vmCvar_t ui_RQ3_videoChanges;
+extern vmCvar_t ui_RQ3_fullScreen;
+
 //
 // ui_qmenu.c
 //
diff --git a/reaction/code/ui/ui_main.c b/reaction/code/ui/ui_main.c
index 01a6ea08..cdd54b48 100644
--- a/reaction/code/ui/ui_main.c
+++ b/reaction/code/ui/ui_main.c
@@ -2948,6 +2948,31 @@ static void UI_DrawOpponentName(rectDef_t * rect, float scale, vec4_t color, int
 		textStyle, qfalse);
 }
 
+static qboolean UI_IsCurrentResolution(const resolution_t* res)
+{
+	return (res->width == uiInfo.uiDC.glconfig.vidWidth && res->height == uiInfo.uiDC.glconfig.vidHeight);
+}
+
+static const char* UI_GetCustomResolutionString()
+{
+	int idx = uiInfo.uiDC.selectedMode;
+
+	if (idx == -2)
+	{
+		return "Custom";
+	}
+	else if (idx == -1 || uiInfo.uiDC.numSupportedModes <= 0)
+	{
+		return "Desktop Default";
+	}
+	else
+	{
+		char* fmt[2] = { "%d x %d", "%d x %d *" };
+		const resolution_t* res = &uiInfo.uiDC.supportedMode[idx];
+		return va(fmt[UI_IsCurrentResolution(res)], res->width, res->height);
+	}
+}
+
 static int UI_OwnerDrawWidth(int ownerDraw, float scale)
 {
 	int i, h, value;
@@ -3070,6 +3095,9 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale)
 	case UI_RQ3_REPLACEMENTINFO:
 		s = uiInfo.replacements.Info;
 		break;
+	case UI_RESOLUTION:
+		//s = UI_GetCustomResolutionString();
+		break;
 	default:
 		break;
 	}
@@ -4004,6 +4032,19 @@ static void UI_DrawReplacementModel(rectDef_t *rect)
 	uiInfo.uiDC.renderScene(&refdef);
 }
 
+// Makro - custom resolutions
+static void UI_DrawResolution(rectDef_t * rect, float scale, vec4_t color, int textStyle)
+{
+	const char *text = UI_GetCustomResolutionString();
+
+	if (!rect->hasVectors) {
+		Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, 0, textStyle, qfalse);
+	} else {
+		Text_PaintAngled(rect->x, rect->y,
+			rect->u, rect->v, scale, color, text, 0, 0, 0, textStyle, qfalse);
+	}
+}
+
 
 // FIXME: table drive
 //
@@ -4018,7 +4059,7 @@ static void UI_OwnerDraw(itemDef_t *item, float x, float y, float w, float h, fl
 	rect.h = h;
 	if (item->window.rectClient.hasVectors)
 	{
-		float p[2];
+		float* p = &rect.x;
 
 		p[0] = x;
 		p[1] = y;
@@ -4026,8 +4067,7 @@ static void UI_OwnerDraw(itemDef_t *item, float x, float y, float w, float h, fl
 		Vector2Copy(item->window.rectClient.v, rect.v);
 		Vector2MA(p, text_x, rect.u, p);
 		Vector2MA(p, text_y, rect.v, p);
-		rect.x = p[0];
-		rect.y = p[1];
+		//Vector2MA(p, item->textaligny * scale, rect.v, p);
 		rect.hasVectors = qtrue;
 	} else {
 		rect.hasVectors = qfalse;
@@ -4237,6 +4277,9 @@ static void UI_OwnerDraw(itemDef_t *item, float x, float y, float w, float h, fl
 	case UI_KEYBINDSTATUS:
 		UI_DrawKeyBindStatus(item, &rect, scale, color, textStyle);
 		break;
+	case UI_RESOLUTION:
+		UI_DrawResolution(&rect, scale, color, textStyle);
+		break;
 	default:
 		break;
 	}
@@ -5050,6 +5093,46 @@ static qboolean UI_ReplacementSubType_HandleKey(int flags, float *special, int k
 	return qfalse;
 }
 
+static qboolean UI_Resolution_HandleKey(int flags, float *special, int key)
+{
+	if (uiInfo.uiDC.numSupportedModes <= 0)
+		return qfalse;
+
+	if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER || key == K_LEFTARROW || key == K_RIGHTARROW)
+	{
+		int index = uiInfo.uiDC.selectedMode;
+
+		if (key == K_MOUSE2 || key == K_LEFTARROW) {
+			index--;
+		} else {
+			index++;
+		}
+
+		if (index == uiInfo.uiDC.numSupportedModes)
+			index = -1;
+		else if (index == -2)
+			index = uiInfo.uiDC.numSupportedModes - 1;
+
+		uiInfo.uiDC.selectedMode = index;
+
+		return qtrue;
+	}
+
+	if (key == K_HOME)
+	{
+		uiInfo.uiDC.selectedMode = -1;
+		return qtrue;
+	}
+
+	if (key == K_END)
+	{
+		uiInfo.uiDC.selectedMode = uiInfo.uiDC.numSupportedModes - 1;
+		return qtrue;
+	}
+
+	return qfalse;
+}
+
 static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key)
 {
 	switch (ownerDraw) {
@@ -5130,6 +5213,9 @@ static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special,
 	case UI_SELECTEDPLAYER:
 		UI_SelectedPlayer_HandleKey(flags, special, key);
 		break;
+	case UI_RESOLUTION:
+		UI_Resolution_HandleKey(flags, special, key);
+		break;
 	default:
 		break;
 	}
@@ -5712,6 +5798,159 @@ static void UI_Update(const char *name)
 	}
 }
 
+static qboolean UI_ParseResolution(char* str, int* width, int* height)
+{
+	char* x = strchr(str, 'x');
+	if (!x)
+	{
+		*width = *height = 0;
+		return qfalse;
+	}
+
+	*x++ = 0;
+
+	if (1 != sscanf(str, "%d", width) || 1 != sscanf(x, "%d", height))
+	{
+		*width = *height = 0;
+		return qfalse;
+	}
+
+	return qtrue;
+}
+
+static void UI_SelectCurrentResolution()
+{
+	int idx;
+	int r_mode = (int) trap_Cvar_VariableValue("r_mode");
+
+	if (r_mode == -2)
+	{
+		uiInfo.uiDC.selectedMode = -1;
+	}
+	else
+	{
+		uiInfo.uiDC.selectedMode = -2;
+		for (idx=0; idx<uiInfo.uiDC.numSupportedModes; ++idx)
+		{
+			if (UI_IsCurrentResolution(&uiInfo.uiDC.supportedMode[idx]))
+				uiInfo.uiDC.selectedMode = idx;
+		}
+	}
+}
+
+static void UI_GetSupportedModes()
+{
+	char buf[4096] = { 0 };
+	const char* delim = " ";
+	char* tok;
+	int idx;
+
+	uiInfo.uiDC.numSupportedModes = 0;
+	uiInfo.uiDC.selectedMode = 0;
+
+	trap_Cvar_VariableStringBuffer("r_availableModes", buf, sizeof(buf));
+
+	for (tok=strtok(buf, delim); tok; tok=strtok(NULL, delim))
+	{
+		int width, height;
+		if (UI_ParseResolution(tok, &width, &height))
+		{
+			idx = uiInfo.uiDC.numSupportedModes++;
+			if (uiInfo.uiDC.numSupportedModes > MAX_NUM_SUPPORTED_MODES)
+			{
+				Com_Printf(S_COLOR_YELLOW "Warning: more than MAX_NUM_SUPPORTED_MODES resolutions found.\n");
+				return;
+			}
+			uiInfo.uiDC.supportedMode[idx].width = width;
+			uiInfo.uiDC.supportedMode[idx].height = height;
+		}
+	}
+
+	// O(n^2) sort
+	
+	for (idx=0; idx<uiInfo.uiDC.numSupportedModes-1; ++idx)
+	{
+		int j;
+		resolution_t* ri = &uiInfo.uiDC.supportedMode[idx];
+		for (j=idx+1; j<uiInfo.uiDC.numSupportedModes; ++j)
+		{
+			resolution_t* rj = &uiInfo.uiDC.supportedMode[j];
+			if (rj->width < ri->width || (rj->width == ri->width && rj->height < ri->height))
+			{
+				resolution_t tmp = *ri;
+				*ri = *rj;
+				*rj = tmp;
+			}
+		}
+	}
+
+	UI_SelectCurrentResolution();
+}
+
+static void UI_InitSystemSettings()
+{
+	UI_SelectCurrentResolution();
+}
+
+static qboolean UI_ChangeVideoCvarAndBackup(const char* name, const char* backup, int value)
+{
+	int oldValue = (int) trap_Cvar_VariableValue(name);
+	trap_Cvar_SetValue(backup, oldValue);
+	trap_Cvar_SetValue(name, value);
+	return oldValue != value;
+}
+
+static qboolean UI_BackupVideoCvar(const char* src, const char* dst)
+{
+	int oldValue = (int) trap_Cvar_VariableValue(dst);
+	int value = (int) trap_Cvar_VariableValue(src);
+	trap_Cvar_SetValue(dst, value);
+	return value != oldValue;
+}
+
+static void UI_ApplySystemSettings()
+{
+	int fullScreen = (int) trap_Cvar_VariableValue("ui_RQ3_fullScreen");
+	qboolean changed = UI_ChangeVideoCvarAndBackup("r_fullscreen", "ui_RQ3_old_r_fullScreen", fullScreen);
+
+	if (uiInfo.uiDC.selectedMode == -2)
+	{
+		// keep current settings
+		UI_BackupVideoCvar("r_mode", "ui_RQ3_old_r_mode");
+	}
+	else if (uiInfo.uiDC.selectedMode != -1 && uiInfo.uiDC.numSupportedModes > 0)
+	{
+		changed |=
+			UI_ChangeVideoCvarAndBackup("r_mode", "ui_RQ3_old_r_mode", -1) |
+			UI_ChangeVideoCvarAndBackup("r_customWidth", "ui_RQ3_old_r_customWidth", uiInfo.uiDC.supportedMode[uiInfo.uiDC.selectedMode].width) |
+			UI_ChangeVideoCvarAndBackup("r_customHeight", "ui_RQ3_old_r_customHeight", uiInfo.uiDC.supportedMode[uiInfo.uiDC.selectedMode].height)
+			;
+	}
+	else
+	{
+		changed |= UI_ChangeVideoCvarAndBackup("r_mode", "ui_RQ3_old_r_mode", -2);
+		UI_BackupVideoCvar("r_customwidth", "ui_RQ3_old_r_customWidth");
+		UI_BackupVideoCvar("r_customheight", "ui_RQ3_old_r_customHeight");
+	}
+	
+	if (changed)
+	{
+		trap_Cvar_Set("ui_RQ3_videoChanges", "1");
+	}
+
+	trap_Cmd_ExecuteText(EXEC_APPEND, "vid_restart;");
+}
+
+static void UI_RevertVideoSettings()
+{
+	UI_BackupVideoCvar("ui_RQ3_old_r_mode", "r_mode");
+	UI_BackupVideoCvar("ui_RQ3_old_r_customWidth", "r_customwidth");
+	UI_BackupVideoCvar("ui_RQ3_old_r_customHeight", "r_customheight");
+	UI_BackupVideoCvar("ui_RQ3_old_r_fullScreen", "r_fullscreen");
+
+	trap_Cmd_ExecuteText(EXEC_APPEND, "vid_restart;");
+}
+
 // FIXME: Makro - this is a monster of a function
 // Not exactly efficient with all this strcmp's in it, either...
 
@@ -6012,6 +6251,12 @@ static void UI_RunMenuScript(char **args)
 			Controls_SetConfig(qtrue);
 		} else if (Q_stricmp(name, "loadControls") == 0) {
 			Controls_GetConfig();
+		} else if (Q_stricmp(name, "initSystemSettings") == 0) {
+			UI_InitSystemSettings();
+		} else if (Q_stricmp(name, "applySystemSettings") == 0) {
+			UI_ApplySystemSettings();
+		} else if (Q_stricmp(name, "revertVideoSettings") == 0) {
+			UI_RevertVideoSettings();
 		} else if (Q_stricmp(name, "clearError") == 0) {
 			trap_Cvar_Set("com_errorMessage", "");
 		} else if (Q_stricmp(name, "loadGameInfo") == 0) {
@@ -8256,6 +8501,25 @@ static void UI_MakeExtensionsList( void )
 	}
 }
 
+static qboolean UI_VidRestartPopup(qboolean inGame)
+{
+	int changes = (int) trap_Cvar_VariableValue("ui_RQ3_videoChanges");
+	if (changes)
+	{
+		trap_Cvar_Set("ui_RQ3_videoChanges", "0");
+		// popup menu
+		if (inGame)
+		{
+			trap_Cvar_Set("cl_paused", "1");
+			trap_Key_SetCatcher(KEYCATCH_UI);
+			Menus_CloseAll();
+		}
+		Menus_ActivateByName("post_vid_restart", qfalse);
+		return qtrue;
+	}
+	return qfalse;
+}
+
 /*
 =================
 UI_Init
@@ -8278,6 +8542,8 @@ void _UI_Init(qboolean inGameLoad)
 	
 	// cache redundant calulations
 	trap_GetGlconfig(&uiInfo.uiDC.glconfig);
+	UI_GetSupportedModes();
+	UI_BackupVideoCvar("r_fullscreen", "ui_RQ3_fullScreen");
 
 	UI_MakeExtensionsList();
 
@@ -8623,12 +8889,10 @@ void _UI_SetActiveMenu(uiMenuCommand_t menu)
 					trap_Cvar_Set("com_errorMessage", "");
 				}
 			//Makro - check com_hunkmegs
-			} else {
-				if ((int)trap_Cvar_VariableValue("com_hunkMegs") < 256)
-				{
-					trap_Cvar_SetValue("com_hunkMegs", 256);
-					Menus_ActivateByName("memory_popmenu", qfalse);
-				};
+			} else if ((int)trap_Cvar_VariableValue("com_hunkMegs") < 256) {
+				trap_Cvar_SetValue("com_hunkMegs", 256);
+				Menus_ActivateByName("memory_popmenu", qfalse);
+			} else if (UI_VidRestartPopup(qfalse)) {
 			}
 			return;
 		case UIMENU_TEAM:
@@ -8697,6 +8961,12 @@ void _UI_SetActiveMenu(uiMenuCommand_t menu)
 			Menus_CloseAll();
 			Menus_ActivateByName("ingame_presets", qfalse);
 			return;
+
+		case UIMENU_RQ3_POST_VID_RESTART:
+			//Menus_CloseAll();
+			//Menus_ActivateByName("post_vid_restart", qfalse);
+			UI_VidRestartPopup(qtrue);
+			return;
 		}
 	}
 }
@@ -9183,6 +9453,14 @@ vmCvar_t ui_RQ3_radioPreset10Script;
 //Makro - player gender; irrelevant for now
 vmCvar_t ui_RQ3_gender;
 
+vmCvar_t ui_RQ3_old_r_mode;
+vmCvar_t ui_RQ3_old_r_customWidth;
+vmCvar_t ui_RQ3_old_r_customHeight;
+vmCvar_t ui_RQ3_old_r_fullScreen;
+vmCvar_t ui_RQ3_videoChanges;
+vmCvar_t ui_RQ3_fullScreen;
+
+
 
 // bk001129 - made static to avoid aliasing
 static cvarTable_t cvarTable[] = {
@@ -9378,7 +9656,14 @@ static cvarTable_t cvarTable[] = {
 	{&ui_RQ3_radioPreset10Desc,		"ui_RQ3_radioPreset10Desc", "", CVAR_ARCHIVE},
 	{&ui_RQ3_radioPreset10Script,	"ui_RQ3_radioPreset10Script", "", CVAR_ARCHIVE},
 	//Makro - player gender; irrelevant for now
-	{&ui_RQ3_gender,				"ui_RQ3_gender", "0",	CVAR_ARCHIVE}
+	{&ui_RQ3_gender,				"ui_RQ3_gender", "0",	CVAR_ARCHIVE},
+
+	{&ui_RQ3_old_r_mode,			"ui_RQ3_old_r_mode", "-2", CVAR_ROM},
+	{&ui_RQ3_old_r_customWidth,		"ui_RQ3_old_r_customWidth", "640", CVAR_ROM},
+	{&ui_RQ3_old_r_customHeight,	"ui_RQ3_old_r_customHeight", "480", CVAR_ROM},
+	{&ui_RQ3_old_r_fullScreen,		"ui_RQ3_old_r_fullScreen", "1", CVAR_ROM},
+	{&ui_RQ3_videoChanges,			"ui_RQ3_videoChanges", "0", CVAR_ROM},
+	{&ui_RQ3_fullScreen,			"ui_RQ3_fullScreen", "1", CVAR_ROM},
 };
 
 // bk001129 - made static to avoid aliasing
diff --git a/reaction/code/ui/ui_public.h b/reaction/code/ui/ui_public.h
index fc2f5df4..45b47ed0 100644
--- a/reaction/code/ui/ui_public.h
+++ b/reaction/code/ui/ui_public.h
@@ -151,14 +151,16 @@ typedef enum {
 	UIMENU_BAD_CD_KEY,
 	UIMENU_TEAM,
 	UIMENU_POSTGAME,
-//Makro - added weapon menu
+// Makro - added weapon menu
 	UIMENU_RQ3_WEAPON,
-//Makro - added join menu
+// Makro - added join menu
 	UIMENU_RQ3_JOIN,
-//Makro - tkok yes/no menu
+// Makro - tkok yes/no menu
 	UIMENU_RQ3_TKOK,
-//Makro - radio presets menu
-	UIMENU_RQ3_PRESETS
+// Makro - radio presets menu
+	UIMENU_RQ3_PRESETS,
+// Makro - post-vid_restart menu
+	UIMENU_RQ3_POST_VID_RESTART,
 } uiMenuCommand_t;
 
 #define SORT_HOST			0
diff --git a/reaction/code/ui/ui_shared.c b/reaction/code/ui/ui_shared.c
index e4ba78e1..d608937d 100644
--- a/reaction/code/ui/ui_shared.c
+++ b/reaction/code/ui/ui_shared.c
@@ -6068,9 +6068,11 @@ void Item_OwnerDraw_Paint(itemDef_t * item)
 		if (item->text) {
 			float p[2];
 			
-			p[0] = item->textRect.x;
-			p[1] = item->window.rect.y;
 			Item_Text_Paint(item);
+			
+			p[0] = item->textRect.x;
+			p[1] = item->textRect.y;
+			//p[1] = item->window.rect.y;
 
 			// +8 is an offset kludge to properly align owner draw items that have text combined with them
 			if (item->window.rectClient.hasVectors) {
@@ -6087,7 +6089,7 @@ void Item_OwnerDraw_Paint(itemDef_t * item)
 				}
 			}
 			DC->ownerDrawItem(item, p[0], p[1],
-				item->window.rect.w, item->window.rect.h, 0, item->textaligny,
+				item->window.rect.w, item->window.rect.h, 0, 0,
 				item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment,
 				item->special, item->textscale, color, item->window.background,
 				item->textStyle);
@@ -6273,7 +6275,10 @@ void Item_Paint(itemDef_t * item)
 		color[1] = color[3] = 1;
 		color[0] = color[2] = 0;
 		//Makro - added shader parm
-		DC->drawRect(r->x, r->y, r->w, r->h, 1, color, DC->whiteShader);
+		if (r->hasVectors)
+			DC->drawAngledRect(r->x, r->y, r->w, r->h, r->u, r->v, 1, color, RECT_FULL, DC->whiteShader);
+		else
+			DC->drawRect(r->x, r->y, r->w, r->h, 1, color, DC->whiteShader);
 	}
 	//DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
 
diff --git a/reaction/code/ui/ui_shared.h b/reaction/code/ui/ui_shared.h
index ba31a76a..e6c2fb85 100644
--- a/reaction/code/ui/ui_shared.h
+++ b/reaction/code/ui/ui_shared.h
@@ -503,7 +503,12 @@ typedef struct {
 										(intvec)[(pos)>>5] &= ~(1 << ((pos) & 31))\
 										
 
-#define MAX_NUM_GL_EXTENSIONS	128
+#define MAX_NUM_GL_EXTENSIONS		128
+#define MAX_NUM_SUPPORTED_MODES		256
+
+typedef struct {
+	unsigned short width, height;
+} resolution_t;
 
 typedef struct {
 	qhandle_t(*registerShaderNoMip) (const char *p);
@@ -621,6 +626,11 @@ typedef struct {
 	// Makro - total screen extents (which can go outside 0,0-640,480 for wide screens)
 	float min[2];
 	float max[2];
+
+	// Makro - supported resolutions
+	resolution_t supportedMode[MAX_NUM_SUPPORTED_MODES];
+	int numSupportedModes;
+	int selectedMode;
 } displayContextDef_t;
 
 const char *String_Alloc(const char *p);