GL Gamma Correction

Discuss programming topics for the various GPL'd game engine sources.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: GL Gamma Correction

Post by Baker »

reckless wrote:Definatly worth it sifting through mh's older OpenGL engine sources, lots of non standard but amazingly well working ideas :) His Q2 sources are also worth having a look at, many nice ideas in them.
Well, your code post was a major asset to my recent engine work. I entirely rewrote all the video code, all the input code, some of the menu code, reworked the lightmap code and with this added I have an engine that I can stand to look at the source code. The size of source files dropped 33% after rewriting the ghastly Quake video and input code to be light and tight. (* look how short my platform neutral vid.c is, below)

Now I'm debating on whether to quickly port to OS X natively or via SDL. Or both so someone Linuxy has the opportunity to use the engine, I have worked with Linux before but it is so much work and hassles for so few users and so many diverse problems with such fragmentation of distros and versions.

But either way, I have say this was the icing on the cake. :D I still can't believe how fast it is for code that has to operate on the entire buffer. And this code has motivated me to push the boundaries on other things that irritate me.

Code: Select all

// vid.c -- common video

#include "quakedef.h"

viddef_t	vid; // global video state

cvar_t		vid_fullscreen = {"vid_fullscreen", "1", CVAR_ARCHIVE};
cvar_t		vid_width = {"vid_width", "640", CVAR_ARCHIVE};
cvar_t		vid_height = {"vid_height", "480", CVAR_ARCHIVE};
cvar_t		vid_bpp = {"vid_bpp", "32", CVAR_ARCHIVE};
cvar_t		vid_vsync = {"vid_vsync", "0", CVAR_ARCHIVE};

//
// set mode and restart
//

/*
================
VID_SetMode
================
*/
int VID_SetMode (int modenum)
{
// so Con_Printfs don't mess us up by forcing vid and snd updates
	int	temp = scr_disabled_for_loading;
	qboolean re_setupgl;

	scr_disabled_for_loading = true;
	vid.canalttab = false;

	// Stop Sounds
	S_BlockSound ();
	S_ClearBuffer ();
	CDAudio_Pause ();

	// Platform specific stuff
	re_setupgl = (VID_Local_SetMode (modenum) == false);

	// Assignment
	{
		vid.modenum_screen = modenum;
		vid.screen = vid.modelist[vid.modenum_screen];
		// keep cvars in line with actual mode
		VID_Cvars_Sync_To_Mode (&vid.modelist[vid.modenum_screen]);

		// Refresh console
		SCR_Conwidth_f (NULL);
		vid.recalc_refdef = 1;
		vid.numpages = 2;
	}

	// GL break-in
	GL_Evaluate_Renderer ();
	GL_SetupState ();
	// ensure swap settings right
	VID_Local_Vsync_f (NULL);
	if (re_setupgl)
	{
		Con_DPrintf ("Reuploading images\n");	
		TexMgr_ReloadImages (); // SAFE?
	} else Con_DPrintf ("Reused context no reupload images\n");

	TexMgr_RecalcWarpImageSize (); // SAFE?

	// Restore sound
	Input_Think ();
	S_UnblockSound ();
	CDAudio_Resume ();

	vid.canalttab = true;
	scr_disabled_for_loading = temp;
	
	return true;
}

qboolean VID_Restart (int flags /* favorite vs. temp*/)
{
	vmode_t		newmode = VID_Cvars_To_Mode ();
	vmode_t		oldmode = vid.screen;
	int			newmodenum;
	
	// No change scenario
	if ( memcmp (&newmode, &oldmode, sizeof(vmode_t)) == 0)
	{
		Con_Printf ("Video mode request is same as current mode.\n");
		return false;
	}

	// Fullscreen must check existing modes, window must set it instead.
	switch (newmode.type)
	{
	case MODE_WINDOWED:
		memcpy (&vid.modelist[MODE_WINDOWED], &newmode, sizeof (vmode_t) );
		newmodenum = 0;
		break;

	case MODE_FULLSCREEN:
		if (VID_Mode_Exists (&newmode, &newmodenum) == false)
		{
			Con_Printf ("%d x %d x %d (%i) is not a valid fullscreen mode\n",
				(int)vid_width.value,
				(int)vid_height.value,
				(int)vid_bpp.value,
				(int)vid_fullscreen.value);
			return false;
		}
		break;
	}
	
	// Determine if the mode is invalid.

	VID_SetMode (newmodenum);

	if (flags == USER_SETTING_FAVORITE_MODE)
		vid.modenum_user_selected = vid.modenum_screen;

	return true;
}

