From c5790ebb593767e649ede7ec8c3f38aed3168db3 Mon Sep 17 00:00:00 2001
From: bones_was_here <bones_was_here@xonotic.au>
Date: Tue, 16 Apr 2024 06:46:54 +1000
Subject: [PATCH] vid: consolidate mode structures

This uses a viddef_mode_t `vid.mode` in the global viddef_t `vid`
instead of having a separate declaration of each var there, makes
copying it more efficient.

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
---
 cap_avi.c    |  2 +-
 cl_input.c   |  6 ++--
 cl_screen.c  | 90 ++++++++++++++++++++++++++--------------------------
 cl_video.c   |  2 +-
 clvm_cmds.c  |  4 +--
 csprogs.c    |  4 +--
 ft2.c        | 12 +++----
 gl_draw.c    | 20 ++++++------
 gl_rmain.c   | 20 ++++++------
 menu.c       | 32 +++++++++----------
 mvm_cmds.c   |  4 +--
 vid.h        |  9 +-----
 vid_sdl.c    | 18 +++++------
 vid_shared.c | 22 +++----------
 14 files changed, 113 insertions(+), 132 deletions(-)

diff --git a/cap_avi.c b/cap_avi.c
index ea0e3544..54f636dc 100644
--- a/cap_avi.c
+++ b/cap_avi.c
@@ -504,7 +504,7 @@ void SCR_CaptureVideo_Avi_BeginVideo(void)
 	double aspect;
 	char vabuf[1024];
 
-	aspect = vid.width / (vid.height * vid_pixelheight.value);
+	aspect = vid.mode.width / (vid.mode.height * vid_pixelheight.value);
 
 	cls.capturevideo.format = CAPTUREVIDEOFORMAT_AVI_I420;
 	cls.capturevideo.formatextension = "avi";
diff --git a/cl_input.c b/cl_input.c
index f41c4c91..21c2ad64 100644
--- a/cl_input.c
+++ b/cl_input.c
@@ -535,7 +535,7 @@ void CL_Input (void)
 			static int oldwindowmouse[2];
 			if (oldwindowmouse[0] != in_windowmouse_x || oldwindowmouse[1] != in_windowmouse_y)
 			{
-				CL_VM_InputEvent(3, in_windowmouse_x * vid_conwidth.value / vid.width, in_windowmouse_y * vid_conheight.value / vid.height);
+				CL_VM_InputEvent(3, in_windowmouse_x * vid_conwidth.value / vid.mode.width, in_windowmouse_y * vid_conheight.value / vid.mode.height);
 				oldwindowmouse[0] = in_windowmouse_x;
 				oldwindowmouse[1] = in_windowmouse_y;
 			}
@@ -704,8 +704,8 @@ void CL_Input (void)
 		// mouse interacting with the scene, mostly stationary view
 		V_StopPitchDrift();
 		// update prydon cursor
-		cl.cmd.cursor_screen[0] = in_windowmouse_x * 2.0 / vid.width - 1.0;
-		cl.cmd.cursor_screen[1] = in_windowmouse_y * 2.0 / vid.height - 1.0;
+		cl.cmd.cursor_screen[0] = in_windowmouse_x * 2.0 / vid.mode.width - 1.0;
+		cl.cmd.cursor_screen[1] = in_windowmouse_y * 2.0 / vid.mode.height - 1.0;
 	}
 
 	if(v_flipped.integer)
diff --git a/cl_screen.c b/cl_screen.c
index 04d25a01..191cd70a 100644
--- a/cl_screen.c
+++ b/cl_screen.c
@@ -999,17 +999,17 @@ void SCR_ScreenShot_f(cmd_state_t *cmd)
 		shotnumber++;
 	}
 
-	buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4);
-	buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (scr_screenshot_alpha.integer ? 4 : 3));
+	buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.mode.width * vid.mode.height * 4);
+	buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.mode.width * vid.mode.height * (scr_screenshot_alpha.integer ? 4 : 3));
 
