r1328 - in trunk: . code/client code/renderer

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Apr 27 13:32:15 EDT 2008


Author: thilo
Date: 2008-04-27 13:32:14 -0400 (Sun, 27 Apr 2008)
New Revision: 1328

Modified:
   trunk/Makefile
   trunk/README
   trunk/code/client/cl_scrn.c
   trunk/code/renderer/tr_backend.c
   trunk/code/renderer/tr_cmds.c
   trunk/code/renderer/tr_image.c
   trunk/code/renderer/tr_init.c
   trunk/code/renderer/tr_local.h
   trunk/code/renderer/tr_main.c
   trunk/code/renderer/tr_scene.c
   trunk/code/renderer/tr_shade.c
   trunk/code/renderer/tr_shadows.c
Log:
- Implement stereo rendering with anaglyph images.
- Add r_greyscale for black&white rendering


Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/Makefile	2008-04-27 17:32:14 UTC (rev 1328)
@@ -155,7 +155,6 @@
 TEMPDIR=/tmp
 
 # extract version info
-# echo $(BUILD_CLIENT)
 
 ifeq ($(BUILD_STANDALONE),1)
   VERSION=$(shell grep "\#define *PRODUCT_VERSION" $(CMDIR)/q_shared.h | head -n 1 | \

Modified: trunk/README
===================================================================
--- trunk/README	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/README	2008-04-27 17:32:14 UTC (rev 1328)
@@ -154,8 +154,22 @@
   net_mcast6addr                    - multicast address to use for scanning for
                                       ipv6 servers on the local network
   net_mcastiface                    - outgoing interface to use for scan
-                                      
 
+  r_zProj                           - distance of observer camera to projection
+                                      plane
+  r_greyscale                       - render black and white images
+  r_anaglyphMode                    - Enable rendering of anaglyph images
+                                      red-cyan glasses:    1
+                                      red-blue:            2
+                                      red-green:           3
+                                      To swap the colors for both sides just
+                                      add 3 to the value for the wanted color
+                                      combination. For red-blue and red-green
+                                      you probably want to enable r_greyscale.
+  r_stereoSeparation                - Control eye separation. Resulting
+                                      separation is r_zProj divided by this
+                                      value.
+
 New commands
   video [filename]        - start video capture (use with demo command)
   stopvideo               - stop video capture

Modified: trunk/code/client/cl_scrn.c
===================================================================
--- trunk/code/client/cl_scrn.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/client/cl_scrn.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -474,7 +474,7 @@
 		case CA_LOADING:
 		case CA_PRIMED:
 			// draw the game information screen and loading progress
-			CL_CGameRendering( stereoFrame );
+			CL_CGameRendering(STEREO_CENTER);
 
 			// also draw the connection information, so it doesn't
 			// flash away too briefly on local or lan games
@@ -483,7 +483,8 @@
 			VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue );
 			break;
 		case CA_ACTIVE:
-			CL_CGameRendering( stereoFrame );
+			// always supply STEREO_CENTER as vieworg offset is now done by the engine.
+			CL_CGameRendering(STEREO_CENTER);
 			SCR_DrawDemoRecording();
 			break;
 		}
@@ -528,7 +529,7 @@
 	if(uivm)
 	{
 		// if running in stereo, we need to draw the frame twice
-		if ( cls.glconfig.stereoEnabled ) {
+		if ( cls.glconfig.stereoEnabled || Cvar_VariableIntegerValue("r_anaglyphMode")) {
 			SCR_DrawScreenField( STEREO_LEFT );
 			SCR_DrawScreenField( STEREO_RIGHT );
 		} else {

Modified: trunk/code/renderer/tr_backend.c
===================================================================
--- trunk/code/renderer/tr_backend.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_backend.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -607,14 +607,38 @@
 			qglLoadMatrixf( backEnd.or.modelMatrix );
 
 			//
-			// change depthrange if needed
+			// change depthrange. Also change projection matrix so first person weapon does not look like coming
+			// out of the screen.
 			//
-			if ( oldDepthRange != depthRange ) {
-				if ( depthRange ) {
+			if (oldDepthRange != depthRange)
+			{
+				if (depthRange)
+				{
+					if(backEnd.viewParms.stereoFrame != STEREO_CENTER)
+					{
+						viewParms_t temp = backEnd.viewParms;
+					
+						R_SetupProjection(&temp, r_znear->value, qfalse);
+
+						qglMatrixMode(GL_PROJECTION);
+						qglLoadMatrixf(temp.projectionMatrix);
+						qglMatrixMode(GL_MODELVIEW);
+					}
+
 					qglDepthRange (0, 0.3);
-				} else {
+				}
+				else
+				{
+					if(backEnd.viewParms.stereoFrame != STEREO_CENTER)
+					{
+						qglMatrixMode(GL_PROJECTION);
+						qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
+						qglMatrixMode(GL_MODELVIEW);
+					}
+
 					qglDepthRange (0, 1);
 				}
+
 				oldDepthRange = depthRange;
 			}
 
@@ -988,9 +1012,45 @@
 
 }
 
+/*
+=============
+RB_ColorMask
 
+=============
+*/
+const void *RB_ColorMask(const void *data)
+{
+	const colorMaskCommand_t *cmd = data;
+	
+	qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]);
+	
+	return (const void *)(cmd + 1);
+}
+
 /*
 =============
+RB_ClearDepth
+
+=============
+*/
+const void *RB_ClearDepth(const void *data)
+{
+	const clearDepthCommand_t *cmd = data;
+	
+	if(tess.numIndexes)
+		RB_EndSurface();
+
+	// texture swapping test
+	if (r_showImages->integer)
+		RB_ShowImages();
+
+	qglClear(GL_DEPTH_BUFFER_BIT);
+	
+	return (const void *)(cmd + 1);
+}
+
+/*
+=============
 RB_SwapBuffers
 
 =============
@@ -1084,7 +1144,12 @@
 		case RC_VIDEOFRAME:
 			data = RB_TakeVideoFrameCmd( data );
 			break;
-
+		case RC_COLORMASK:
+			data = RB_ColorMask(data);
+			break;
+		case RC_CLEARDEPTH:
+			data = RB_ClearDepth(data);
+			break;
 		case RC_END_OF_LIST:
 		default:
 			// stop rendering on this thread

Modified: trunk/code/renderer/tr_cmds.c
===================================================================
--- trunk/code/renderer/tr_cmds.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_cmds.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -91,6 +91,9 @@
 			ri.Printf( PRINT_ALL, "...failed.\n" );
 		}
 	}
+
+	if(r_stereoEnabled->integer)
+		glConfig.stereoEnabled = qtrue;
 }
 
 /*
@@ -293,7 +296,39 @@
 	cmd->t2 = t2;
 }
 
+#define MODE_RED_CYAN	1
+#define MODE_RED_BLUE	2
+#define MODE_RED_GREEN	3
+#define MODE_MAX	MODE_RED_GREEN
 
+void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
+{
+	rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
+	
+	if(colormode > MODE_MAX)
+	{
+		if(stereoFrame == STEREO_LEFT)
+			stereoFrame = STEREO_RIGHT;
+		else if(stereoFrame == STEREO_RIGHT)
+			stereoFrame = STEREO_LEFT;
+		
+		colormode -= MODE_MAX;
+	}
+	
+	if(stereoFrame == STEREO_LEFT)
+		rgba[1] = rgba[2] = GL_FALSE;
+	else if(stereoFrame == STEREO_RIGHT)
+	{
+		rgba[0] = GL_FALSE;
+		
+		if(colormode == MODE_RED_BLUE)
+			rgba[1] = 0;
+		else if(colormode == MODE_RED_GREEN)
+			rgba[2] = 0;
+	}
+}
+
+
 /*
 ====================
 RE_BeginFrame
@@ -303,7 +338,8 @@
 ====================
 */
 void RE_BeginFrame( stereoFrame_t stereoFrame ) {
-	drawBufferCommand_t	*cmd;
+	drawBufferCommand_t	*cmd = NULL;
+	colorMaskCommand_t *colcmd;
 
 	if ( !tr.registered ) {
 		return;
@@ -370,26 +406,22 @@
 		R_SetColorMappings();
 	}
 
-    // check for errors
-    if ( !r_ignoreGLErrors->integer ) {
-        int	err;
+	// check for errors
+	if ( !r_ignoreGLErrors->integer )
+	{
+		int	err;
 
 		R_SyncRenderThread();
-        if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
-            ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err );
-        }
-    }
-
-	//
-	// draw buffer stuff
-	//
-	cmd = R_GetCommandBuffer( sizeof( *cmd ) );
-	if ( !cmd ) {
-		return;
+		if ((err = qglGetError()) != GL_NO_ERROR)
+			ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err);
 	}
-	cmd->commandId = RC_DRAW_BUFFER;
 
-	if ( glConfig.stereoEnabled ) {
+	if (glConfig.stereoEnabled) {
+		if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
+			return;
+			
+		cmd->commandId = RC_DRAW_BUFFER;
+		
 		if ( stereoFrame == STEREO_LEFT ) {
 			cmd->buffer = (int)GL_BACK_LEFT;
 		} else if ( stereoFrame == STEREO_RIGHT ) {
@@ -397,16 +429,79 @@
 		} else {
 			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
 		}
-	} else {
-		if ( stereoFrame != STEREO_CENTER ) {
-			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
+	}
+	else
+	{
+		if(r_anaglyphMode->integer)
+		{
+			if(r_anaglyphMode->modified)
+			{
+				// clear both, front and backbuffer.
+				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+				
+				qglDrawBuffer(GL_FRONT);
+				qglClear(GL_COLOR_BUFFER_BIT);
+				qglDrawBuffer(GL_BACK);
+				qglClear(GL_COLOR_BUFFER_BIT);
+				
+				r_anaglyphMode->modified = qfalse;
+			}
+			
+			if(stereoFrame == STEREO_LEFT)
+			{
+				if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
+					return;
+				
+				if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
+					return;
+			}
+			else if(stereoFrame == STEREO_RIGHT)
+			{
+				clearDepthCommand_t *cldcmd;
+				
+				if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
+					return;
+
+				cldcmd->commandId = RC_CLEARDEPTH;
+
+				if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
+					return;
+			}
+			else
+				ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
+
+			R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
+			colcmd->commandId = RC_COLORMASK;
 		}
-		if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
-			cmd->buffer = (int)GL_FRONT;
-		} else {
-			cmd->buffer = (int)GL_BACK;
+		else
+		{
+			if(stereoFrame != STEREO_CENTER)
+				ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
+
+			if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
+				return;
 		}
+
+		if(cmd)
+		{
+			cmd->commandId = RC_DRAW_BUFFER;
+
+			if(stereoFrame == STEREO_CENTER && r_anaglyphMode->modified)
+			{
+				if(!r_anaglyphMode->integer)
+					qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+				r_anaglyphMode->modified = qfalse;
+			}
+
+			if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
+				cmd->buffer = (int)GL_FRONT;
+			else
+				cmd->buffer = (int)GL_BACK;
+		}
 	}
+	
+	tr.refdef.stereoFrame = stereoFrame;
 }
 
 

Modified: trunk/code/renderer/tr_image.c
===================================================================
--- trunk/code/renderer/tr_image.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_image.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -558,7 +558,16 @@
 	c = width*height;
 	scan = ((byte *)data);
 	samples = 3;
-	if (!lightMap) {
+
+	if(lightMap)
+	{
+		if(r_greyscale->integer)
+			internalFormat = GL_LUMINANCE;
+		else
+			internalFormat = GL_RGB;
+	}
+	else
+	{
 		for ( i = 0; i < c; i++ )
 		{
 			if ( scan[i*4+0] > rMax )
@@ -582,41 +591,64 @@
 		// select proper internal format
 		if ( samples == 3 )
 		{
-			if ( glConfig.textureCompression == TC_S3TC )
+			if(r_greyscale->integer)
 			{
-				internalFormat = GL_RGB4_S3TC;
+				if(r_texturebits->integer == 16)
+					internalFormat = GL_LUMINANCE8;
+				else if(r_texturebits->integer == 32)
+					internalFormat = GL_LUMINANCE16;
+				else
+					internalFormat = GL_LUMINANCE;
 			}
-			else if ( r_texturebits->integer == 16 )
-			{
-				internalFormat = GL_RGB5;
-			}
-			else if ( r_texturebits->integer == 32 )
-			{
-				internalFormat = GL_RGB8;
-			}
 			else
 			{
-				internalFormat = 3;
+				if ( glConfig.textureCompression == TC_S3TC )
+				{
+					internalFormat = GL_RGB4_S3TC;
+				}
+				else if ( r_texturebits->integer == 16 )
+				{
+					internalFormat = GL_RGB5;
+				}
+				else if ( r_texturebits->integer == 32 )
+				{
+					internalFormat = GL_RGB8;
+				}
+				else
+				{
+					internalFormat = GL_RGB;
+				}
 			}
 		}
 		else if ( samples == 4 )
 		{
-			if ( r_texturebits->integer == 16 )
+			if(r_greyscale->integer)
 			{
-				internalFormat = GL_RGBA4;
+				if(r_texturebits->integer == 16)
+					internalFormat = GL_LUMINANCE8_ALPHA8;
+				else if(r_texturebits->integer == 32)
+					internalFormat = GL_LUMINANCE16_ALPHA16;
+				else
+					internalFormat = GL_LUMINANCE_ALPHA;
 			}
-			else if ( r_texturebits->integer == 32 )
-			{
-				internalFormat = GL_RGBA8;
-			}
 			else
 			{
-				internalFormat = 4;
+				if ( r_texturebits->integer == 16 )
+				{
+					internalFormat = GL_RGBA4;
+				}
+				else if ( r_texturebits->integer == 32 )
+				{
+					internalFormat = GL_RGBA8;
+				}
+				else
+				{
+					internalFormat = GL_RGBA;
+				}
 			}
 		}
-	} else {
-		internalFormat = 3;
 	}
+
 	// copy or resample data as appropriate for first MIP level
 	if ( ( scaled_width == width ) && 
 		( scaled_height == height ) ) {

Modified: trunk/code/renderer/tr_init.c
===================================================================
--- trunk/code/renderer/tr_init.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_init.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -50,11 +50,18 @@
 cvar_t	*r_detailTextures;
 
 cvar_t	*r_znear;
+cvar_t	*r_zproj;
+cvar_t	*r_stereoSeparation;
 
 cvar_t	*r_smp;
 cvar_t	*r_showSmp;
 cvar_t	*r_skipBackEnd;
 
+cvar_t	*r_stereoEnabled;
+cvar_t	*r_anaglyphMode;
+
+cvar_t	*r_greyscale;
+
 cvar_t	*r_ignorehwgamma;
 cvar_t	*r_measureOverdraw;
 
@@ -93,7 +100,6 @@
 cvar_t	*r_stencilbits;
 cvar_t	*r_depthbits;
 cvar_t	*r_colorbits;
-cvar_t	*r_stereo;
 cvar_t	*r_primitives;
 cvar_t	*r_texturebits;
 
@@ -916,7 +922,6 @@
 	r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
 	r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
-	r_stereo = ri.Cvar_Get( "r_stereo", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
 	r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
@@ -931,7 +936,9 @@
 	r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0);
 	r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH);
 	r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_ARCHIVE | CVAR_LATCH);
+	r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH);
 	r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH );
+	r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH);
 
 	//
 	// temporary latched variables that can only change over a restart
@@ -951,6 +958,8 @@
 	r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
 	r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT );
 	AssertCvarRange( r_znear, 0.001f, 200, qtrue );
+	r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE );
+	r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "32", CVAR_ARCHIVE );
 	r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
 	r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
 	r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
@@ -973,6 +982,8 @@
 	r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT );
 	r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
 
+	r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE);
+
 	//
 	// temporary variables that can change at any time
 	//

Modified: trunk/code/renderer/tr_local.h
===================================================================
--- trunk/code/renderer/tr_local.h	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_local.h	2008-04-27 17:32:14 UTC (rev 1328)
@@ -433,6 +433,8 @@
 	vec3_t		vieworg;
 	vec3_t		viewaxis[3];		// transformation matrix
 
+	stereoFrame_t	stereoFrame;
+
 	int			time;				// time in milliseconds for shader effects and other time dependent rendering issues
 	int			rdflags;			// RDF_NOWORLDMODEL, etc
 
@@ -504,6 +506,7 @@
 	cplane_t	frustum[4];
 	vec3_t		visBounds[2];
 	float		zFar;
+	stereoFrame_t	stereoFrame;
 } viewParms_t;
 
 
@@ -996,6 +999,8 @@
 extern cvar_t	*r_ignoreFastPath;		// allows us to ignore our Tess fast paths
 
 extern cvar_t	*r_znear;				// near Z clip plane
+extern cvar_t	*r_zproj;				// z distance of projection plane
+extern cvar_t	*r_stereoSeparation;			// separation of cameras for stereo rendering
 
 extern cvar_t	*r_stencilbits;			// number of desired stencil bits
 extern cvar_t	*r_depthbits;			// number of desired depth bits
@@ -1088,6 +1093,11 @@
 extern	cvar_t	*r_showSmp;
 extern	cvar_t	*r_skipBackEnd;
 
+extern	cvar_t	*r_stereoEnabled;
+extern	cvar_t	*r_anaglyphMode;
+
+extern	cvar_t	*r_greyscale;
+
 extern	cvar_t	*r_ignoreGLErrors;
 
 extern	cvar_t	*r_overBrightBits;
@@ -1136,6 +1146,7 @@
 int R_CullPointAndRadius( vec3_t origin, float radius );
 int R_CullLocalPointAndRadius( vec3_t origin, float radius );
 
+void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum);
 void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or );
 
 /*
@@ -1614,6 +1625,18 @@
 	qboolean			motionJpeg;
 } videoFrameCommand_t;
 
+typedef struct
+{
+	int commandId;
+
+	GLboolean rgba[4];
+} colorMaskCommand_t;
+
+typedef struct
+{
+	int commandId;
+} clearDepthCommand_t;
+
 typedef enum {
 	RC_END_OF_LIST,
 	RC_SET_COLOR,
@@ -1622,7 +1645,9 @@
 	RC_DRAW_BUFFER,
 	RC_SWAP_BUFFERS,
 	RC_SCREENSHOT,
-	RC_VIDEOFRAME
+	RC_VIDEOFRAME,
+	RC_COLORMASK,
+	RC_CLEARDEPTH
 } renderCommand_t;
 
 

Modified: trunk/code/renderer/tr_main.c
===================================================================
--- trunk/code/renderer/tr_main.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_main.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -381,7 +381,7 @@
 /*
 ** SetFarClip
 */
-static void SetFarClip( void )
+static void R_SetFarClip( void )
 {
 	float	farthestCornerDistance = 0;
 	int		i;
@@ -442,97 +442,141 @@
 	tr.viewParms.zFar = sqrt( farthestCornerDistance );
 }
 
+/*
+=================
+R_SetupFrustum
 
+Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
+the projection matrix.
+=================
+*/
+void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep)
+{
+	vec3_t ofsorigin;
+	float oppleg, adjleg, length;
+	int i;
+	
+	if(stereoSep == 0)
+	{
+		// symmetric case can be simplified
+		VectorCopy(dest->or.origin, ofsorigin);
+
+		length = sqrt(xmax * xmax + zProj * zProj);
+		oppleg = xmax / length;
+		adjleg = zProj / length;
+
+		VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal);
+		VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal);
+
+		VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal);
+		VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal);
+	}
+	else
+	{
+		// In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the
+		// actual origin that we're rendering so offset the tip of the view pyramid.
+		VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin);
+	
+		oppleg = xmax + stereoSep;
+		length = sqrt(oppleg * oppleg + zProj * zProj);
+		VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal);
+		VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal);
+
+		oppleg = xmin + stereoSep;
+		length = sqrt(oppleg * oppleg + zProj * zProj);
+		VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal);
+		VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal);
+	}
+
+	length = sqrt(ymax * ymax + zProj * zProj);
+	oppleg = ymax / length;
+	adjleg = zProj / length;
+
+	VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal);
+	VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal);
+
+	VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal);
+	VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal);
+	
+	for (i=0 ; i<4 ; i++) {
+		dest->frustum[i].type = PLANE_NON_AXIAL;
+		dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal);
+		SetPlaneSignbits( &dest->frustum[i] );
+	}
+}
+
 /*
 ===============
 R_SetupProjection
 ===============
 */