/*
================
VID_Test -- johnfitz -- like vid_restart, but asks for confirmation after switching modes
================
*/
void VID_Test (void)
{
	vmode_t		newmode = VID_Cvars_To_Mode ();
	vmode_t		oldmode = vid.screen;
	qboolean	mode_changed = memcmp (&newmode, &vid.screen, sizeof(vmode_t) );
	
	if (!mode_changed)
		return;
//
// now try the switch
//
	VID_Restart (USER_SETTING_FAVORITE_MODE);

	//pop up confirmation dialog
	if (!SCR_ModalMessage("Would you like to keep this\nvideo mode? (y/n)\n", 5.0f))
	{
		// User rejected new mode: revert cvars and mode
		VID_Cvars_Sync_To_Mode (&oldmode);
		VID_Restart (USER_SETTING_FAVORITE_MODE);
	}
}

void VID_Alt_Enter_f (void)
{
	if (vid.modenum_screen != vid.modenum_user_selected) 
	{
		// Go to favorite mode
		VID_Cvars_Sync_To_Mode ( &vid.modelist[vid.modenum_user_selected] );
		VID_Restart (USER_SETTING_FAVORITE_MODE);
		return;
	}

// ALT-ENTER to a temp mode
	if (vid.screen.type == MODE_WINDOWED)
		VID_Cvars_Set_Autoselect_Temp_Fullscreen_Mode (vid.modenum_screen);
	else  VID_Cvars_Set_Autoselect_Temp_Windowed_Mode (vid.modenum_screen);

	VID_Restart (ALT_ENTER_TEMPMODE);
}


void VID_Restart_f (void)
{
	VID_Restart (USER_SETTING_FAVORITE_MODE);
}

//
// in-game
//


void VID_AppActivate(qboolean fActive, qboolean minimize)
{
	vid.ActiveApp = fActive;
	vid.Minimized = minimize;

//	Con_Printf ("App activate occurred %i\n", vid.ActiveApp);

	if (vid.ActiveApp)
	{
		if (!vid.sound_active)
		{
			S_UnblockSound ();
			vid.sound_active = true;
		}
		if (vid.screen.type == MODE_FULLSCREEN && vid.canalttab && vid.wassuspended) 
		{
			VID_Local_Suspend (false);
			vid.wassuspended = false;
		}
	}

	if (!vid.ActiveApp)
	{
		if (vid.screen.type == MODE_FULLSCREEN && vid.canalttab) 
		{
			VID_Local_Suspend (true);
			vid.wassuspended = true;
		}

		if (vid.sound_active)
		{
			S_BlockSound ();
			vid.sound_active = false;
		}
	}
}

void VID_SwapBuffers (void)
{
	VID_Local_SwapBuffers ();
}

//
// functions to match modes to cvars or reverse
//

void VID_Cvars_Sync_To_Mode (vmode_t* mymode)
{
	// Don't allow anything exiting to call this.  I think we are "ok"
	Cvar_SetValue (vid_width.name, (float)mymode->width);
	Cvar_SetValue (vid_height.name, (float)mymode->height);
	Cvar_SetValue (vid_bpp.name, (float)mymode->bpp);
	Cvar_SetValue (vid_fullscreen.name, mymode->type == MODE_FULLSCREEN ? 1 : 0);
}

vmode_t VID_Cvars_To_Mode (void)
{
	vmode_t retmode;

	retmode.type	= vid_fullscreen.value ? MODE_FULLSCREEN : MODE_WINDOWED;
	retmode.width	= (int)vid_width.value;
	retmode.height	= (int)vid_height.value;
	retmode.bpp		= (int)vid_bpp.value;
	
	if (retmode.type == MODE_WINDOWED)
	{
		retmode.width	= CLAMP (MIN_WINDOWED_MODE_WIDTH, retmode.width, vid.desktop.width);
		retmode.height	= CLAMP (MIN_WINDOWED_MODE_HEIGHT, retmode.height, vid.desktop.height);
		retmode.bpp		= vid.desktop.bpp;
	}
	
	return retmode;
}

static qboolean VID_Read_Early_Cvars_For_File (const char* config_file_name)
{
	qboolean found_any_vid_cvars = false;
	cvar_t	*video_cvars[] = {&vid_fullscreen, &vid_width, &vid_height, &vid_bpp, &scr_brightness, NULL};
	char	config_buffer[8192];
	FILE	*f;
	int		bytes_size = COM_FOpenFile (config_file_name, &f);
	int		i;
	

	// Read the file into the buffer.  Read the first 8000 bytes (if longer, tough cookies)
	// Because it is pretty likely that size of file will get a "SZ_GetSpace: overflow without allowoverflow set"
	// During command execution

	if (bytes_size !=-1)
	{
		int	bytes_in = q_min (bytes_size, 8000); // Cap at 8000
		int bytes_read = fread (config_buffer, 1, bytes_in, f);
		config_buffer [bytes_read + 1] = 0; // Null terminate just in case

		fclose (f);
	} else return false;

	for (i = 0; video_cvars[i]; i++)
	{
		float value;
		qboolean found = Parse_Float_From_String (&value, config_buffer, video_cvars[i]->name);

//		MessageBox (NULL, va("Cvar %s was %s and is %g", video_cvars[i]->name, found ? "Found" : "Not found", found ? value : 0), "", MB_OK);

		if (found == false)
			continue;

		Cvar_SetValue (video_cvars[i]->name, value);
		found_any_vid_cvars = true;
	}

	return found_any_vid_cvars;
}

qboolean VID_Read_Early_Cvars (void)
{

	// Any of these found and we bail
	char *video_override_commandline_params[] = {"-window", "-width", "-height", "-current", "-bpp", NULL } ;
	qboolean found_in_config, found_in_autoexec;
	int i;

	for (i = 0; video_override_commandline_params[i]; i++)
		if (COM_CheckParm (video_override_commandline_params[i]))
			return false;

	found_in_config = VID_Read_Early_Cvars_For_File (CONFIG_CFG);
	found_in_autoexec = VID_Read_Early_Cvars_For_File (AUTOEXEC_CFG);

	return (found_in_config || found_in_autoexec);
}


qboolean VID_Mode_Exists (vmode_t* test, int *outmodenum)
{
	int i;

	for (i = 0; i < vid.nummodes; i++)
	{
		if (memcmp (&vid.modelist[i], test, sizeof(vmode_t)))
			continue; // No match

		// dup
		if (outmodenum) *outmodenum = i;
		return true; // Duplicate
	}
	return false;
}

void VID_MakeMode (modestate_t mode_type, vmode_t *new_mode)
{
	new_mode->type	= mode_type;
	new_mode->width	= 640;
	new_mode->height= 480;
	new_mode->bpp	= vid.desktop.bpp;

	// !!(int)vid_fullscreen.value --> turn into an int and "NOT" it twice 
	// so must have 0 or 1 value.  In case vid_fullscreen is 2 or something weird
	if ( (!!(int)vid_fullscreen.value) == mode_type)
	{
		new_mode->width = vid_width.value;
		new_mode->height= vid_height.value;
		new_mode->bpp	= vid_bpp.value;
	} 
	vid.nummodes ++;
}

void VID_Cvars_Set_Autoselect_Temp_Windowed_Mode (int favoritemode)
{
	// Pencil in last windowed mode, but set the bpp to the desktop bpp
	VID_Cvars_Sync_To_Mode (&vid.modelist[MODE_WINDOWED]);
	Cvar_SetValue (vid_bpp.name, (float)vid.desktop.bpp);
}

void VID_Cvars_Set_Autoselect_Temp_Fullscreen_Mode (int favoritemode)
{
	vmode_t *fave = &vid.modelist[favoritemode];
	int best = -1;
	int	bestscore = -1;
	int i;

	// Look through the video modes.

	// If an exact matching fullscreen mode of same resolution
	// exists, pick that.  Try to go for same bpp.

	// Attempt 1: Match resolution

	// Baker: Locate matching mode
	for (i = 1; i < vid.nummodes; i ++)
	{
		vmode_t *mode = &vid.modelist[i];
		int size_match		= (mode->width == fave->width && mode->height == fave->height);
		int bpp_match		= mode->bpp == fave->bpp;
		int bpp_deskmatch	= mode->bpp == vid.desktop.bpp;

		int score = size_match * 20 + bpp_match * 5 + bpp_deskmatch;

		if (score <= bestscore)
			continue;  // Didn't beat best
		
		// New best
		best = i;
		bestscore = score;
	}

	if (bestscore < 20)
	{
		// No size match ... try again
		// If fails, pick something with width/height both divisble by 8
		// so charset doesn't look stretched.  Go for largest mode with
		// desktop bpp and desktop refreshrate and desktop width/height
		// Unless those are stupid.

		best = -1;
		bestscore = -1;

		for (i = 1; i < vid.nummodes; i ++)
		{
			vmode_t *mode = &vid.modelist[i];

			if (mode->width & 7)
				continue; // Skip stupid resolutions
			if (mode->height & 7)
				continue; // Skip stupid resolutions
			if (mode->bpp != vid.desktop.bpp && mode->bpp != fave->bpp)
				continue;

			if (mode->width >= vid.desktop.width - 7)
				if (mode->height >= vid.desktop.height - 7)
				{
					// Take it
					best = i;
					break;
				}

			// Not an automatic winner.  If largest ...
			if (mode->width >= vid.modelist[best].width || mode->height >= vid.modelist[best].height)
			{
				best = i;
			}
		}

		if (best == -1)
			Sys_Error ("Couldn't find suitable video mode");

	}

	// Set cvars
	VID_Cvars_Sync_To_Mode (&vid.modelist[best]);

	// Ok ... cvars are ready !
}


//
// startup / shutdown
//

void	VID_Init (void)
{
	int		i;

	qboolean videos_cvars_read;

	vid.desktop = VID_Local_GetDesktopProperties (); // Good time to get them.

	Cvar_RegisterVariable (&vid_fullscreen);
	Cvar_RegisterVariable (&vid_width);
	Cvar_RegisterVariable (&vid_height);
	Cvar_RegisterVariable (&vid_bpp);
	Cvar_RegisterVariableWithCallback (&vid_vsync, VID_Local_Vsync_f);
	Cvar_RegisterVariable (&scr_brightness);

	Cmd_AddCommand ("vid_restart", VID_Restart_f);
	Cmd_AddCommand ("vid_test", VID_Test);
	Cmd_AddCommand ("gl_info", GL_Info_f);

	// Now, if we have -window or anything we don't bother to read the cvars early
	// But we will still read them later.

	videos_cvars_read = VID_Read_Early_Cvars ();

	if ((i = COM_CheckParm("-width")) && i + 1 < com_argc)
		Cvar_SetValue (vid_width.name, (float)atoi(com_argv[i+1]) );

	if ((i = COM_CheckParm("-height")) && i + 1 < com_argc)
		Cvar_SetValue (vid_height.name, (float)atoi(com_argv[i+1]) );

	if ((i = COM_CheckParm("-bpp")) && i + 1 < com_argc)
		Cvar_SetValue (vid_bpp.name, (float)atoi(com_argv[i+1]) );

	if (COM_CheckParm("-current"))
	{
		VID_Cvars_Sync_To_Mode (&vid.desktop); // Use desktop sizes.
	}

	if (COM_CheckParm("-window"))
		Cvar_SetValue (vid_fullscreen.name, 0);

	VID_Local_Window_PreSetup ();

// Add the default windowed and default fullscreen modes.
// This does allow a user to do an invalid mode in the a command line, but that's on them.
	VID_MakeMode (MODE_WINDOWED,   &vid.modelist[MODE_WINDOWED]);
	VID_MakeMode (MODE_FULLSCREEN, &vid.modelist[MODE_FULLSCREEN]);

// Add the fullscreen modes
	VID_Local_AddFullscreenModes ();

	if (COM_CheckParm("-fullsbar"))
		vid.fullsbardraw = true;

	vid.initialized = true;

// Now we set the video mode

	VID_SetMode (vid_fullscreen.value ? MODE_FULLSCREEN : MODE_WINDOWED);

	vid.modenum_user_selected = vid.modenum_screen; // Default choice	

	VID_Menu_Init(); //johnfitz
}


void VID_Shutdown (void)
{
   	if (!vid.initialized)
		return;

	VID_Local_Window_Renderer_Teardown (TEARDOWN_FULL);
	vid.canalttab = false;
}
You might think the platform neutral video code is short because the platform-specific code is long. Except it's not true. :D :D It's even shorter.

Code: Select all

// vid_wgl.c -- Windows specific

#include "quakedef.h"
#include "winquake.h"
#include "resource.h" // IDI_ICON2

wplat_t wplat;

//
// miscelleanous init
//

void VID_Local_Window_PreSetup (void)
{
	WNDCLASS		wc;
	wplat.hIcon = LoadIcon (wplat.hInstance, MAKEINTRESOURCE (IDI_ICON2));


	// Register the frame class
    wc.style         = 0;
    wc.lpfnWndProc   = (WNDPROC)WIN_MainWndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = wplat.hInstance;
    wc.hIcon         = wplat.hIcon;
    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
	wc.hbrBackground = NULL;
    wc.lpszMenuName  = 0;
    wc.lpszClassName = ENGINE_NAME;

    if (!RegisterClass (&wc) )
		Sys_Error ("Couldn't register window class");
	
}

vmode_t VID_Local_GetDesktopProperties (void)
{
	DEVMODE	devmode;
	vmode_t desktop = {0};

	if (!EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &devmode))
	{
		Sys_Error ("VID_UpdateDesktopProperties: EnumDisplaySettings failed\n");
		return desktop;
	}

	desktop.type		=	MODE_FULLSCREEN;
	desktop.width		=	devmode.dmPelsWidth;
	desktop.height		=	devmode.dmPelsHeight;
	desktop.bpp			=	devmode.dmBitsPerPel;
	
	return desktop;
}

