mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2024-12-13 13:40:56 +00:00
- Implement stereo rendering with anaglyph images.
- Add r_greyscale for black&white rendering
This commit is contained in:
parent
48d9999698
commit
425c351d1b
12 changed files with 435 additions and 128 deletions
1
Makefile
1
Makefile
|
@ -155,7 +155,6 @@ LIBSDIR=$(MOUNT_DIR)/libs
|
|||
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 | \
|
||||
|
|
14
README
14
README
|
@ -155,6 +155,20 @@ New cvars
|
|||
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)
|
||||
|
|
|
@ -474,7 +474,7 @@ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
|
|||
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 @@ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
|
|||
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 @@ void SCR_UpdateScreen( void ) {
|
|||
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 {
|
||||
|
|
|
@ -607,14 +607,38 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
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,6 +1012,42 @@ void RB_ShowImages( void ) {
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
|
@ -1084,7 +1144,12 @@ void RB_ExecuteRenderCommands( const void *data ) {
|
|||
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
|
||||
|
|
|
@ -91,6 +91,9 @@ void R_InitCommandBuffers( void ) {
|
|||
ri.Printf( PRINT_ALL, "...failed.\n" );
|
||||
}
|
||||
}
|
||||
|
||||
if(r_stereoEnabled->integer)
|
||||
glConfig.stereoEnabled = qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -293,6 +296,38 @@ void RE_StretchPic ( float x, float y, float w, float h,
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
|
@ -303,7 +338,8 @@ for each RE_EndFrame
|
|||
====================
|
||||
*/
|
||||
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
||||
drawBufferCommand_t *cmd;
|
||||
drawBufferCommand_t *cmd = NULL;
|
||||
colorMaskCommand_t *colcmd;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
|
@ -371,25 +407,21 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
|||
}
|
||||
|
||||
// check for errors
|
||||
if ( !r_ignoreGLErrors->integer ) {
|
||||
if ( !r_ignoreGLErrors->integer )
|
||||
{
|
||||
int err;
|
||||
|
||||
R_SyncRenderThread();
|
||||
if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
|
||||
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;
|
||||
}
|
||||
cmd->commandId = RC_DRAW_BUFFER;
|
||||
|
||||
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 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
|||
} 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 );
|
||||
}
|
||||
if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
else
|
||||
cmd->buffer = (int)GL_BACK;
|
||||
}
|
||||
}
|
||||
|
||||
tr.refdef.stereoFrame = stereoFrame;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -558,7 +558,16 @@ static void Upload32( unsigned *data,
|
|||
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 )
|
||||
|
@ -581,6 +590,17 @@ static void Upload32( unsigned *data,
|
|||
}
|
||||
// select proper internal format
|
||||
if ( samples == 3 )
|
||||
{
|
||||
if(r_greyscale->integer)
|
||||
{
|
||||
if(r_texturebits->integer == 16)
|
||||
internalFormat = GL_LUMINANCE8;
|
||||
else if(r_texturebits->integer == 32)
|
||||
internalFormat = GL_LUMINANCE16;
|
||||
else
|
||||
internalFormat = GL_LUMINANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( glConfig.textureCompression == TC_S3TC )
|
||||
{
|
||||
|
@ -596,10 +616,22 @@ static void Upload32( unsigned *data,
|
|||
}
|
||||
else
|
||||
{
|
||||
internalFormat = 3;
|
||||
internalFormat = GL_RGB;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( samples == 4 )
|
||||
{
|
||||
if(r_greyscale->integer)
|
||||
{
|
||||
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 == 16 )
|
||||
{
|
||||
|
@ -611,12 +643,12 @@ static void Upload32( unsigned *data,
|
|||
}
|
||||
else
|
||||
{
|
||||
internalFormat = 4;
|
||||
internalFormat = GL_RGBA;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
internalFormat = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// copy or resample data as appropriate for first MIP level
|
||||
if ( ( scaled_width == width ) &&
|
||||
( scaled_height == height ) ) {
|
||||
|
|
|
@ -50,11 +50,18 @@ cvar_t *r_displayRefresh;
|
|||
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_logFile;
|
|||
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 @@ void R_Register( void )
|
|||
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 @@ void R_Register( void )
|
|||
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 @@ void R_Register( void )
|
|||
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 @@ void R_Register( void )
|
|||
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
|
||||
//
|
||||
|
|
|
@ -433,6 +433,8 @@ typedef struct {
|
|||
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 @@ typedef struct {
|
|||
cplane_t frustum[4];
|
||||
vec3_t visBounds[2];
|
||||
float zFar;
|
||||
stereoFrame_t stereoFrame;
|
||||
} viewParms_t;
|
||||
|
||||
|
||||
|
@ -996,6 +999,8 @@ extern cvar_t *r_verbose; // used for verbose debug spew
|
|||
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_smp;
|
|||
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_CullLocalBox (vec3_t bounds[2]);
|
|||
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 @@ typedef struct {
|
|||
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 @@ typedef enum {
|
|||
RC_DRAW_BUFFER,
|
||||
RC_SWAP_BUFFERS,
|
||||
RC_SCREENSHOT,
|
||||
RC_VIDEOFRAME
|
||||
RC_VIDEOFRAME,
|
||||
RC_COLORMASK,
|
||||
RC_CLEARDEPTH
|
||||
} renderCommand_t;
|
||||
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ void R_RotateForViewer (void)
|
|||
/*
|
||||
** SetFarClip
|
||||
*/
|
||||
static void SetFarClip( void )
|
||||
static void R_SetFarClip( void )
|
||||
{
|
||||
float farthestCornerDistance = 0;
|
||||
int i;
|
||||
|
@ -442,96 +442,140 @@ static void SetFarClip( void )
|
|||
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.
|
||||
*/
|
||||
|
||||
//
|
||||
// set up projection matrix
|
||||
//
|
||||
zNear = r_znear->value;
|
||||
zFar = tr.viewParms.zFar;
|
||||
if(dest->stereoFrame == STEREO_LEFT)
|
||||
stereoSep = zProj / r_stereoSeparation->value;
|
||||
else if(dest->stereoFrame == STEREO_RIGHT)
|
||||
stereoSep = zProj / -r_stereoSeparation->value;
|
||||
else
|
||||
stereoSep = 0;
|
||||
|
||||
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;
|
||||
|
||||
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[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[1] = 0;
|
||||
tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
|
||||
tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
|
||||
tr.viewParms.projectionMatrix[13] = 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[2] = 0;
|
||||
tr.viewParms.projectionMatrix[6] = 0;
|
||||
tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;
|
||||
tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;
|
||||
dest->projectionMatrix[3] = 0;
|
||||
dest->projectionMatrix[7] = 0;
|
||||
dest->projectionMatrix[11] = -1;
|
||||
dest->projectionMatrix[15] = 0;
|
||||
|
||||
tr.viewParms.projectionMatrix[3] = 0;
|
||||
tr.viewParms.projectionMatrix[7] = 0;
|
||||
tr.viewParms.projectionMatrix[11] = -1;
|
||||
tr.viewParms.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;
|
||||
|
||||
ang = tr.viewParms.fovX / 180 * M_PI * 0.5f;
|
||||
xs = sin( ang );
|
||||
xc = cos( ang );
|
||||
zNear = r_znear->value;
|
||||
zFar = dest->zFar;
|
||||
depth = zFar - zNear;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
|
@ -1251,7 +1295,12 @@ void R_GenerateDrawSurfs( void ) {
|
|||
// 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 @@ void R_RenderView (viewParms_t *parms) {
|
|||
// set viewParms.world
|
||||
R_RotateForViewer ();
|
||||
|
||||
R_SetupFrustum ();
|
||||
R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue);
|
||||
|
||||
R_GenerateDrawSurfs();
|
||||
|
||||
|
|
|
@ -390,6 +390,8 @@ void RE_RenderScene( const refdef_t *fd ) {
|
|||
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] );
|
||||
VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
|
||||
|
|
|
@ -938,6 +938,18 @@ static void ComputeColors( shaderStage_t *pStage )
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -155,6 +155,7 @@ void RB_ShadowTessEnd( void ) {
|
|||
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 @@ void RB_ShadowTessEnd( void ) {
|
|||
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 @@ void RB_ShadowTessEnd( void ) {
|
|||
|
||||
|
||||
// reenable writing to the color buffer
|
||||
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
|
||||
qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue