diff --git a/code/cgame/cg_draw.c b/code/cgame/cg_draw.c index a525e5c3..7fe0558c 100644 --- a/code/cgame/cg_draw.c +++ b/code/cgame/cg_draw.c @@ -1861,7 +1861,8 @@ CROSSHAIR CG_DrawCrosshair ================= */ -static void CG_DrawCrosshair(void) { +static void CG_DrawCrosshair(void) +{ float w, h; qhandle_t hShader; float f; @@ -1915,6 +1916,82 @@ static void CG_DrawCrosshair(void) { w, h, 0, 0, 1, 1, hShader ); } +/* +================= +CG_DrawCrosshair3D +================= +*/ +static void CG_DrawCrosshair3D(void) +{ + float w, h; + qhandle_t hShader; + float f; + int ca; + + trace_t trace; + vec3_t endpos; + float stereoSep, zProj, maxdist, xmax; + char rendererinfos[128]; + refEntity_t ent; + + if ( !cg_drawCrosshair.integer ) { + return; + } + + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) { + return; + } + + if ( cg.renderingThirdPerson ) { + return; + } + + w = h = cg_crosshairSize.value; + + // pulse the size of the crosshair when picking up items + f = cg.time - cg.itemPickupBlendTime; + if ( f > 0 && f < ITEM_BLOB_TIME ) { + f /= ITEM_BLOB_TIME; + w *= ( 1 + f ); + h *= ( 1 + f ); + } + + ca = cg_drawCrosshair.integer; + if (ca < 0) { + ca = 0; + } + hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ]; + + // Use a different method rendering the crosshair so players don't see two of them when + // focusing their eyes at distant objects with high stereo separation + // We are going to trace to the next shootable object and place the crosshair in front of it. + + // first get all the important renderer information + trap_Cvar_VariableStringBuffer("r_zProj", rendererinfos, sizeof(rendererinfos)); + zProj = atof(rendererinfos); + trap_Cvar_VariableStringBuffer("r_stereoSeparation", rendererinfos, sizeof(rendererinfos)); + stereoSep = zProj / atof(rendererinfos); + + xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f); + + // let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel. + maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax); + VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos); + CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT); + + memset(&ent, 0, sizeof(ent)); + ent.reType = RT_SPRITE; + ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR; + + VectorCopy(trace.endpos, ent.origin); + + // scale the crosshair so it appears the same size for all distances + ent.radius = w / 640 * xmax * trace.fraction * maxdist / zProj; + ent.customShader = hShader; + + trap_R_AddRefEntityToScene(&ent); +} + /* @@ -2439,7 +2516,8 @@ void CG_DrawTimedMenus( void ) { CG_Draw2D ================= */ -static void CG_Draw2D( void ) { +static void CG_Draw2D(stereoFrame_t stereoFrame) +{ #ifdef MISSIONPACK if (cgs.orderPending && cg.time > cgs.orderTime) { CG_CheckOrderPending(); @@ -2466,7 +2544,10 @@ static void CG_Draw2D( void ) { */ if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) { CG_DrawSpectator(); - CG_DrawCrosshair(); + + if(stereoFrame == STEREO_CENTER) + CG_DrawCrosshair(); + CG_DrawCrosshairNames(); } else { // don't draw any status if dead or the scoreboard is being explicitly shown @@ -2486,7 +2567,8 @@ static void CG_Draw2D( void ) { #ifdef MISSIONPACK CG_DrawProxWarning(); #endif - CG_DrawCrosshair(); + if(stereoFrame == STEREO_CENTER) + CG_DrawCrosshair(); CG_DrawCrosshairNames(); CG_DrawWeaponSelect(); @@ -2550,9 +2632,6 @@ Perform all drawing needed to completely fill the screen ===================== */ void CG_DrawActive( stereoFrame_t stereoView ) { - float separation; - vec3_t baseOrg; - // optionally draw the info screen instead if ( !cg.snap ) { CG_DrawInformation(); @@ -2566,41 +2645,17 @@ void CG_DrawActive( stereoFrame_t stereoView ) { return; } - switch ( stereoView ) { - case STEREO_CENTER: - separation = 0; - break; - case STEREO_LEFT: - separation = -cg_stereoSeparation.value / 2; - break; - case STEREO_RIGHT: - separation = cg_stereoSeparation.value / 2; - break; - default: - separation = 0; - CG_Error( "CG_DrawActive: Undefined stereoView" ); - } - - // clear around the rendered view if sized down CG_TileClear(); - // offset vieworg appropriately if we're doing stereo separation - VectorCopy( cg.refdef.vieworg, baseOrg ); - if ( separation != 0 ) { - VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg ); - } + if(stereoView != STEREO_CENTER) + CG_DrawCrosshair3D(); // draw 3D view trap_R_RenderScene( &cg.refdef ); - // restore original viewpoint if running stereo - if ( separation != 0 ) { - VectorCopy( baseOrg, cg.refdef.vieworg ); - } - // draw status bar and other floating elements - CG_Draw2D(); + CG_Draw2D(stereoView); } diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 71598a6a..d000916d 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -1134,7 +1134,6 @@ extern vmCvar_t cg_zoomFov; extern vmCvar_t cg_thirdPersonRange; extern vmCvar_t cg_thirdPersonAngle; extern vmCvar_t cg_thirdPerson; -extern vmCvar_t cg_stereoSeparation; extern vmCvar_t cg_lagometer; extern vmCvar_t cg_drawAttacker; extern vmCvar_t cg_synchronousClients; @@ -1288,7 +1287,7 @@ void CG_InitTeamChat( void ); void CG_GetTeamColor(vec4_t *color); const char *CG_GetGameStatusText( void ); const char *CG_GetKillerText( void ); -void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ); +void CG_Draw3DModel(float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles); void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader); void CG_CheckOrderPending( void ); const char *CG_GameTypeString( void ); diff --git a/code/cgame/cg_main.c b/code/cgame/cg_main.c index 15f4db53..15a5539b 100644 --- a/code/cgame/cg_main.c +++ b/code/cgame/cg_main.c @@ -142,7 +142,6 @@ vmCvar_t cg_zoomFov; vmCvar_t cg_thirdPerson; vmCvar_t cg_thirdPersonRange; vmCvar_t cg_thirdPersonAngle; -vmCvar_t cg_stereoSeparation; vmCvar_t cg_lagometer; vmCvar_t cg_drawAttacker; vmCvar_t cg_synchronousClients; @@ -211,7 +210,6 @@ static cvarTable_t cvarTable[] = { { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE }, { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE }, { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE }, - { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE }, { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE }, { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE }, { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE }, diff --git a/code/client/cl_main.c b/code/client/cl_main.c index ef50e0ba..d130620a 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -2743,6 +2743,8 @@ void CL_Init( void ) { // cgame might not be initialized before menu is used Cvar_Get ("cg_viewsize", "100", CVAR_ARCHIVE ); + // Make sure cg_stereoSeparation is zero as that variable is deprecated and should not be used anymore. + Cvar_Get ("cg_stereoSeparation", "0", CVAR_ROM); // // register our commands diff --git a/code/client/cl_scrn.c b/code/client/cl_scrn.c index 3172f3da..fd4c38b5 100644 --- a/code/client/cl_scrn.c +++ b/code/client/cl_scrn.c @@ -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(STEREO_CENTER); + CL_CGameRendering(stereoFrame); // also draw the connection information, so it doesn't // flash away too briefly on local or lan games @@ -484,7 +484,7 @@ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) { break; case CA_ACTIVE: // always supply STEREO_CENTER as vieworg offset is now done by the engine. - CL_CGameRendering(STEREO_CENTER); + CL_CGameRendering(stereoFrame); SCR_DrawDemoRecording(); break; } diff --git a/code/qcommon/cvar.c b/code/qcommon/cvar.c index 9dfff2e1..2526e389 100644 --- a/code/qcommon/cvar.c +++ b/code/qcommon/cvar.c @@ -228,6 +228,17 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { Z_Free( var->resetString ); var->resetString = CopyString( var_value ); + if(flags & CVAR_ROM) + { + // this variable was set by the user, + // so force it to value given by the engine. + + if(var->latchedString) + Z_Free(var->latchedString); + + var->latchedString = CopyString(var_value); + } + // ZOID--needs to be set so that cvars the game sets as // SERVERINFO get sent to clients cvar_modifiedFlags |= flags; @@ -239,16 +250,6 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { // we don't have a reset string yet Z_Free( var->resetString ); var->resetString = CopyString( var_value ); - - // if there is no reset string yet this means the variable was set by the user, - // so force it to value given by the engine. - if(var->flags & CVAR_ROM) - { - if(var->latchedString) - Z_Free(var->latchedString); - - var->latchedString = CopyString(var_value); - } } else if ( var_value[0] && strcmp( var->resetString, var_value ) ) { Com_DPrintf( "Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n", var_name, var->resetString, var_value ); diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 904c7d44..15e32c5c 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -521,7 +521,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; @@ -539,6 +539,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; + wasCrosshair = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; @@ -573,7 +574,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]; @@ -590,9 +591,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; @@ -610,26 +615,40 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // - if (oldDepthRange != depthRange) + if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { - viewParms_t temp = backEnd.viewParms; - - R_SetupProjection(&temp, r_znear->value, qfalse); + 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; - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(temp.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); + R_SetupProjection(&temp, r_znear->value, qfalse); + + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf(temp.projectionMatrix); + qglMatrixMode(GL_MODELVIEW); + } } - qglDepthRange (0, 0.3); + if(!oldDepthRange) + qglDepthRange (0, 0.3); } else { - if(backEnd.viewParms.stereoFrame != STEREO_CENTER) + if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); @@ -640,6 +659,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } oldDepthRange = depthRange; + wasCrosshair = isCrosshair; } oldEntityNum = entityNum; diff --git a/code/renderer/tr_cmds.c b/code/renderer/tr_cmds.c index 06a18e80..d5069863 100644 --- a/code/renderer/tr_cmds.c +++ b/code/renderer/tr_cmds.c @@ -319,9 +319,9 @@ void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode) rgba[0] = GL_FALSE; if(colormode == MODE_RED_BLUE) - rgba[1] = 0; + rgba[1] = GL_FALSE; else if(colormode == MODE_RED_GREEN) - rgba[2] = 0; + rgba[2] = GL_FALSE; } } diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index c5996bae..feda1051 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -456,7 +456,7 @@ void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, floa float oppleg, adjleg, length; int i; - if(stereoSep == 0) + if(stereoSep == 0 && xmin != -xmax) { // symmetric case can be simplified VectorCopy(dest->or.origin, ofsorigin); @@ -513,19 +513,22 @@ R_SetupProjection void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) { float xmin, xmax, ymin, ymax; - float width, height, stereoSep; + float width, height, stereoSep = r_stereoSeparation->value; /* * 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; + + 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 = zProj * tan(dest->fovY * M_PI / 360.0f); ymin = -ymax; diff --git a/code/renderer/tr_types.h b/code/renderer/tr_types.h index bb917cfa..2a10342f 100644 --- a/code/renderer/tr_types.h +++ b/code/renderer/tr_types.h @@ -24,27 +24,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_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_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_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;