//
// vsync
//


qboolean VID_Local_Vsync_Init (const char* gl_extensions_str)
{
	if (strstr(gl_extensions_str, "GL_EXT_swap_control") || strstr(gl_extensions_str, "GL_WIN_swap_hint"))

	{
		wplat.wglSwapIntervalEXT = (SETSWAPFUNC) wglGetProcAddress("wglSwapIntervalEXT");
		wplat.wglGetSwapIntervalEXT = (GETSWAPFUNC) wglGetProcAddress("wglGetSwapIntervalEXT");

		if (wplat.wglSwapIntervalEXT && wplat.wglGetSwapIntervalEXT && wplat.wglSwapIntervalEXT(0) && 
			wplat.wglGetSwapIntervalEXT() != -1)
				return true;
	}
	return false;
}

void VID_Local_Vsync_f (cvar_t *var)
{
	if (renderer.gl_swap_control)
	{
		if (vid_vsync.value)
		{
			if (!wplat.wglSwapIntervalEXT(1))
				Con_Printf ("VID_Vsync_f: failed on wglSwapIntervalEXT\n");
		}
		else
		{
			if (!wplat.wglSwapIntervalEXT(0))
				Con_Printf ("VID_Vsync_f: failed on wglSwapIntervalEXT\n");
		}
	}
}

//
// vid modes
//