-void R_SetupProjection( void ) {
+void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum)
+{
 	float	xmin, xmax, ymin, ymax;
-	float	width, height, depth;
-	float	zNear, zFar;
+	float	width, height, stereoSep;
 
-	// dynamically compute far clip plane distance
-	SetFarClip();
+	/*
+	 * offset the view origin of the viewer for stereo rendering 
+	 * by setting the projection matrix appropriately.
+	 */
+	 
+	if(dest->stereoFrame == STEREO_LEFT)
+		stereoSep = zProj / r_stereoSeparation->value;
+	else if(dest->stereoFrame == STEREO_RIGHT)
+		stereoSep = zProj / -r_stereoSeparation->value;
+	else
+		stereoSep = 0;
 
-	//
-	// set up projection matrix
-	//
-	zNear	= r_znear->value;
-	zFar	= tr.viewParms.zFar;
-
-	ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
+	ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
 	ymin = -ymax;
 
-	xmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );
+	xmax = zProj * tan(dest->fovX * M_PI / 360.0f);
 	xmin = -xmax;
 
 	width = xmax - xmin;
 	height = ymax - ymin;
-	depth = zFar - zNear;
+	
+	dest->projectionMatrix[0] = 2 * zProj / width;
+	dest->projectionMatrix[4] = 0;
+	dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
+	dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
 
-	tr.viewParms.projectionMatrix[0] = 2 * zNear / width;
-	tr.viewParms.projectionMatrix[4] = 0;
-	tr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width;	// normally 0
-	tr.viewParms.projectionMatrix[12] = 0;
+	dest->projectionMatrix[1] = 0;
+	dest->projectionMatrix[5] = 2 * zProj / height;
+	dest->projectionMatrix[9] = ( ymax + ymin ) / height;	// normally 0
+	dest->projectionMatrix[13] = 0;
 
-	tr.viewParms.projectionMatrix[1] = 0;
-	tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
-	tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height;	// normally 0
-	tr.viewParms.projectionMatrix[13] = 0;
-
-	tr.viewParms.projectionMatrix[2] = 0;
-	tr.viewParms.projectionMatrix[6] = 0;
-	tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;
-	tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;
-
-	tr.viewParms.projectionMatrix[3] = 0;
-	tr.viewParms.projectionMatrix[7] = 0;
-	tr.viewParms.projectionMatrix[11] = -1;
-	tr.viewParms.projectionMatrix[15] = 0;
+	dest->projectionMatrix[3] = 0;
+	dest->projectionMatrix[7] = 0;
+	dest->projectionMatrix[11] = -1;
+	dest->projectionMatrix[15] = 0;
+	
+	// Now that we have all the data for the projection matrix we can also setup the view frustum.
+	if(computeFrustum)
+		R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep);
 }
 
 /*
-=================
-R_SetupFrustum
+===============
+R_SetupProjectionZ
 
-Setup that culling frustum planes for the current view
-=================
+Sets the z-component transformation part in the projection matrix
+===============
 */