-	if (SCR_ScreenShot (filename, buffer1, buffer2, 0, 0, vid.width, vid.height, false, false, false, jpeg, png, true, scr_screenshot_alpha.integer != 0))
+	if (SCR_ScreenShot (filename, buffer1, buffer2, 0, 0, vid.mode.width, vid.mode.height, false, false, false, jpeg, png, true, scr_screenshot_alpha.integer != 0))
 		Con_Printf("Wrote %s\n", filename);
 	else
 	{
 		Con_Printf(CON_ERROR "Unable to write %s\n", filename);
 		if(jpeg || png)
 		{
-			if(SCR_ScreenShot (filename, buffer1, buffer2, 0, 0, vid.width, vid.height, false, false, false, false, false, true, scr_screenshot_alpha.integer != 0))
+			if(SCR_ScreenShot (filename, buffer1, buffer2, 0, 0, vid.mode.width, vid.mode.height, false, false, false, false, false, true, scr_screenshot_alpha.integer != 0))
 			{
 				dp_strlcpy(filename + strlen(filename) - 3, "tga", 4);
 				Con_Printf("Wrote %s\n", filename);
@@ -1033,14 +1033,14 @@ static void SCR_CaptureVideo_BeginVideo(void)
 	// soundrate is figured out on the first SoundFrame
 
 	if(width == 0 && height != 0)
-		width = (int) (height * (double)vid.width / ((double)vid.height * vid_pixelheight.value)); // keep aspect
+		width = (int) (height * (double)vid.mode.width / ((double)vid.mode.height * vid_pixelheight.value)); // keep aspect
 	if(width != 0 && height == 0)
-		height = (int) (width * ((double)vid.height * vid_pixelheight.value) / (double)vid.width); // keep aspect
+		height = (int) (width * ((double)vid.mode.height * vid_pixelheight.value) / (double)vid.mode.width); // keep aspect
 
-	if(width < 2 || width > vid.width) // can't scale up
-		width = vid.width;
-	if(height < 2 || height > vid.height) // can't scale up
-		height = vid.height;
+	if(width < 2 || width > vid.mode.width) // can't scale up
+		width = vid.mode.width;
+	if(height < 2 || height > vid.mode.height) // can't scale up
+		height = vid.mode.height;
 
 	// ensure it's all even; if not, scale down a little
 	if(width % 1)
@@ -1060,7 +1060,7 @@ static void SCR_CaptureVideo_BeginVideo(void)
 	cls.capturevideo.starttime = cls.capturevideo.lastfpstime = host.realtime;
 	cls.capturevideo.soundsampleframe = 0;
 	cls.capturevideo.realtime = cl_capturevideo_realtime.integer != 0;
-	cls.capturevideo.screenbuffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4);
+	cls.capturevideo.screenbuffer = (unsigned char *)Mem_Alloc(tempmempool, vid.mode.width * vid.mode.height * 4);
 	cls.capturevideo.outbuffer = (unsigned char *)Mem_Alloc(tempmempool, width * height * (4+4) + 18);
 	dpsnprintf(cls.capturevideo.basename, sizeof(cls.capturevideo.basename), "video/%s%03i", Sys_TimeString(cl_capturevideo_nameformat.string), cl_capturevideo_number.integer);
 	Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1);
@@ -1219,9 +1219,9 @@ static void SCR_CaptureVideo_VideoFrame(int newframestepframenum)
 	CHECKGLERROR
 	// speed is critical here, so do saving as directly as possible
 
-	GL_ReadPixelsBGRA(x, y, vid.width, vid.height, cls.capturevideo.screenbuffer);
+	GL_ReadPixelsBGRA(x, y, vid.mode.width, vid.mode.height, cls.capturevideo.screenbuffer);
 
-	SCR_ScaleDownBGRA (cls.capturevideo.screenbuffer, vid.width, vid.height, cls.capturevideo.outbuffer, width, height);
+	SCR_ScaleDownBGRA (cls.capturevideo.screenbuffer, vid.mode.width, vid.mode.height, cls.capturevideo.outbuffer, width, height);
 
 	cls.capturevideo.videoframes(newframestepframenum - cls.capturevideo.framestepframe);
 	cls.capturevideo.framestepframe = newframestepframenum;
@@ -1343,7 +1343,7 @@ static void R_Envmap_f(cmd_state_t *cmd)
 		Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
 		return;
 	}