void VID_Local_AddFullscreenModes (void)
{

	BOOL		stat;						// Used to test mode validity
	DEVMODE		devmode = {0};
	int			hmodenum = 0;				// Hardware modes start at 0

	// Baker: Run through every display mode and get information
	
	while ( (stat = EnumDisplaySettings (NULL, hmodenum++, &devmode)) && vid.nummodes < MAX_MODE_LIST )
	{
		vmode_t test		= { MODE_FULLSCREEN, devmode.dmPelsWidth, devmode.dmPelsHeight, devmode.dmBitsPerPel };
		qboolean bpp_ok		= (devmode.dmBitsPerPel >= 16);
		qboolean width_ok	= INBOUNDS (MIN_MODE_WIDTH, devmode.dmPelsWidth, MAX_MODE_WIDTH);
		qboolean height_ok	= INBOUNDS (MIN_MODE_HEIGHT, devmode.dmPelsHeight, MAX_MODE_HEIGHT);
		qboolean qualified	= (bpp_ok && width_ok && height_ok);

		devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;

		if (qualified && !VID_Mode_Exists(&test, NULL) && ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
		{
			// Not a dup and test = ok ---> add it
			memcpy (&vid.modelist[vid.nummodes++], &test, sizeof(vmode_t) );
		}
	}
}


void WIN_Construct_Or_Resize_Window (DWORD style, DWORD exstyle, RECT window_rect)
{
	const char* nm = ENGINE_NAME;
	
	int x = window_rect.left, y = window_rect.top;
	int w = RECT_WIDTH(window_rect), h = RECT_HEIGHT(window_rect);

	if (wplat.mainwindow)
	{
		SetWindowLong (wplat.mainwindow, GWL_EXSTYLE, exstyle);
		SetWindowLong (wplat.mainwindow, GWL_STYLE, style);
		SetWindowPos  (wplat.mainwindow, NULL, x, y, w, h, SWP_DRAWFRAME);
		return;
	}
	
	wplat.mainwindow = CreateWindowEx (exstyle, nm, nm, style, x, y, w, h, NULL, NULL, wplat.hInstance, NULL);

	if (!wplat.mainwindow) Sys_Error ("Couldn't create DIB window");
}

void WIN_Change_DisplaySettings (int modenum)
{
	// Change display settings
	wplat.gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
	wplat.gdevmode.dmBitsPerPel = vid.modelist[modenum].bpp;
	wplat.gdevmode.dmPelsWidth = vid.modelist[modenum].width;
	wplat.gdevmode.dmPelsHeight = vid.modelist[modenum].height;
	wplat.gdevmode.dmSize = sizeof (DEVMODE);

	if (ChangeDisplaySettings (&wplat.gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
		Sys_Error ("Couldn't set fullscreen mode %i x %i @ %i bpp", vid.modelist[modenum].width, vid.modelist[modenum].height, vid.modelist[modenum].bpp);
}

// Returns false if need to do GL setup again.
qboolean VID_Local_SetMode (int modenum)
{
	qboolean reuseok = false;
	RECT client_rect	= {0,0,vid.modelist[modenum].width, vid.modelist[modenum].height};
	RECT window_rect	= client_rect;
	qboolean bordered	= vid.modelist[modenum].type   == MODE_WINDOWED &&
						  (vid.modelist[modenum].width  != vid.desktop.width || 
						  vid.modelist[modenum].height != vid.desktop.height);

	DWORD ExWindowStyle = 0;
	DWORD WindowStyle	= bordered ? DW_BORDERED : DW_BORDERLESS;
	qboolean restart = (wplat.mainwindow != NULL);
	
	// Preserve these for hopeful reuse.
	HDC wglHDC 		= restart ? wglGetCurrentDC() : 0;
	HGLRC wglHRC 	= restart ? wglGetCurrentContext() : 0;

	if (restart)
		VID_Local_Window_Renderer_Teardown (TEARDOWN_NO_DELETE_GL_CONTEXT);
	
	if (vid.modelist[modenum].type == MODE_FULLSCREEN)
		WIN_Change_DisplaySettings (modenum);

	AdjustWindowRectEx (&window_rect, WindowStyle, FALSE, ExWindowStyle);
	WIN_AdjustRectToCenterScreen(&window_rect);

	WIN_Construct_Or_Resize_Window (WindowStyle, ExWindowStyle, window_rect);

	if (vid.modelist[modenum].type == MODE_WINDOWED)
		ChangeDisplaySettings (NULL, 0);

	// clear to black so it isn't empty
	wplat.draw_context = GetDC(wplat.mainwindow);
	PatBlt (wplat.draw_context, 0, 0, vid.modelist[modenum].width,vid.modelist[modenum].height, BLACKNESS);

// Get focus if we can, get foreground, finish setup, pump messages.
// then sleep a little.

	ShowWindow (wplat.mainwindow, SW_SHOWDEFAULT);
	UpdateWindow (wplat.mainwindow);
	SetWindowPos (wplat.mainwindow, HWND_TOP, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOCOPYBITS);
	SetForegroundWindow (wplat.mainwindow);

	{
	    MSG				msg;
		while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
		{
	      	TranslateMessage (&msg);
	      	DispatchMessage (&msg);
		}
	
		Sleep (100);
	}

	WIN_SetupPixelFormat (wplat.draw_context);
	if (wglHRC && (reuseok = wglMakeCurrent (wplat.draw_context, wglHRC)) == 0)
	{
		// Tried to reuse context and it failed
		wglDeleteContext (wglHRC);
		wglHRC = NULL;
		Con_Printf ("Context reuse failed.  Must reload textures.\n");
	}

	if (!wglHRC)
	{
		// Must create a context.
		wglHRC = wglCreateContext( wplat.draw_context );
		if (!wglHRC)
			Sys_Error ("Could not initialize GL (wglCreateContext failed).\n\nMake sure you in are 65535 color mode, and try running -window.");
		if (!wglMakeCurrent( wplat.draw_context, wglHRC ))
			Sys_Error ("VID_Init: wglMakeCurrent failed");
	}

	return reuseok;
}

//
// in game
//

void VID_Local_SwapBuffers (void)
{
	if (SwapBuffers (wplat.draw_context) == 0)
		MessageBox (NULL, "Swapbuffers failed", "", MB_OK);
}


void VID_Local_Suspend (qboolean bSuspend)
{
	if (bSuspend == false)
	{
		ChangeDisplaySettings (&wplat.gdevmode, CDS_FULLSCREEN);
		ShowWindow(wplat.mainwindow, SW_SHOWNORMAL);
		MoveWindow(wplat.mainwindow, 0, 0, wplat.gdevmode.dmPelsWidth, wplat.gdevmode.dmPelsHeight, false); //johnfitz -- alt-tab fix via Baker
	} else  ChangeDisplaySettings (NULL, 0);
}

//
// window setup
//


BOOL WIN_SetupPixelFormat(HDC hDC)
{
    static PIXELFORMATDESCRIPTOR pfd = {
	sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
	1,						// version number
	PFD_DRAW_TO_WINDOW |	// support window
	PFD_SUPPORT_OPENGL |	// support OpenGL
	PFD_DOUBLEBUFFER,		// double buffered
	PFD_TYPE_RGBA,			// RGBA type
	24,						// 24-bit color depth
	0, 0, 0, 0, 0, 0,		// color bits ignored
	0,						// no alpha buffer
	0,						// shift bit ignored
	0,						// no accumulation buffer
	0, 0, 0, 0, 			// accum bits ignored
	32,						// 32-bit z-buffer
	0,						// no stencil buffer
	0,						// no auxiliary buffer
	PFD_MAIN_PLANE,			// main layer
	0,						// reserved
	0, 0, 0					// layer masks ignored
    };
    int pixelformat;
	PIXELFORMATDESCRIPTOR  test; //johnfitz

    if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
    {
        MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
        return FALSE;
    }

	DescribePixelFormat(hDC, pixelformat, sizeof(PIXELFORMATDESCRIPTOR), &test); //johnfitz

    if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE)
    {
        MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
        return FALSE;
    }

    return TRUE;
}

void WIN_AdjustRectToCenterScreen (RECT *in_windowrect)
{
	vmode_t desktop = VID_Local_GetDesktopProperties ();
	int nwidth  = in_windowrect->right - in_windowrect->left;
	int nheight = in_windowrect->bottom - in_windowrect->top;

	in_windowrect->left = 0 + (desktop.width - nwidth) / 2;
	in_windowrect->top =  0 + (desktop.height - nheight) / 2;
	in_windowrect->right = in_windowrect->left + nwidth;
	in_windowrect->bottom = in_windowrect->top + nheight;
}

// 
// window teardown
//

void VID_Local_Window_Renderer_Teardown (int destroy)
{
	// destroy = 1 = TEARDOWN_FULL else TEARDOWN_NO_DELETE_GL_CONTEXT (don't destroy the context or destroy window)
	HGLRC hRC = wglGetCurrentContext();
    HDC	  hDC = wglGetCurrentDC();

    wglMakeCurrent(NULL, NULL);

    if (hRC && destroy)		wglDeleteContext(hRC);
	if (hDC)				ReleaseDC(wplat.mainwindow, hDC);

	if (wplat.draw_context)	
	{
		ReleaseDC (wplat.mainwindow, wplat.draw_context);
		wplat.draw_context = NULL;
	}

	if (destroy)
	{
		DestroyWindow (wplat.mainwindow);
		wplat.mainwindow = NULL;
	}

	ChangeDisplaySettings (NULL, 0);	
}
The hardware gamma stuff annoyed me to death. Now I can sleep at night. :P
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: GL Gamma Correction

Post by Spike »

where's the code to enable anti aliasing?

also, no support for http://www.opengl.org/registry/specs/EX ... l_tear.txt
nor quad-buffered rendering, but I guess drivers fail at that too.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: GL Gamma Correction

Post by revelator »

The hardware gamma stuff annoyed me to death. Now I can sleep at night. :P
Hehe glad i could dig something up that could put your mind at rest :)

Very short platform code :shock: you must have put quite some Work in it to get it that optimized.
Productivity is a state of mind.
Barnes
Posts: 232
Joined: Thu Dec 24, 2009 2:26 pm
Location: Russia, Moscow
Contact:

Re: GL Gamma Correction

Post by Barnes »

Nice feature :)
read.. testing... work very nice :)
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: GL Gamma Correction

