summaryrefslogtreecommitdiff
path: root/src/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer')
-rw-r--r--src/renderer/tr_backend.c103
-rw-r--r--src/renderer/tr_bsp.c3
-rw-r--r--src/renderer/tr_cmds.c139
-rw-r--r--src/renderer/tr_image.c79
-rw-r--r--src/renderer/tr_init.c45
-rw-r--r--src/renderer/tr_local.h38
-rw-r--r--src/renderer/tr_main.c192
-rw-r--r--src/renderer/tr_model.c70
-rw-r--r--src/renderer/tr_public.h1
-rw-r--r--src/renderer/tr_scene.c2
-rw-r--r--src/renderer/tr_shade.c45
-rw-r--r--src/renderer/tr_shader.c85
-rw-r--r--src/renderer/tr_shadows.c4
-rw-r--r--src/renderer/tr_types.h43
14 files changed, 637 insertions, 212 deletions
diff --git a/src/renderer/tr_backend.c b/src/renderer/tr_backend.c
index 9c9b841a..5eed467a 100644
--- a/src/renderer/tr_backend.c
+++ b/src/renderer/tr_backend.c
@@ -522,7 +522,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
int fogNum, oldFogNum;
int entityNum, oldEntityNum;
int dlighted, oldDlighted;
- qboolean depthRange, oldDepthRange;
+ qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair;
int i;
drawSurf_t *drawSurf;
int oldSort;
@@ -540,6 +540,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
oldShader = NULL;
oldFogNum = -1;
oldDepthRange = qfalse;
+ wasCrosshair = qfalse;
oldDlighted = qfalse;
oldSort = -1;
depthRange = qfalse;
@@ -574,7 +575,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
// change the modelview matrix if needed
//
if ( entityNum != oldEntityNum ) {
- depthRange = qfalse;
+ depthRange = isCrosshair = qfalse;
if ( entityNum != ENTITYNUM_WORLD ) {
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
@@ -591,9 +592,13 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
}
- if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) {
+ if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
+ {
// hack the depth range to prevent view model from poking into walls
depthRange = qtrue;
+
+ if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR)
+ isCrosshair = qtrue;
}
} else {
backEnd.currentEntity = &tr.worldEntity;
@@ -608,15 +613,54 @@ 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 ) {
- qglDepthRange (0, 0.3);
- } else {
+ if (oldDepthRange != depthRange || wasCrosshair != isCrosshair)
+ {
+ if (depthRange)
+ {
+ if(backEnd.viewParms.stereoFrame != STEREO_CENTER)
+ {
+ if(isCrosshair)
+ {
+ if(oldDepthRange)
+ {
+ // was not a crosshair but now is, change back proj matrix
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
+ qglMatrixMode(GL_MODELVIEW);
+ }
+ }
+ else
+ {
+ viewParms_t temp = backEnd.viewParms;
+
+ R_SetupProjection(&temp, r_znear->value, qfalse);
+
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf(temp.projectionMatrix);
+ qglMatrixMode(GL_MODELVIEW);
+ }
+ }
+
+ if(!oldDepthRange)
+ qglDepthRange (0, 0.3);
+ }
+ else
+ {
+ if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER)
+ {
+ qglMatrixMode(GL_PROJECTION);
+ qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
+ qglMatrixMode(GL_MODELVIEW);
+ }
+
qglDepthRange (0, 1);
}
+
oldDepthRange = depthRange;
+ wasCrosshair = isCrosshair;
}
oldEntityNum = entityNum;
@@ -989,6 +1033,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);
+}
/*
=============
@@ -1085,7 +1165,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
diff --git a/src/renderer/tr_bsp.c b/src/renderer/tr_bsp.c
index 2eff8349..1f63f9f0 100644
--- a/src/renderer/tr_bsp.c
+++ b/src/renderer/tr_bsp.c
@@ -1322,6 +1322,9 @@ static void R_LoadSubmodels( lump_t *l ) {
model = R_AllocModel();
assert( model != NULL ); // this should never happen
+ if ( model == NULL ) {
+ ri.Error(ERR_DROP, "R_LoadSubmodels: R_AllocModel() failed");
+ }
model->type = MOD_BRUSH;
model->bmodel = out;
diff --git a/src/renderer/tr_cmds.c b/src/renderer/tr_cmds.c
index 550ce4e8..1b39c56b 100644
--- a/src/renderer/tr_cmds.c
+++ b/src/renderer/tr_cmds.c
@@ -294,6 +294,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] = GL_FALSE;
+ else if(colormode == MODE_RED_GREEN)
+ rgba[2] = GL_FALSE;
+ }
+}
+
/*
====================
@@ -304,7 +336,8 @@ for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
- drawBufferCommand_t *cmd;
+ drawBufferCommand_t *cmd = NULL;
+ colorMaskCommand_t *colcmd = NULL;
if ( !tr.registered ) {
return;
@@ -371,26 +404,22 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
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 ) {
@@ -398,16 +427,78 @@ 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 );
+ }
+ else
+ {
+ if(r_anaglyphMode->integer)
+ {
+ if(r_anaglyphMode->modified)
+ {
+ // clear both, front and backbuffer.
+ qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ 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(r_anaglyphMode->modified)
+ {
+ 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;
}
diff --git a/src/renderer/tr_image.c b/src/renderer/tr_image.c
index 9a0b01fc..a2e92e49 100644
--- a/src/renderer/tr_image.c
+++ b/src/renderer/tr_image.c
@@ -183,6 +183,7 @@ void R_ImageList_f( void ) {
ri.Printf( PRINT_ALL, "RGB8" );
break;
case GL_RGB4_S3TC:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
ri.Printf( PRINT_ALL, "S3TC " );
break;
case GL_RGBA4:
@@ -559,7 +560,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 )
@@ -583,41 +593,68 @@ static void Upload32( unsigned *data,
// select proper internal format
if ( samples == 3 )
{
- if ( glConfig.textureCompression == TC_S3TC )
+ if(r_greyscale->integer)
{
- internalFormat = GL_RGB4_S3TC;
- }
- else if ( r_texturebits->integer == 16 )
- {
- internalFormat = GL_RGB5;
- }
- else if ( r_texturebits->integer == 32 )
- {
- internalFormat = GL_RGB8;
+ if(r_texturebits->integer == 16)
+ internalFormat = GL_LUMINANCE8;
+ else if(r_texturebits->integer == 32)
+ internalFormat = GL_LUMINANCE16;
+ else
+ internalFormat = GL_LUMINANCE;
}
else
{
- internalFormat = 3;
+ if ( glConfig.textureCompression == TC_S3TC_ARB )
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ }
+ else 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 )
- {
- internalFormat = GL_RGBA4;
- }
- else if ( r_texturebits->integer == 32 )
+ if(r_greyscale->integer)
{
- internalFormat = GL_RGBA8;
+ 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
{
- 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 ) ) {
diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c
index 426579d7..685f6fa1 100644
--- a/src/renderer/tr_init.c
+++ b/src/renderer/tr_init.c
@@ -47,11 +47,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;
@@ -90,7 +97,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;
@@ -149,30 +155,6 @@ int max_polys;
cvar_t *r_maxpolyverts;
int max_polyverts;
-static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral )
-{
- if ( shouldBeIntegral )
- {
- if ( ( int ) cv->value != cv->integer )
- {
- ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' must be integral (%f)\n", cv->name, cv->value );
- ri.Cvar_Set( cv->name, va( "%d", cv->integer ) );
- }
- }
-
- if ( cv->value < minVal )
- {
- ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' out of range (%f < %f)\n", cv->name, cv->value, minVal );
- ri.Cvar_Set( cv->name, va( "%f", minVal ) );
- }
- else if ( cv->value > maxVal )
- {
- ri.Printf( PRINT_WARNING, "WARNING: cvar '%s' out of range (%f > %f)\n", cv->name, cv->value, maxVal );
- ri.Cvar_Set( cv->name, va( "%f", maxVal ) );
- }
-}
-
-
#define GENERIC_HW_R_PICMIP_DEFAULT "0"
#define GENERIC_HW_R_TEXTUREMODE_DEFAULT "GL_LINEAR_MIPMAP_LINEAR"
@@ -925,11 +907,10 @@ void R_Register( void )
r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
- AssertCvarRange( r_picmip, 0, 16, qtrue );
+ ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue );
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 );
@@ -943,13 +924,15 @@ 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
//
r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH );
- AssertCvarRange( r_displayRefresh, 0, 200, qtrue );
+ ri.Cvar_CheckRange( r_displayRefresh, 0, 200, qtrue );
r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
@@ -962,7 +945,9 @@ void R_Register( void )
r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE );
r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
r_znear = ri.Cvar_Get( "r_znear", "1", CVAR_CHEAT );
- AssertCvarRange( r_znear, 0.001f, 200, qtrue );
+ ri.Cvar_CheckRange( r_znear, 0.001f, 200, qfalse );
+ r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE );
+ r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", 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 );
@@ -986,6 +971,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
//
diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h
index 76acb15e..b8d89af8 100644
--- a/src/renderer/tr_local.h
+++ b/src/renderer/tr_local.h
@@ -323,10 +323,12 @@ typedef struct {
struct shaderCommands_s;
-#define LIGHTMAP_2D -4 // shader is for 2D rendering
-#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models
-#define LIGHTMAP_WHITEIMAGE -2
-#define LIGHTMAP_NONE -1
+// any change in the LIGHTMAP_* defines here MUST be reflected in
+// R_FindShader() in tr_bsp.c
+#define LIGHTMAP_2D -4 // shader is for 2D rendering
+#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models
+#define LIGHTMAP_WHITEIMAGE -2
+#define LIGHTMAP_NONE -1
typedef enum {
CT_FRONT_SIDED,
@@ -434,6 +436,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
@@ -505,6 +509,7 @@ typedef struct {
cplane_t frustum[4];
vec3_t visBounds[2];
float zFar;
+ stereoFrame_t stereoFrame;
} viewParms_t;
@@ -990,11 +995,12 @@ 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
extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen
-extern cvar_t *r_stereo; // desired pixelformat stereo flag
extern cvar_t *r_texturebits; // number of desired texture bits
// 0 = use framebuffer depth
// 16 = use 16-bit textures
@@ -1085,6 +1091,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;
@@ -1133,6 +1144,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 );
/*
@@ -1611,6 +1623,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,
@@ -1619,7 +1643,9 @@ typedef enum {
RC_DRAW_BUFFER,
RC_SWAP_BUFFERS,
RC_SCREENSHOT,
- RC_VIDEOFRAME
+ RC_VIDEOFRAME,
+ RC_COLORMASK,
+ RC_CLEARDEPTH
} renderCommand_t;
diff --git a/src/renderer/tr_main.c b/src/renderer/tr_main.c
index bbe94236..3d908316 100644
--- a/src/renderer/tr_main.c
+++ b/src/renderer/tr_main.c
@@ -382,7 +382,7 @@ void R_RotateForViewer (void)
/*
** SetFarClip
*/
-static void SetFarClip( void )
+static void R_SetFarClip( void )
{
float farthestCornerDistance = 0;
int i;
@@ -443,97 +443,144 @@ 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 && xmin != -xmax)
+ {
+ // 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 = r_stereoSeparation->value;
- // 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(stereoSep != 0)
+ {
+ 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;
-
- 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[0] = 2 * zProj / width;
+ dest->projectionMatrix[4] = 0;
+ dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
+ dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
+
+ dest->projectionMatrix[1] = 0;
+ dest->projectionMatrix[5] = 2 * zProj / height;
+ dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
+ dest->projectionMatrix[13] = 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;
-
- 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 );
+void R_SetupProjectionZ(viewParms_t *dest)
+{
+ float zNear, zFar, depth;
+
+ zNear = r_znear->value;
+ zFar = dest->zFar;
+ depth = zFar - zNear;
- 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
@@ -1252,7 +1299,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 ();
}
@@ -1337,7 +1389,7 @@ void R_RenderView (viewParms_t *parms) {
// set viewParms.world
R_RotateForViewer ();
- R_SetupFrustum ();
+ R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue);
R_GenerateDrawSurfs();
diff --git a/src/renderer/tr_model.c b/src/renderer/tr_model.c
index 8fdd0adb..b4ca744f 100644
--- a/src/renderer/tr_model.c
+++ b/src/renderer/tr_model.c
@@ -405,13 +405,13 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_
}
+#ifdef RAVENMD4
/*
=================
R_LoadMDR
=================
*/
-#ifdef RAVENMD4
static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
{
int i, j, k, l;
@@ -445,10 +445,10 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
mod->type = MOD_MDR;
- pinmodel->numFrames = LittleLong(pinmodel->numFrames);
- pinmodel->numBones = LittleLong(pinmodel->numBones);
- pinmodel->ofsFrames = LittleLong(pinmodel->ofsFrames);
-
+ LL(pinmodel->numFrames);
+ LL(pinmodel->numBones);
+ LL(pinmodel->ofsFrames);
+
// This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
// over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4.
if(pinmodel->ofsFrames < 0)
@@ -459,6 +459,14 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
}
+ // simple bounds check
+ if(pinmodel->numBones < 0 ||
+ sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return qfalse;
+ }
+
mod->dataSize += size;
mod->md4 = mdr = ri.Hunk_Alloc( size, h_low );
@@ -471,8 +479,8 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
mdr->numBones = pinmodel->numBones;
mdr->numLODs = LittleLong(pinmodel->numLODs);
mdr->numTags = LittleLong(pinmodel->numTags);
- // We don't care about offset values, we'll generate them ourselves while loading.
-
+ // We don't care about the other offset values, we'll generate them ourselves while loading.
+
mod->numLods = mdr->numLODs;
if ( mdr->numFrames < 1 )
@@ -491,7 +499,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
// compressed model...
cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
-
+
for(i = 0; i < mdr->numFrames; i++)
{
for(j = 0; j < 3; j++)
@@ -566,6 +574,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
// swap all the LOD's
for ( l = 0 ; l < mdr->numLODs ; l++)
{
+ // simple bounds check
+ if((byte *) (lod + 1) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return qfalse;
+ }
+
lod->numSurfaces = LittleLong(curlod->numSurfaces);
// swap all the surfaces
@@ -573,7 +588,15 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
- for ( i = 0 ; i < lod->numSurfaces ; i++) {
+ for ( i = 0 ; i < lod->numSurfaces ; i++)
+ {
+ // simple bounds check
+ if((byte *) (surf + 1) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return qfalse;
+ }
+
// first do some copying stuff
surf->ident = SF_MDR;
@@ -617,6 +640,15 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
for(j = 0; j < surf->numVerts; j++)
{
+ LL(curv->numWeights);
+
+ // simple bounds check
+ if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return qfalse;
+ }
+
v->normal[0] = LittleFloat(curv->normal[0]);
v->normal[1] = LittleFloat(curv->normal[1]);
v->normal[2] = LittleFloat(curv->normal[2]);
@@ -624,7 +656,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
v->texCoords[0] = LittleFloat(curv->texCoords[0]);
v->texCoords[1] = LittleFloat(curv->texCoords[1]);
- v->numWeights = LittleLong(curv->numWeights);
+ v->numWeights = curv->numWeights;
weight = &v->weights[0];
curweight = &curv->weights[0];
@@ -651,6 +683,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
+ // simple bounds check
+ if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return qfalse;
+ }
+
for(j = 0; j < surf->numTriangles; j++)
{
tri->indexes[0] = LittleLong(curtri->indexes[0]);
@@ -681,6 +720,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
tag = (mdrTag_t *) lod;
mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
+
+ // simple bounds check
+ if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
+ {
+ ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
+ return qfalse;
+ }
for (i = 0 ; i < mdr->numTags ; i++)
{
@@ -691,7 +737,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
curtag++;
}
- // And finally we know the offset to the end.
+ // And finally we know the real offset to the end.
mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
// phew! we're done.
@@ -876,7 +922,7 @@ void RE_BeginRegistration( glconfig_t *glconfigOut ) {
// NOTE: this sucks, for some reason the first stretch pic is never drawn
// without this we'd see a white flash on a level load because the very
// first time the level shot would not be drawn
- RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0);
+// RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0);
}
//=============================================================================
diff --git a/src/renderer/tr_public.h b/src/renderer/tr_public.h
index e4e4d047..eac2cd29 100644
--- a/src/renderer/tr_public.h
+++ b/src/renderer/tr_public.h
@@ -132,6 +132,7 @@ typedef struct {
cvar_t *(*Cvar_Get)( const char *name, const char *value, int flags );
void (*Cvar_Set)( const char *name, const char *value );
+ void (*Cvar_CheckRange)( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral );
void (*Cmd_AddCommand)( const char *name, void(*cmd)(void) );
void (*Cmd_RemoveCommand)( const char *name );
diff --git a/src/renderer/tr_scene.c b/src/renderer/tr_scene.c
index a45d8f86..82084886 100644
--- a/src/renderer/tr_scene.c
+++ b/src/renderer/tr_scene.c
@@ -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] );
diff --git a/src/renderer/tr_shade.c b/src/renderer/tr_shade.c
index 0214083b..dd8b81bb 100644
--- a/src/renderer/tr_shade.c
+++ b/src/renderer/tr_shade.c
@@ -456,9 +456,19 @@ static void ProjectDlightTexture_altivec( void ) {
radius = dl->radius;
scale = 1.0f / radius;
- floatColor[0] = dl->color[0] * 255.0f;
- floatColor[1] = dl->color[1] * 255.0f;
- floatColor[2] = dl->color[2] * 255.0f;
+ if(r_greyscale->integer)
+ {
+ float luminance;
+
+ luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
+ floatColor[0] = floatColor[1] = floatColor[2] = luminance;
+ }
+ else
+ {
+ floatColor[0] = dl->color[0] * 255.0f;
+ floatColor[1] = dl->color[1] * 255.0f;
+ floatColor[2] = dl->color[2] * 255.0f;
+ }
floatColorVec0 = vec_ld(0, floatColor);
floatColorVec1 = vec_ld(11, floatColor);
floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
@@ -600,9 +610,20 @@ static void ProjectDlightTexture_scalar( void ) {
radius = dl->radius;
scale = 1.0f / radius;
- floatColor[0] = dl->color[0] * 255.0f;
- floatColor[1] = dl->color[1] * 255.0f;
- floatColor[2] = dl->color[2] * 255.0f;
+ if(r_greyscale->integer)
+ {
+ float luminance;
+
+ luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
+ floatColor[0] = floatColor[1] = floatColor[2] = luminance;
+ }
+ else
+ {
+ floatColor[0] = dl->color[0] * 255.0f;
+ floatColor[1] = dl->color[1] * 255.0f;
+ floatColor[2] = dl->color[2] * 255.0f;
+ }
+
for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
int clip = 0;
vec3_t dist;
@@ -939,6 +960,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;
+ }
+ }
}
/*
diff --git a/src/renderer/tr_shader.c b/src/renderer/tr_shader.c
index 499c335a..f3f8a331 100644
--- a/src/renderer/tr_shader.c
+++ b/src/renderer/tr_shader.c
@@ -1433,7 +1433,6 @@ static qboolean ParseShader( char **text )
// stage definition
else if ( token[0] == '{' )
{
- // 20051019 misantropia -- fix buffer overrun.
if ( s >= MAX_SHADER_STAGES ) {
ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s\n", shader.name );
return qfalse;
@@ -2153,7 +2152,7 @@ static shader_t *FinishShader( void ) {
//
// set appropriate stage information
//
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
+ for ( stage = 0; stage < MAX_SHADER_STAGES; ) {
shaderStage_t *pStage = &stages[stage];
if ( !pStage->active ) {
@@ -2164,17 +2163,33 @@ static shader_t *FinishShader( void ) {
if ( !pStage->bundle[0].image[0] ) {
ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
pStage->active = qfalse;
+ stage++;
continue;
}
//
// ditch this stage if it's detail and detail textures are disabled
//
- if ( pStage->isDetail && !r_detailTextures->integer ) {
- if ( stage < ( MAX_SHADER_STAGES - 1 ) ) {
- memmove( pStage, pStage + 1, sizeof( *pStage ) * ( MAX_SHADER_STAGES - stage - 1 ) );
- Com_Memset( pStage + 1, 0, sizeof( *pStage ) );
+ if ( pStage->isDetail && !r_detailTextures->integer )
+ {
+ int index;
+
+ for(index = stage + 1; index < MAX_SHADER_STAGES; index++)
+ {
+ if(!stages[index].active)
+ break;
+ }
+
+ if(index < MAX_SHADER_STAGES)
+ memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage));
+ else
+ {
+ if(stage + 1 < MAX_SHADER_STAGES)
+ memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1));
+
+ Com_Memset(&stages[index - 1], 0, sizeof(*stages));
}
+
continue;
}
@@ -2243,6 +2258,8 @@ static shader_t *FinishShader( void ) {
}
}
}
+
+ stage++;
}
// there are times when you will need to manually apply a sort to
@@ -2430,6 +2447,10 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag
// lightmaps
if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
lightmapIndex = LIGHTMAP_BY_VERTEX;
+ } else if ( lightmapIndex < LIGHTMAP_2D ) {
+ // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
+ ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex );
+ lightmapIndex = LIGHTMAP_BY_VERTEX;
}
COM_StripExtension(name, strippedName, sizeof(strippedName));
@@ -2564,7 +2585,7 @@ qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_
hash = generateHashValue(name, FILE_HASH_SIZE);
- // 20051020 misantropia -- probably not necessary since this function
+ // probably not necessary since this function
// only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D
// but better safe than sorry.
if ( lightmapIndex >= tr.numLightmaps ) {
@@ -2869,7 +2890,7 @@ static void ScanAndLoadShaderFiles( void )
char *oldp, *token, *hashMem;
int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
- long sum = 0;
+ long sum = 0, summand;
// scan for shader files
shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
@@ -2890,10 +2911,38 @@ static void ScanAndLoadShaderFiles( void )
Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
- sum += ri.FS_ReadFile( filename, (void **)&buffers[i] );
- if ( !buffers[i] ) {
+ summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
+
+ if ( !buffers[i] )
ri.Error( ERR_DROP, "Couldn't load %s", filename );
+
+ // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders.
+ p = buffers[i];
+ while(1)
+ {
+ token = COM_ParseExt(&p, qtrue);
+
+ if(!*token)
+ break;
+
+ oldp = p;
+
+ token = COM_ParseExt(&p, qtrue);
+ if(token[0] != '{' && token[1] != '\0')
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: Bad shader file %s has incorrect syntax.\n", filename);
+ ri.FS_FreeFile(buffers[i]);
+ buffers[i] = NULL;
+ break;
+ }
+
+ SkipBracedSection(&oldp);
+ p = oldp;
}
+
+
+ if (buffers[i])
+ sum += summand;
}
// build single large buffer
@@ -2901,12 +2950,16 @@ static void ScanAndLoadShaderFiles( void )
s_shaderText[ 0 ] = '\0';
// free in reverse order, so the temp files are all dumped
- for ( i = numShaderFiles - 1; i >= 0 ; i-- ) {
- p = &s_shaderText[strlen(s_shaderText)];
- strcat( s_shaderText, buffers[i] );
- ri.FS_FreeFile( buffers[i] );
- COM_Compress(p);
- strcat( s_shaderText, "\n" );
+ for ( i = numShaderFiles - 1; i >= 0 ; i-- )
+ {
+ if(buffers[i])
+ {
+ p = &s_shaderText[strlen(s_shaderText)];
+ strcat( s_shaderText, buffers[i] );
+ ri.FS_FreeFile( buffers[i] );
+ COM_Compress(p);
+ strcat( s_shaderText, "\n" );
+ }
}
// free up memory
diff --git a/src/renderer/tr_shadows.c b/src/renderer/tr_shadows.c
index 19d40466..a9f34130 100644
--- a/src/renderer/tr_shadows.c
+++ b/src/renderer/tr_shadows.c
@@ -156,6 +156,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 ) {
@@ -216,6 +217,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 );
@@ -246,7 +248,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]);
}
diff --git a/src/renderer/tr_types.h b/src/renderer/tr_types.h
index a1c338b1..82270b91 100644
--- a/src/renderer/tr_types.h
+++ b/src/renderer/tr_types.h
@@ -25,27 +25,33 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define __TR_TYPES_H
-#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
-#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
+#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
+#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
// renderfx flags
-#define RF_MINLIGHT 1 // allways have some light (viewmodel, some items)
-#define RF_THIRD_PERSON 2 // don't draw through eyes, only mirrors (player bodies, chat sprites)
-#define RF_FIRST_PERSON 4 // only draw through eyes (view weapon, damage blood blob)
-#define RF_DEPTHHACK 8 // for view weapon Z crunching
-#define RF_NOSHADOW 64 // don't add stencil shadows
-
-#define RF_LIGHTING_ORIGIN 128 // use refEntity->lightingOrigin instead of refEntity->origin
- // for lighting. This allows entities to sink into the floor
- // with their origin going solid, and allows all parts of a
- // player to get the same lighting
-#define RF_SHADOW_PLANE 256 // use refEntity->shadowPlane
-#define RF_WRAP_FRAMES 512 // mod the model frames by the maxframes to allow continuous
- // animation without needing to know the frame count
+#define RF_MINLIGHT 0x0001 // allways have some light (viewmodel, some items)
+#define RF_THIRD_PERSON 0x0002 // don't draw through eyes, only mirrors (player bodies, chat sprites)
+#define RF_FIRST_PERSON 0x0004 // only draw through eyes (view weapon, damage blood blob)
+#define RF_DEPTHHACK 0x0008 // for view weapon Z crunching
+
+#define RF_CROSSHAIR 0x0010 // This item is a cross hair and will draw over everything similar to
+ // DEPTHHACK in stereo rendering mode, with the difference that the
+ // projection matrix won't be hacked to reduce the stereo separation as
+ // is done for the gun.
+
+#define RF_NOSHADOW 0x0040 // don't add stencil shadows
+
+#define RF_LIGHTING_ORIGIN 0x0080 // use refEntity->lightingOrigin instead of refEntity->origin
+ // for lighting. This allows entities to sink into the floor
+ // with their origin going solid, and allows all parts of a
+ // player to get the same lighting
+
+#define RF_SHADOW_PLANE 0x0100 // use refEntity->shadowPlane
+#define RF_WRAP_FRAMES 0x0200 // mod the model frames by the maxframes to allow continuous
// refdef flags
-#define RDF_NOWORLDMODEL 1 // used for player configuration screen
-#define RDF_HYPERSPACE 4 // teleportation effect
+#define RDF_NOWORLDMODEL 0x0001 // used for player configuration screen
+#define RDF_HYPERSPACE 0x0004 // teleportation effect
typedef struct {
vec3_t xyz;
@@ -146,7 +152,8 @@ typedef enum {
*/
typedef enum {
TC_NONE,
- TC_S3TC
+ TC_S3TC, // this is for the GL_S3_s3tc extension.
+ TC_S3TC_ARB // this is for the GL_EXT_texture_compression_s3tc extension.
} textureCompression_t;
typedef enum {