-void R_SetupFrustum (void) {
-	int		i;
-	float	xs, xc;
-	float	ang;
+void R_SetupProjectionZ(viewParms_t *dest)
+{
+	float zNear, zFar, depth;
+	
+	zNear	= r_znear->value;
+	zFar	= dest->zFar;	
+	depth	= zFar - zNear;
 
-	ang = tr.viewParms.fovX / 180 * M_PI * 0.5f;
-	xs = sin( ang );
-	xc = cos( ang );
-
-	VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[0].normal );
-	VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[0].normal );
-
-	VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[1].normal );
-	VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[1].normal );
-
-	ang = tr.viewParms.fovY / 180 * M_PI * 0.5f;
-	xs = sin( ang );
-	xc = cos( ang );
-
-	VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[2].normal );
-	VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[2].normal );
-
-	VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[3].normal );
-	VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[3].normal );
-
-	for (i=0 ; i<4 ; i++) {
-		tr.viewParms.frustum[i].type = PLANE_NON_AXIAL;
-		tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.or.origin, tr.viewParms.frustum[i].normal);
-		SetPlaneSignbits( &tr.viewParms.frustum[i] );
-	}
+	dest->projectionMatrix[2] = 0;
+	dest->projectionMatrix[6] = 0;
+	dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
+	dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
 }
 
-
 /*
 =================
 R_MirrorPoint
@@ -1251,8 +1295,13 @@
 	// this needs to be done before entities are
 	// added, because they use the projection
 	// matrix for lod calculation
-	R_SetupProjection ();
 
+	// dynamically compute far clip plane distance
+	R_SetFarClip();
+
+	// we know the size of the clipping volume. Now set the rest of the projection matrix.
+	R_SetupProjectionZ (&tr.viewParms);
+
 	R_AddEntitySurfaces ();
 }
 
@@ -1336,7 +1385,7 @@
 	// set viewParms.world
 	R_RotateForViewer ();
 
-	R_SetupFrustum ();
+	R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue);
 
 	R_GenerateDrawSurfs();
 

Modified: trunk/code/renderer/tr_scene.c
===================================================================
--- trunk/code/renderer/tr_scene.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_scene.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -389,6 +389,8 @@
 
 	parms.fovX = tr.refdef.fov_x;
 	parms.fovY = tr.refdef.fov_y;
+	
+	parms.stereoFrame = tr.refdef.stereoFrame;
 
 	VectorCopy( fd->vieworg, parms.or.origin );
 	VectorCopy( fd->viewaxis[0], parms.or.axis[0] );

Modified: trunk/code/renderer/tr_shade.c
===================================================================
--- trunk/code/renderer/tr_shade.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_shade.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -938,6 +938,18 @@
 			break;
 		}
 	}
+	
+	// if in greyscale rendering mode turn all color values into greyscale.
+	if(r_greyscale->integer)
+	{
+		int scale;
+		
+		for(i = 0; i < tess.numVertexes; i++)
+		{
+			scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3;
+			tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale;
+		}
+	}
 }
 
 /*

Modified: trunk/code/renderer/tr_shadows.c
===================================================================
--- trunk/code/renderer/tr_shadows.c	2008-04-23 20:59:12 UTC (rev 1327)
+++ trunk/code/renderer/tr_shadows.c	2008-04-27 17:32:14 UTC (rev 1328)
@@ -155,6 +155,7 @@
 	int		i;
 	int		numTris;
 	vec3_t	lightDir;
+	GLboolean rgba[4];
 
 	// we can only do this if we have enough space in the vertex buffers
 	if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
@@ -215,6 +216,7 @@
 	qglColor3f( 0.2f, 0.2f, 0.2f );
 
 	// don't write to the color buffer
+	qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
 	qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
 
 	qglEnable( GL_STENCIL_TEST );
@@ -245,7 +247,7 @@
 
 
 	// reenable writing to the color buffer
-	qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
+	qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
 }
 
 




More information about the quake3-commits mailing list