Post by Baker »

Spike wrote:where's the code to enable anti aliasing?
Hmmm. I've setup multisample before and for some reason, it wasn't in my "frequently used code". Today, I thought I'd give it another shot and I gave it a shot at making it "elegant". But I can't.

I'm not a fan of the flickering screen deal because you have to "create window/check extensions/use the oddball ARB extra pixel format patchwork bandage/destroy window/create window/set the arb bandage" every time. I like ALT-ENTER to switch between fullscreen and windowed mode, but when I do that, I have to have another flicker-fest to repeat that whole process.

At least to me, it's a bit annoying (I use ALT-ENTER a lot, but maybe that is because I'm constantly engine testing ... I don't really do that during "real" use). I think there is some "hide the window" trick out there, though ...
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: GL Gamma Correction

Post by Spike »

is the pixel format not the same whether its fullscreen or windowed?
either way, if you're changing the pixel format, you need to completely recreate the gl context.

thank god drivers don't have so many window/context-resized bugs nowadays...
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: GL Gamma Correction

Post by Baker »

Spike wrote:is the pixel format not the same whether its fullscreen or windowed?
If you use a 16-bit fullscreen mode and do ALT-ENTER to 32-bit desktop windowed mode. However, perhaps I need to re-evaluate whether or not 16-bit color is relevant in 2013, because it isn't. Perhaps I lose support for bpp switching and you get the desktop bpp no matter what.

I'm still considering some sort of trickery for the double window start-up. You know the stupid "loading Quake" window? :lol: :lol: :lol:

I may resurrect it and give it a new purpose in this world, complete with gl context and secret agent instructions. :D
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: GL Gamma Correction

Post by Spike »

loading screens suck. everyone knows that. thus you should get rid of that extra window. :P