-	if (size > vid.width || size > vid.height)
+	if (size > vid.mode.width || size > vid.mode.height)
 	{
 		Con_Print("envmap: your resolution is not big enough to render that size\n");
 		return;
@@ -1383,7 +1383,7 @@ static void R_Envmap_f(cmd_state_t *cmd)
 		R_Mesh_Start();
 		R_RenderView(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, size, size);
 		R_Mesh_Finish();
-		SCR_ScreenShot(filename, buffer1, buffer2, 0, vid.height - (r_refdef.view.y + r_refdef.view.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, envmapinfo[j].flipdiagonaly, false, false, false, false);
+		SCR_ScreenShot(filename, buffer1, buffer2, 0, vid.mode.height - (r_refdef.view.y + r_refdef.view.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, envmapinfo[j].flipdiagonaly, false, false, false, false);
 	}
 
 	Mem_Free (buffer1);
@@ -1622,44 +1622,44 @@ static void SCR_DrawScreen (void)
 
 		if (r_stereo_sidebyside.integer)
 		{
-			r_refdef.view.width = (int)(vid.width * size / 2.5);
-			r_refdef.view.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
+			r_refdef.view.width = (int)(vid.mode.width * size / 2.5);
+			r_refdef.view.height = (int)(vid.mode.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
 			r_refdef.view.depth = 1;
-			r_refdef.view.x = (int)((vid.width - r_refdef.view.width * 2.5) * 0.5);
-			r_refdef.view.y = (int)((vid.height - r_refdef.view.height)/2);
+			r_refdef.view.x = (int)((vid.mode.width - r_refdef.view.width * 2.5) * 0.5);
+			r_refdef.view.y = (int)((vid.mode.height - r_refdef.view.height)/2);
 			r_refdef.view.z = 0;
 			if (r_stereo_side)
 				r_refdef.view.x += (int)(r_refdef.view.width * 1.5);
 		}
 		else if (r_stereo_horizontal.integer)
 		{
-			r_refdef.view.width = (int)(vid.width * size / 2);
-			r_refdef.view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
+			r_refdef.view.width = (int)(vid.mode.width * size / 2);
+			r_refdef.view.height = (int)(vid.mode.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
 			r_refdef.view.depth = 1;
-			r_refdef.view.x = (int)((vid.width - r_refdef.view.width * 2.0)/2);
-			r_refdef.view.y = (int)((vid.height - r_refdef.view.height)/2);
+			r_refdef.view.x = (int)((vid.mode.width - r_refdef.view.width * 2.0)/2);
+			r_refdef.view.y = (int)((vid.mode.height - r_refdef.view.height)/2);
 			r_refdef.view.z = 0;
 			if (r_stereo_side)
 				r_refdef.view.x += (int)(r_refdef.view.width);
 		}
 		else if (r_stereo_vertical.integer)
 		{
-			r_refdef.view.width = (int)(vid.width * size);
-			r_refdef.view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100) / 2);
+			r_refdef.view.width = (int)(vid.mode.width * size);
+			r_refdef.view.height = (int)(vid.mode.height * size * (1 - bound(0, r_letterbox.value, 100) / 100) / 2);
 			r_refdef.view.depth = 1;
-			r_refdef.view.x = (int)((vid.width - r_refdef.view.width)/2);
-			r_refdef.view.y = (int)((vid.height - r_refdef.view.height * 2.0)/2);
+			r_refdef.view.x = (int)((vid.mode.width - r_refdef.view.width)/2);
+			r_refdef.view.y = (int)((vid.mode.height - r_refdef.view.height * 2.0)/2);
 			r_refdef.view.z = 0;
 			if (r_stereo_side)
 				r_refdef.view.y += (int)(r_refdef.view.height);
 		}
 		else
 		{
-			r_refdef.view.width = (int)(vid.width * size);
-			r_refdef.view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
+			r_refdef.view.width = (int)(vid.mode.width * size);
+			r_refdef.view.height = (int)(vid.mode.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
 			r_refdef.view.depth = 1;
-			r_refdef.view.x = (int)((vid.width - r_refdef.view.width)/2);
-			r_refdef.view.y = (int)((vid.height - r_refdef.view.height)/2);
+			r_refdef.view.x = (int)((vid.mode.width - r_refdef.view.width)/2);
+			r_refdef.view.y = (int)((vid.mode.height - r_refdef.view.height)/2);
 			r_refdef.view.z = 0;
 		}
 
@@ -1699,8 +1699,8 @@ static void SCR_DrawScreen (void)
 
 	if (!r_stereo_sidebyside.integer && !r_stereo_horizontal.integer && !r_stereo_vertical.integer)
 	{
-		r_refdef.view.width = vid.width;
-		r_refdef.view.height = vid.height;
+		r_refdef.view.width = vid.mode.width;
+		r_refdef.view.height = vid.mode.height;
 		r_refdef.view.depth = 1;
 		r_refdef.view.x = 0;
 		r_refdef.view.y = 0;
@@ -1732,9 +1732,9 @@ static void SCR_DrawScreen (void)
 			unsigned char *buffer1;
 			unsigned char *buffer2;
 			dpsnprintf(filename, sizeof(filename), "timedemoscreenshots/%s%06d.tga", cls.demoname, cls.td_frames);
-			buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4);
-			buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
-			SCR_ScreenShot(filename, buffer1, buffer2, 0, 0, vid.width, vid.height, false, false, false, false, false, true, false);
+			buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.mode.width * vid.mode.height * 4);
+			buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.mode.width * vid.mode.height * 3);
+			SCR_ScreenShot(filename, buffer1, buffer2, 0, 0, vid.mode.width, vid.mode.height, false, false, false, false, false, true, false);
 			Mem_Free(buffer1);
 			Mem_Free(buffer2);
 		}
@@ -1828,11 +1828,11 @@ static void SCR_SetLoadingScreenTexture(void)
 
 	SCR_ClearLoadingScreenTexture();
 
-	w = vid.width; h = vid.height;
+	w = vid.mode.width; h = vid.mode.height;
 	loadingscreentexture_w = loadingscreentexture_h = 1;
 
 	loadingscreentexture = R_LoadTexture2D(r_main_texturepool, "loadingscreentexture", w, h, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP, -1, NULL);
-	R_Mesh_CopyToTexture(loadingscreentexture, 0, 0, 0, 0, vid.width, vid.height);
+	R_Mesh_CopyToTexture(loadingscreentexture, 0, 0, 0, 0, vid.mode.width, vid.mode.height);
 
 	loadingscreentexture_vertex3f[2] = loadingscreentexture_vertex3f[5] = loadingscreentexture_vertex3f[8] = loadingscreentexture_vertex3f[11] = 0;
 	loadingscreentexture_vertex3f[0] = loadingscreentexture_vertex3f[9] = 0;
@@ -2050,8 +2050,8 @@ static void SCR_DrawLoadingScreen (void)
 	// apply scale base
 	if(scr_loadingscreen_scale_base.integer)
 	{
-		w *= vid_conwidth.integer / (float) vid.width;
-		h *= vid_conheight.integer / (float) vid.height;
+		w *= vid_conwidth.integer / (float) vid.mode.width;
+		h *= vid_conheight.integer / (float) vid.mode.height;
 	}
 
 	// apply scale limit