I can load up a timedemo, play through the entire thing, and get back to the console in the time it takes for my lcd monitor to change video mode.
with computers that fast, please tell me what the point of a splashscreen is. :P
indeed, much of the time spent loading is spent reading the exe and dlls and stuff (especially if running in msvc's debugger), all of that happens before your (win)main function is even called.
3-second rule. if it takes 3+ seconds for your window/menu/chimpanze to appear, you need a splashscreen that can appear earlier. otherwise you're just wasting cpu cycles making a window appear then disappear. not to mention really messing with input focus.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: GL Gamma Correction

Post by Baker »

Spike wrote:not to mention really messing with input focus.
re: Starting Quake dialog .... Mine's gone real quick --- although I had removed it. :D

Even now, as I resurrected it to give it "secret agent mission" before it goes away to look at multisample availability and get ARB pdf. Achieved very elegant and fast startup with no awkwardness. Works like charm. Looks polished. No flickering during startup because that little "Starting Quake" window goes away during vid init.

Code: Select all

void VID_Local_Window_PreSetup (void)
{
	WNDCLASS		wc;
	wplat.hIcon = LoadIcon (wplat.hInstance, MAKEINTRESOURCE (IDI_ICON2));


	// Register the frame class
    wc.style         = 0;
    wc.lpfnWndProc   = (WNDPROC)WIN_MainWndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = wplat.hInstance;
    wc.hIcon         = wplat.hIcon;
    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
	wc.hbrBackground = NULL;
    wc.lpszMenuName  = 0;
    wc.lpszClassName = ENGINE_NAME;

    if (!RegisterClass (&wc) )
		Sys_Error ("Couldn't register window class");

	if (wplat.hwnd_dialog)
	{
		if (!COM_CheckParm ("-noms")) // temp for testing, no I would not name a command line parameter that stupidly vague ;-)  Will become read early cvar.
		{
			// Poke into it for the PFD
			HDC	hdc			= GetDC(wplat.hwnd_dialog);
			int unused		= WIN_SetupPixelFormat (hdc);
			HGLRC wglHRC	= wglCreateContext( hdc );
			HDC wglHDC 		= wglGetCurrentDC();
			int unused2		= wglMakeCurrent( hdc, wglHRC);

			// Do it.  We already have desktop properties
			wplat.multisamples = InitMultisample (wplat.hInstance, wplat.hwnd_dialog, wplat.pfd, &wplat.forcePixelFormat);

			// Your mission is complete.  You may leave now ...		
			wglMakeCurrent(NULL, NULL);
			wglDeleteContext(wglHRC);
			ReleaseDC(wplat.hwnd_dialog, wglHDC);
			ReleaseDC(wplat.hwnd_dialog, hdc);

			if (wplat.multisamples)
				Con_Printf ("Enabled: Multisample x %i!\n", wplat.multisamples);
			else Con_Printf ("Could not enable multisample\n");
	
			
		} else Con_Warning ("Multisamples disabled by command line\n");

		// Post teardown
		DestroyWindow (wplat.hwnd_dialog);
		wplat.hwnd_dialog = NULL;
	}
	
}
BUT. My timedemo FPS is about 50% with multisample on. :( Goes from 220 fps to 120 fps for timedemo demo1.

"Multisampling antialiasing can be costly with marginal benefit at high resolution". Ah. Well, I had read an article talking about how great and with minimal implementation for the benefit, but said article didn't really mention the performance cost.

Still --- this was a great coding exercise and should I ever really get into 2D, multisample is virtually required (who wants jaggy lines with lines, etc.)

Good learning experience, will probably keep engine feature as "read early" cvar that requires engine restart on change to take effect to satisfy whoever wants feature --- as it is nice --- and that way I keep the code I spent a couple of hours on.

I already do that with "sndspeed" cvar now (plus my video cvars, plus scr_brightness so startup doesn't look dumb with brightness changing after config.cfg is read).

I'm rather satisfied with the implementation and I'm glad you pushed me a little to do this. :D
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Barnes
Posts: 232
Joined: Thu Dec 24, 2009 2:26 pm
Location: Russia, Moscow
Contact:

Re: GL Gamma Correction

Post by Barnes »

as option - use fxaa or if you have nvidia card - csaa
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: GL Gamma Correction

Post by Baker »

Barnes wrote:as option - use fxaa or if you have nvidia card - csaa
Did homework on these learning what they are. Sounds like 4-5 different ever-improved methodologies emerged. When I start working with shaders, will revisit these.

My lack of knowledge on the anti-aliasing techniques doesn't mean I'm not interested in them, more than I have been dealing with numerous "run-of-the-mill" issues "getting Quake right". But that is coming to a close, other than some of the networking stuff Spike likes to talk about and that I like to listen to.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Post Reply