@@ -2105,7 +2105,7 @@ qbool R_Stereo_ColorMasking(void)
 
 qbool R_Stereo_Active(void)
 {
-	return (vid.stereobuffer || r_stereo_sidebyside.integer || r_stereo_horizontal.integer || r_stereo_vertical.integer || R_Stereo_ColorMasking());
+	return (vid.mode.stereobuffer || r_stereo_sidebyside.integer || r_stereo_horizontal.integer || r_stereo_vertical.integer || R_Stereo_ColorMasking());
 }
 
 static void SCR_UpdateVars(void)
@@ -2113,7 +2113,7 @@ static void SCR_UpdateVars(void)
 	float conwidth = bound(160, vid_conwidth.value, 32768);
 	float conheight = bound(90, vid_conheight.value, 24576);
 	if (vid_conwidthauto.integer)
-		conwidth = floor(conheight * vid.width / (vid.height * vid_pixelheight.value));
+		conwidth = floor(conheight * vid.mode.width / (vid.mode.height * vid_pixelheight.value));
 	if (vid_conwidth.value != conwidth)
 		Cvar_SetValueQuick(&vid_conwidth, conwidth);
 	if (vid_conheight.value != conheight)
@@ -2301,7 +2301,7 @@ void CL_UpdateScreen(void)
 	qglDrawBuffer(GL_BACK);CHECKGLERROR
 #endif
 
-	R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
+	R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.mode.width, vid.mode.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
 	R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 	R_SetViewport(&viewport);
 	GL_ScissorTest(false);
@@ -2333,7 +2333,7 @@ void CL_UpdateScreen(void)
 			r_refdef.view.colormask[2] = 0;
 		}
 
-		if (vid.stereobuffer)
+		if (vid.mode.stereobuffer)
 			qglDrawBuffer(GL_BACK_RIGHT);
 
 		SCR_DrawScreen();
@@ -2348,7 +2348,7 @@ void CL_UpdateScreen(void)
 			r_refdef.view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
 		}
 
-		if (vid.stereobuffer)
+		if (vid.mode.stereobuffer)
 			qglDrawBuffer(GL_BACK_LEFT);
 
 		SCR_DrawScreen();
diff --git a/cl_video.c b/cl_video.c
index 2d5cc453..ca9396fb 100644
--- a/cl_video.c
+++ b/cl_video.c
@@ -486,7 +486,7 @@ void CL_DrawVideo(void)
 	st[6] = 1.0; st[7] = 1.0; 
 	if (cl_video_keepaspectratio.integer)
 	{
-		float a = video->getaspectratio(video->stream) / ((float)vid.width / (float)vid.height);
+		float a = video->getaspectratio(video->stream) / ((float)vid.mode.width / (float)vid.mode.height);
 		if (cl_video_keepaspectratio.integer >= 2)
 		{
 			// clip instead of scale
diff --git a/clvm_cmds.c b/clvm_cmds.c
index f3e986ed..fac584d4 100644
--- a/clvm_cmds.c
+++ b/clvm_cmds.c
@@ -2256,9 +2256,9 @@ static void VM_CL_getmousepos(prvm_prog_t *prog)
 	if (key_consoleactive || key_dest != key_game)
 		VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
 	else if (cl.csqc_wantsmousemove)
-		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
+		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.mode.width, in_windowmouse_y * vid_conheight.integer / vid.mode.height, 0);
 	else
-		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
+		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.mode.width, in_mouse_y * vid_conheight.integer / vid.mode.height, 0);
 }
 
 //#345 float(float framenum) getinputstate (EXT_CSQC)
diff --git a/csprogs.c b/csprogs.c
index d9d8630a..da5bd77e 100644
--- a/csprogs.c
+++ b/csprogs.c
@@ -510,8 +510,8 @@ qbool CL_VM_UpdateView (double frametime)
 	// free memory for resources that are no longer referenced
 	PRVM_GarbageCollection(prog);
 	// pass in width and height and menu/focus state as parameters (EXT_CSQC_1)
-	PRVM_G_FLOAT(OFS_PARM0) = vid.width;
-	PRVM_G_FLOAT(OFS_PARM1) = vid.height;
+	PRVM_G_FLOAT(OFS_PARM0) = vid.mode.width;
+	PRVM_G_FLOAT(OFS_PARM1) = vid.mode.height;
 	/*
 	 * This should be fine for now but FTEQW uses flags for keydest
 	 * and checks that an array called "eyeoffset" is 0
diff --git a/ft2.c b/ft2.c
index 64efe9a6..c7fe3ace 100644
--- a/ft2.c
+++ b/ft2.c
@@ -502,7 +502,7 @@ float Font_VirtualToRealSize(float sz)
 	if(sz < 0)
 		return sz;
 	//vw = ((vid.width > 0) ? vid.width : vid_width.value);
-	vh = ((vid.height > 0) ? vid.height : vid_height.value);
+	vh = ((vid.mode.height > 0) ? vid.mode.height : vid_height.value);
 	// now try to scale to our actual size:
 	sn = sz * vh / vid_conheight.value;
 	si = (int)sn;
@@ -1006,11 +1006,11 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
 	float fsize_x, fsize_y;
 	ft2_font_map_t **maps = font->font_maps;
 
-	fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value;
+	fsize_x = fsize_y = _fsize * vid.mode.height / vid_conheight.value;
 	if(outw && *outw)
-		fsize_x = *outw * vid.width / vid_conwidth.value;
+		fsize_x = *outw * vid.mode.width / vid_conwidth.value;
 	if(outh && *outh)
-		fsize_y = *outh * vid.height / vid_conheight.value;
+		fsize_y = *outh * vid.mode.height / vid_conheight.value;
 
 	if (fsize_x < 0)
 	{
@@ -1043,8 +1043,8 @@ int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh)
 	if (value <= r_font_size_snapping.value)
 	{
 		// do NOT keep the aspect for perfect rendering
-		if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height;
-		if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width;
+		if (outh) *outh = maps[match]->size * vid_conheight.value / vid.mode.height;
+		if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.mode.width;
 	}
 	return match;
 }
diff --git a/gl_draw.c b/gl_draw.c
index d6b6a4a7..8eaf3932 100644
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -516,10 +516,10 @@ dp_font_t *FindFont(const char *title, qbool allocate_new)
 
 static float snap_to_pixel_x(float x, float roundUpAt)
 {
-	float pixelpos = x * vid.width / vid_conwidth.value;
+	float pixelpos = x * vid.mode.width / vid_conwidth.value;
 	int snap = (int) pixelpos;
 	if (pixelpos - snap >= roundUpAt) ++snap;
-	return ((float)snap * vid_conwidth.value / vid.width);
+	return ((float)snap * vid_conwidth.value / vid.mode.width);
 	/*
 	x = (int)(x * vid.width / vid_conwidth.value);
 	x = (x * vid_conwidth.value / vid.width);
@@ -529,10 +529,10 @@ static float snap_to_pixel_x(float x, float roundUpAt)
 
 static float snap_to_pixel_y(float y, float roundUpAt)
 {
-	float pixelpos = y * vid.height / vid_conheight.value;
+	float pixelpos = y * vid.mode.height / vid_conheight.value;
 	int snap = (int) pixelpos;
 	if (pixelpos - snap > roundUpAt) ++snap;
-	return ((float)snap * vid_conheight.value / vid.height);
+	return ((float)snap * vid_conheight.value / vid.mode.height);
 	/*
 	y = (int)(y * vid.height / vid_conheight.value);
 	y = (y * vid_conheight.value / vid.height);
@@ -788,7 +788,7 @@ void GL_Draw_Init (void)
 void DrawQ_Start(void)
 {
 	r_refdef.draw2dstage = 1;
-	R_ResetViewRendering2D_Common(0, NULL, NULL, 0, 0, vid.width, vid.height, vid_conwidth.integer, vid_conheight.integer);
+	R_ResetViewRendering2D_Common(0, NULL, NULL, 0, 0, vid.mode.width, vid.mode.height, vid_conwidth.integer, vid_conheight.integer);
 }
 
 qbool r_draw2d_force = false;
@@ -1146,8 +1146,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
 		ftbase_y = snap_to_pixel_y(ftbase_y, 0.3);
 	}
 
-	pix_x = vid.width / vid_conwidth.value;
-	pix_y = vid.height / vid_conheight.value;
+	pix_x = vid.mode.width / vid_conwidth.value;
+	pix_y = vid.mode.height / vid_conheight.value;
 
 	if (fontmap)
 		width_of = fnt->width_of_ft2[map_index];
@@ -1407,11 +1407,11 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f
 	if (fabs(x2 - x1) > fabs(y2 - y1))
 	{
 		offsetx = 0;
-		offsety = 0.5f * width * vid_conheight.value / vid.height;
+		offsety = 0.5f * width * vid_conheight.value / vid.mode.height;
 	}
 	else
 	{
-		offsetx = 0.5f * width * vid_conwidth.value / vid.width;
+		offsetx = 0.5f * width * vid_conwidth.value / vid.mode.width;
 		offsety = 0;
 	}
 	surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);
@@ -1438,7 +1438,7 @@ void DrawQ_SetClipArea(float x, float y, float width, float height)
 	{
 	case RENDERPATH_GL32:
 	case RENDERPATH_GLES2:
-		GL_Scissor(ix, vid.height - iy - ih, iw, ih);
+		GL_Scissor(ix, vid.mode.height - iy - ih, iw, ih);
 		break;
 	}
 
diff --git a/gl_rmain.c b/gl_rmain.c
index a8a92dd1..26c90911 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -4411,7 +4411,7 @@ void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdep
 
 	// GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
 	// Unless the render target is a FBO...
-	viewy_adjusted = viewfbo ? viewy : vid.height - viewheight - viewy;
+	viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy;
 
 	if (!r_refdef.view.useperspective)
 		R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
@@ -4454,7 +4454,7 @@ void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rt
 
 	// GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
 	// Unless the render target is a FBO...
-	viewy_adjusted = viewfbo ? viewy : vid.height - viewheight - viewy;
+	viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy;
 
 	R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, viewy_adjusted, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
 	R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
@@ -5070,8 +5070,8 @@ static void R_Bloom_StartFrame(void)
 		viewscalefpsadjusted = 1.0f;
 
 	scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
-	if (vid.samples)
-		scale *= sqrt(vid.samples); // supersampling
+	if (vid.mode.samples)
+		scale *= sqrt(vid.mode.samples); // supersampling
 	scale = bound(0.03125f, scale, 4.0f);
 	screentexturewidth = (int)ceil(r_refdef.view.width * scale);
 	screentextureheight = (int)ceil(r_refdef.view.height * scale);
@@ -10184,10 +10184,10 @@ void R_DebugLine(vec3_t start, vec3_t end)
 	Vector4Set(w[1], end[0], end[1], end[2], 1);
 	R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
 	R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
-	x1 = s[0][0] * vid_conwidth.value / vid.width;
-	y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
-	x2 = s[1][0] * vid_conwidth.value / vid.width;
-	y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
+	x1 = s[0][0] * vid_conwidth.value / vid.mode.width;
+	y1 = (vid.mode.height - s[0][1]) * vid_conheight.value / vid.mode.height;
+	x2 = s[1][0] * vid_conwidth.value / vid.mode.width;
+	y2 = (vid.mode.height - s[1][1]) * vid_conheight.value / vid.mode.height;
 	//Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
 
 	// add the line to the UI mesh for drawing later
@@ -10196,11 +10196,11 @@ void R_DebugLine(vec3_t start, vec3_t end)
 	if (fabs(x2 - x1) > fabs(y2 - y1))
 	{
 		offsetx = 0;
-		offsety = 0.5f * width * vid_conheight.value / vid.height;
+		offsety = 0.5f * width * vid_conheight.value / vid.mode.height;
 	}
 	else
 	{
-		offsetx = 0.5f * width * vid_conwidth.value / vid.width;
+		offsetx = 0.5f * width * vid_conwidth.value / vid.mode.width;
 		offsety = 0;
 	}
 	surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);
diff --git a/menu.c b/menu.c
index 7b51ab4c..38fc7adf 100644
--- a/menu.c
+++ b/menu.c
@@ -2242,8 +2242,8 @@ static void M_Options_ColorControl_Draw (void)
 
 	m_opty += 4;
 	DrawQ_Fill(menu_x, menu_y + m_opty, 320, 4 + 64 + 8 + 64 + 4, 0, 0, 0, 1, 0);m_opty += 4;
-	s = (float) 312 / 2 * vid.width / vid_conwidth.integer;
-	t = (float) 4 / 2 * vid.height / vid_conheight.integer;
+	s = (float) 312 / 2 * vid.mode.width / vid_conwidth.integer;
+	t = (float) 4 / 2 * vid.mode.height / vid_conheight.integer;
 	DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, dither, 312, 4, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0);m_opty += 4;
 	DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 1,0,0,1, 0,1, 0,0,0,1, 1,1, 1,0,0,1, 0);m_opty += 4;
 	DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, dither, 312, 4, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0);m_opty += 4;
@@ -2257,8 +2257,8 @@ static void M_Options_ColorControl_Draw (void)
 	c[1] = c[0];
 	c[2] = c[1];
 	VID_ApplyGammaToColor(c, c);
-	s = (float) 48 / 2 * vid.width / vid_conwidth.integer;
-	t = (float) 48 / 2 * vid.height / vid_conheight.integer;
+	s = (float) 48 / 2 * vid.mode.width / vid_conwidth.integer;
+	t = (float) 48 / 2 * vid.mode.height / vid_conheight.integer;
 	u = s * 0.5;
 	v = t * 0.5;
 	m_opty += 8;
@@ -2896,7 +2896,7 @@ void M_Menu_Video_f(cmd_state_t *cmd)
 	m_state = m_video;
 	m_entersound = true;
 
-	M_Menu_Video_FindResolution(vid.width, vid.height, vid_pixelheight.value);
+	M_Menu_Video_FindResolution(vid.mode.width, vid.mode.height, vid_pixelheight.value);
 }
 
 
@@ -2923,10 +2923,10 @@ static void M_Video_Draw (void)
 
 	// Current and Proposed Resolution
 	M_Print(16, video_cursor_table[t] - 12, "    Current Resolution");
-	if (vid_supportrefreshrate && vid.userefreshrate && vid.fullscreen)
-		M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d %.2fhz", vid.width, vid.height, vid.refreshrate));
+	if (vid_supportrefreshrate && vid.mode.userefreshrate && vid.mode.fullscreen)
+		M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d %.2fhz", vid.mode.width, vid.mode.height, vid.mode.refreshrate));
 	else
-		M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d", vid.width, vid.height));
+		M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d", vid.mode.width, vid.mode.height));
 	M_Print(16, video_cursor_table[t], "        New Resolution");
 	M_Print(220, video_cursor_table[t], va(vabuf, sizeof(vabuf), "%dx%d", menu_video_resolutions[menu_video_resolution].width, menu_video_resolutions[menu_video_resolution].height));
 	M_Print(96, video_cursor_table[t] + 8, va(vabuf, sizeof(vabuf), "Type: %s", menu_video_resolutions[menu_video_resolution].type));
@@ -3025,12 +3025,12 @@ static void M_Video_Key(cmd_state_t *cmd, int key, int ascii)
 	{
 		case K_ESCAPE:
 			// vid_shared.c has a copy of the current video config. We restore it
-			Cvar_SetValueQuick(&vid_fullscreen, vid.fullscreen);
-			Cvar_SetValueQuick(&vid_bitsperpixel, vid.bitsperpixel);
-			Cvar_SetValueQuick(&vid_samples, vid.samples);
+			Cvar_SetValueQuick(&vid_fullscreen, vid.mode.fullscreen);
+			Cvar_SetValueQuick(&vid_bitsperpixel, vid.mode.bitsperpixel);
+			Cvar_SetValueQuick(&vid_samples, vid.mode.samples);
 			if (vid_supportrefreshrate)
-				Cvar_SetValueQuick(&vid_refreshrate, vid.refreshrate);
-			Cvar_SetValueQuick(&vid_userefreshrate, vid.userefreshrate);
+				Cvar_SetValueQuick(&vid_refreshrate, vid.mode.refreshrate);
+			Cvar_SetValueQuick(&vid_userefreshrate, vid.mode.userefreshrate);
 
 			S_LocalSound ("sound/misc/menu1.wav");
 			M_Menu_Options_f(cmd);
@@ -5339,8 +5339,8 @@ static void MP_Draw (void)
 
 	// FIXME: this really shouldnt error out lest we have a very broken refdef state...?
 	// or does it kill the server too?
-	PRVM_G_FLOAT(OFS_PARM0) = vid.width;
-	PRVM_G_FLOAT(OFS_PARM1) = vid.height;
+	PRVM_G_FLOAT(OFS_PARM0) = vid.mode.width;
+	PRVM_G_FLOAT(OFS_PARM1) = vid.mode.height;
 	prog->ExecuteProgram(prog, PRVM_menufunction(m_draw),"m_draw() required");
 
 	// TODO: imo this should be moved into scene, too [1/27/2008 Andreas]
@@ -5628,7 +5628,7 @@ void MR_Init(void)
 	}
 
 	menu_video_resolutions_forfullscreen = !!vid_fullscreen.integer;
-	M_Menu_Video_FindResolution(vid.width, vid.height, vid_pixelheight.value);
+	M_Menu_Video_FindResolution(vid.mode.width, vid.mode.height, vid_pixelheight.value);
 
 	// use -forceqmenu to use always the normal quake menu (it sets forceqmenu to 1)
 // COMMANDLINEOPTION: Client: -forceqmenu disables menu.dat (same as +forceqmenu 1)
diff --git a/mvm_cmds.c b/mvm_cmds.c
index 41c0d1bb..812930fd 100644
--- a/mvm_cmds.c
+++ b/mvm_cmds.c
@@ -793,9 +793,9 @@ static void VM_M_getmousepos(prvm_prog_t *prog)
 	if (key_consoleactive || (key_dest != key_menu && key_dest != key_menu_grabbed))
 		VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
 	else if (in_client_mouse)
-		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
+		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.mode.width, in_windowmouse_y * vid_conheight.integer / vid.mode.height, 0);
 	else
-		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
+		VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.mode.width, in_mouse_y * vid_conheight.integer / vid.mode.height, 0);
 }
 
 static void VM_M_crypto_getkeyfp(prvm_prog_t *prog)
diff --git a/vid.h b/vid.h
index 0f140b09..e360c712 100644
--- a/vid.h
+++ b/vid.h
@@ -69,14 +69,7 @@ typedef struct viddef_s
 {
 	// these are set by VID_Mode
 	// used in many locations in the renderer
-	int width;
-	int height;
-	int bitsperpixel;
-	qbool fullscreen;
-	float refreshrate;
-	qbool userefreshrate;
-	qbool stereobuffer;
-	int samples;
+	viddef_mode_t mode; ///< currently active video mode
 	qbool stencil;
 	qbool sRGB2D; // whether 2D rendering is sRGB corrected (based on sRGBcapable2D)
 	qbool sRGB3D; // whether 3D rendering is sRGB corrected (based on sRGBcapable3D)
diff --git a/vid_sdl.c b/vid_sdl.c
index 9f921a30..742dd0b1 100644
--- a/vid_sdl.c
+++ b/vid_sdl.c
@@ -879,8 +879,8 @@ static void IN_Move_TouchScreen_Quake(void)
 
 	// simple quake controls
 	multitouch[MAXFINGERS-1][0] = SDL_GetMouseState(&x, &y);
-	multitouch[MAXFINGERS-1][1] = x * 32768 / vid.width;
-	multitouch[MAXFINGERS-1][2] = y * 32768 / vid.height;
+	multitouch[MAXFINGERS-1][1] = x * 32768 / vid.mode.width;
+	multitouch[MAXFINGERS-1][2] = y * 32768 / vid.mode.height;
 
 	// top of screen is toggleconsole and K_ESCAPE
 	switch(keydest)
@@ -1190,7 +1190,7 @@ void Sys_SDL_HandleEvents(void)
 							//vid.width = event.window.data1;
 							//vid.height = event.window.data2;
 							// get the real framebuffer size in case the platform's screen coordinates are DPI scaled
-							SDL_GL_GetDrawableSize(window, &vid.width, &vid.height);
+							SDL_GL_GetDrawableSize(window, &vid.mode.width, &vid.mode.height);
 						}
 						break;
 					case SDL_WINDOWEVENT_SIZE_CHANGED: // internal and external events
@@ -1398,7 +1398,7 @@ static void VID_ApplyDisplaySettings_c(cvar_t *var)
 			Con_Printf(CON_ERROR "ERROR: can't deactivate fullscreen on display %i because %s\n", vid.displayindex, SDL_GetError());
 			return;
 		}
-		vid.fullscreen = false;
+		vid.mode.fullscreen = false;
 		Con_DPrintf("Fullscreen deactivated on display %i\n", vid.displayindex);
 	}
 
@@ -1406,7 +1406,7 @@ static void VID_ApplyDisplaySettings_c(cvar_t *var)
 	if (!fullscreenwanted)
 	{
 		int toppx;
-		SDL_SetWindowSize(window, vid.width = vid_width.integer, vid.height = vid_height.integer);
+		SDL_SetWindowSize(window, vid.mode.width = vid_width.integer, vid.mode.height = vid_height.integer);
 		SDL_SetWindowResizable(window, vid_resizable.integer ? SDL_TRUE : SDL_FALSE);
 		SDL_SetWindowBordered(window, (SDL_bool)!vid_borderless.integer);
 		SDL_GetWindowBordersSize(window, &toppx, NULL, NULL, NULL);
@@ -1433,8 +1433,8 @@ static void VID_ApplyDisplaySettings_c(cvar_t *var)
 			Con_Printf(CON_ERROR "Error getting bounds of display %i: \"%s\"\n", displaywanted, SDL_GetError());
 			return;
 		}
-		vid.xPos = displaybounds.x + 0.5 * (displaybounds.w - vid.width);
-		vid.yPos = displaybounds.y + 0.5 * (displaybounds.h - vid.height);
+		vid.xPos = displaybounds.x + 0.5 * (displaybounds.w - vid.mode.width);
+		vid.yPos = displaybounds.y + 0.5 * (displaybounds.h - vid.mode.height);
 		SDL_SetWindowPosition(window, vid.xPos, vid.yPos);
 
 		vid.displayindex = displaywanted;
@@ -1469,8 +1469,8 @@ static void VID_ApplyDisplaySettings_c(cvar_t *var)
 			return;
 		}
 		// get the real framebuffer size in case the platform's screen coordinates are DPI scaled
-		SDL_GL_GetDrawableSize(window, &vid.width, &vid.height);
-		vid.fullscreen = true;
+		SDL_GL_GetDrawableSize(window, &vid.mode.width, &vid.mode.height);
+		vid.mode.fullscreen = true;
 		Con_DPrintf("Fullscreen activated on display %i\n", vid.displayindex);
 	}
 }
diff --git a/vid_shared.c b/vid_shared.c
index f8868f95..bc834776 100644
--- a/vid_shared.c
+++ b/vid_shared.c
@@ -834,7 +834,7 @@ void GL_Setup(void)
 	{
 		int samples = 0;
 		qglGetIntegerv(GL_SAMPLES, &samples);
-		vid.samples = samples;
+		vid.mode.samples = samples;
 		if (samples > 1)
 			qglEnable(GL_MULTISAMPLE);
 		else
@@ -1404,13 +1404,7 @@ static int VID_Mode(int fullscreen, int width, int height, int bpp, float refres
 	if (VID_InitMode(&mode))
 	{
 		// accept the (possibly modified) mode
-		vid.fullscreen     = mode.fullscreen;
-		vid.width          = mode.width;
-		vid.height         = mode.height;
-		vid.bitsperpixel   = mode.bitsperpixel;
-		vid.refreshrate    = mode.refreshrate;
-		vid.userefreshrate = mode.userefreshrate;
-		vid.stereobuffer   = mode.stereobuffer;
+		vid.mode = mode;
 		vid.stencil        = mode.bitsperpixel > 16;
 		vid.sRGB2D         = vid_sRGB.integer >= 1 && vid.sRGBcapable2D;
 		vid.sRGB3D         = vid_sRGB.integer >= 1 && vid.sRGBcapable3D;
@@ -1422,13 +1416,13 @@ static int VID_Mode(int fullscreen, int width, int height, int bpp, float refres
 			{
 				GLboolean stereo;
 				qglGetBooleanv(GL_STEREO, &stereo);
-				vid.stereobuffer = stereo != 0;
+				vid.mode.stereobuffer = stereo != 0;
 			}
 #endif
 			break;
 		case RENDERPATH_GLES2:
 		default:
-			vid.stereobuffer = false;
+			vid.mode.stereobuffer = false;
 			break;
 		}
 
@@ -1466,13 +1460,7 @@ void VID_Restart_f(cmd_state_t *cmd)
 	if (vid_commandlinecheck)
 		return;
 
-	oldmode.fullscreen     = vid.fullscreen;
-	oldmode.width          = vid.width;
-	oldmode.height         = vid.height;
-	oldmode.bitsperpixel   = vid.bitsperpixel;
-	oldmode.refreshrate    = vid.refreshrate;
-	oldmode.userefreshrate = vid.userefreshrate;
-	oldmode.stereobuffer   = vid.stereobuffer;
+	oldmode = vid.mode;
 
 	Con_Printf("VID_Restart: changing from %s %dx%dx%dbpp%s, to %s %dx%dx%dbpp%s.\n",
 		oldmode.fullscreen ? "fullscreen" : "window", oldmode.width, oldmode.height, oldmode.bitsperpixel, oldmode.fullscreen && oldmode.userefreshrate ? va(vabuf, sizeof(vabuf), "x%.2fhz", oldmode.refreshrate) : "",
-- 
2.39.5