Merge branch 'r_locksurfaces-dhewm3'

This commit is contained in:
Daniel Gibson 2021-06-15 03:28:40 +02:00
commit a8ef0f67fe
7 changed files with 162 additions and 100 deletions

View file

@ -209,8 +209,14 @@ EmitToCurrentView
void idGuiModel::EmitToCurrentView( float modelMatrix[16], bool depthHack ) {
float modelViewMatrix[16];
myGlMultMatrix( modelMatrix, tr.viewDef->worldSpace.modelViewMatrix,
modelViewMatrix );
const float* worldMVM = tr.viewDef->worldSpace.modelViewMatrix;
// DG: for r_lockSurfaces use the real world modelViewMatrix
// so GUIs don't float around
if(r_lockSurfaces.GetBool() && tr.viewDef == tr.primaryView) {
worldMVM = tr.lockSurfacesRealViewDef.worldSpace.modelViewMatrix;
}
myGlMultMatrix( modelMatrix, worldMVM, modelViewMatrix );
for ( int i = 0 ; i < surfaces.Num() ; i++ ) {
EmitSurface( &surfaces[i], modelMatrix, modelViewMatrix, depthHack );

View file

@ -221,11 +221,6 @@ void R_AddDrawViewCmd( viewDef_t *parms ) {
cmd->viewDef = parms;
if ( parms->viewEntitys ) {
// save the command for r_lockSurfaces debugging
tr.lockSurfacesCmd = *cmd;
}
tr.pc.c_numViews++;
R_ViewStatistics( parms );
@ -235,43 +230,6 @@ void R_AddDrawViewCmd( viewDef_t *parms ) {
//=================================================================================
/*
======================
R_LockSurfaceScene
r_lockSurfaces allows a developer to move around
without changing the composition of the scene, including
culling. The only thing that is modified is the
view position and axis, no front end work is done at all
Add the stored off command again, so the new rendering will use EXACTLY
the same surfaces, including all the culling, even though the transformation
matricies have been changed. This allow the culling tightness to be
evaluated interactively.
======================
*/
void R_LockSurfaceScene( viewDef_t *parms ) {
drawSurfsCommand_t *cmd;
viewEntity_t *vModel;
// set the matrix for world space to eye space
R_SetViewMatrix( parms );
tr.lockSurfacesCmd.viewDef->worldSpace = parms->worldSpace;
// update the view origin and axis, and all
// the entity matricies
for( vModel = tr.lockSurfacesCmd.viewDef->viewEntitys ; vModel ; vModel = vModel->next ) {
myGlMultMatrix( vModel->modelMatrix,
tr.lockSurfacesCmd.viewDef->worldSpace.modelViewMatrix,
vModel->modelViewMatrix );
}
// add the stored off surface commands again
cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
*cmd = tr.lockSurfacesCmd;
}
/*
=============
R_CheckCvars
@ -599,6 +557,18 @@ void idRenderSystemLocal::BeginFrame( int windowWidth, int windowHeight ) {
return;
}
// DG: r_lockSurfaces only works properly if r_useScissor is disabled
if ( r_lockSurfaces.IsModified() ) {
static bool origUseScissor = true;
r_lockSurfaces.ClearModified();
if ( r_lockSurfaces.GetBool() ) {
origUseScissor = r_useScissor.GetBool();
r_useScissor.SetBool( false );
} else {
r_useScissor.SetBool( origUseScissor );
}
} // DG end
// determine which back end we will use
SetBackEndRenderer();
@ -715,6 +685,7 @@ void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) {
// use the other buffers next frame, because another CPU
// may still be rendering into the current buffers
R_ToggleSmpFrame();
// we can now release the vertexes used this frame

View file

@ -675,6 +675,8 @@ Rendering a scene may require multiple views to be rendered
to handle mirrors,
====================
*/
extern void R_SetupViewFrustum( viewDef_t* viewDef );
extern void R_SetupProjection( viewDef_t * viewDef );
void idRenderWorldLocal::RenderScene( const renderView_t *renderView ) {
#ifndef ID_DEDICATED
renderView_t copy;
@ -742,10 +744,32 @@ void idRenderWorldLocal::RenderScene( const renderView_t *renderView ) {
}
if ( r_lockSurfaces.GetBool() ) {
R_LockSurfaceScene( parms );
return;
tr.lockSurfacesRealViewDef = *parms;
// usually the following are called later in R_RenderView(), but we pass
// the locked viewDef to that function so do these calculations here
// (the results are needed for some special cases like in-world GUIs and mirrors)
R_SetViewMatrix( &tr.lockSurfacesRealViewDef );
R_SetupViewFrustum( &tr.lockSurfacesRealViewDef);
R_SetupProjection( &tr.lockSurfacesRealViewDef );
const viewDef_t* origParms = &tr.lockSurfacesRealViewDef;
*parms = tr.lockSurfacesViewDef;
parms->renderWorld = origParms->renderWorld;
parms->floatTime = origParms->floatTime;
parms->drawSurfs = origParms->drawSurfs; // should be NULL I think
parms->numDrawSurfs = origParms->numDrawSurfs;
parms->maxDrawSurfs = origParms->maxDrawSurfs;
parms->viewLights = origParms->viewLights;
parms->viewEntitys = origParms->viewEntitys;
parms->connectedAreas = origParms->connectedAreas;
} else {
// save current viewDef so it can be used if we enable r_lockSurfaces in the next frame
tr.lockSurfacesViewDef = *parms;
}
// save this world for use by some console commands
tr.primaryWorld = this;
tr.primaryRenderView = *renderView;

View file

@ -548,7 +548,6 @@ extern frameData_t *frameData;
//=======================================================================
void R_LockSurfaceScene( viewDef_t *parms );
void R_ClearCommandChain( void );
void R_AddDrawViewCmd( viewDef_t *parms );
@ -785,6 +784,9 @@ public:
performanceCounters_t pc; // performance counters
drawSurfsCommand_t lockSurfacesCmd; // use this when r_lockSurfaces = 1
//renderView_t lockSurfacesRenderView;
viewDef_t lockSurfacesViewDef; // of locked position/view
viewDef_t lockSurfacesRealViewDef; // of actual player position
viewEntity_t identitySpace; // can use if we don't know viewDef->worldSpace is valid
int stencilIncr, stencilDecr; // GL_INCR / INCR_WRAP_EXT, GL_DECR / GL_DECR_EXT

View file

@ -184,9 +184,6 @@ R_ToggleSmpFrame
====================
*/
void R_ToggleSmpFrame( void ) {
if ( r_lockSurfaces.GetBool() ) {
return;
}
R_FreeDeferredTriSurfs( frameData );
// clear frame-temporary data
@ -894,7 +891,7 @@ R_SetupProjection
This uses the "infinite far z" trick
===============
*/
void R_SetupProjection( void ) {
void R_SetupProjection( viewDef_t * viewDef ) {
float xmin, xmax, ymin, ymax;
float width, height;
float zNear;
@ -915,48 +912,48 @@ void R_SetupProjection( void ) {
// set up projection matrix
//
zNear = r_znear.GetFloat();
if ( tr.viewDef->renderView.cramZNear ) {
if ( viewDef->renderView.cramZNear ) {
zNear *= 0.25;
}
ymax = zNear * tan( tr.viewDef->renderView.fov_y * idMath::PI / 360.0f );
ymax = zNear * tan( viewDef->renderView.fov_y * idMath::PI / 360.0f );
ymin = -ymax;
xmax = zNear * tan( tr.viewDef->renderView.fov_x * idMath::PI / 360.0f );
xmax = zNear * tan( viewDef->renderView.fov_x * idMath::PI / 360.0f );
xmin = -xmax;
width = xmax - xmin;
height = ymax - ymin;
jitterx = jitterx * width / ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 + 1 );
jitterx = jitterx * width / ( viewDef->viewport.x2 - viewDef->viewport.x1 + 1 );
xmin += jitterx;
xmax += jitterx;
jittery = jittery * height / ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 + 1 );
jittery = jittery * height / ( viewDef->viewport.y2 - viewDef->viewport.y1 + 1 );
ymin += jittery;
ymax += jittery;
tr.viewDef->projectionMatrix[0] = 2 * zNear / width;
tr.viewDef->projectionMatrix[4] = 0;
tr.viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
tr.viewDef->projectionMatrix[12] = 0;
viewDef->projectionMatrix[0] = 2 * zNear / width;
viewDef->projectionMatrix[4] = 0;
viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
viewDef->projectionMatrix[12] = 0;
tr.viewDef->projectionMatrix[1] = 0;
tr.viewDef->projectionMatrix[5] = 2 * zNear / height;
tr.viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
tr.viewDef->projectionMatrix[13] = 0;
viewDef->projectionMatrix[1] = 0;
viewDef->projectionMatrix[5] = 2 * zNear / height;
viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
viewDef->projectionMatrix[13] = 0;
// this is the far-plane-at-infinity formulation, and
// crunches the Z range slightly so w=0 vertexes do not
// rasterize right at the wraparound point
tr.viewDef->projectionMatrix[2] = 0;
tr.viewDef->projectionMatrix[6] = 0;
tr.viewDef->projectionMatrix[10] = -0.999f;
tr.viewDef->projectionMatrix[14] = -2.0f * zNear;
viewDef->projectionMatrix[2] = 0;
viewDef->projectionMatrix[6] = 0;
viewDef->projectionMatrix[10] = -0.999f;
viewDef->projectionMatrix[14] = -2.0f * zNear;
tr.viewDef->projectionMatrix[3] = 0;
tr.viewDef->projectionMatrix[7] = 0;
tr.viewDef->projectionMatrix[11] = -1;
tr.viewDef->projectionMatrix[15] = 0;
viewDef->projectionMatrix[3] = 0;
viewDef->projectionMatrix[7] = 0;
viewDef->projectionMatrix[11] = -1;
viewDef->projectionMatrix[15] = 0;
}
/*
@ -967,30 +964,31 @@ Setup that culling frustum planes for the current view
FIXME: derive from modelview matrix times projection matrix
=================
*/
static void R_SetupViewFrustum( void ) {
//static
void R_SetupViewFrustum( viewDef_t* viewDef ) {
int i;
float xs, xc;
float ang;
ang = DEG2RAD( tr.viewDef->renderView.fov_x ) * 0.5f;
ang = DEG2RAD( viewDef->renderView.fov_x ) * 0.5f;
idMath::SinCos( ang, xs, xc );
tr.viewDef->frustum[0] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[1];
tr.viewDef->frustum[1] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[1];
viewDef->frustum[0] = xs * viewDef->renderView.viewaxis[0] + xc * viewDef->renderView.viewaxis[1];
viewDef->frustum[1] = xs * viewDef->renderView.viewaxis[0] - xc * viewDef->renderView.viewaxis[1];
ang = DEG2RAD( tr.viewDef->renderView.fov_y ) * 0.5f;
ang = DEG2RAD( viewDef->renderView.fov_y ) * 0.5f;
idMath::SinCos( ang, xs, xc );
tr.viewDef->frustum[2] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[2];
tr.viewDef->frustum[3] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[2];
viewDef->frustum[2] = xs * viewDef->renderView.viewaxis[0] + xc * viewDef->renderView.viewaxis[2];
viewDef->frustum[3] = xs * viewDef->renderView.viewaxis[0] - xc * viewDef->renderView.viewaxis[2];
// plane four is the front clipping plane
tr.viewDef->frustum[4] = /* vec3_origin - */ tr.viewDef->renderView.viewaxis[0];
viewDef->frustum[4] = /* vec3_origin - */ viewDef->renderView.viewaxis[0];
for ( i = 0; i < 5; i++ ) {
// flip direction so positive side faces out (FIXME: globally unify this)
tr.viewDef->frustum[i] = -tr.viewDef->frustum[i].Normal();
tr.viewDef->frustum[i][3] = -( tr.viewDef->renderView.vieworg * tr.viewDef->frustum[i].Normal() );
viewDef->frustum[i] = -viewDef->frustum[i].Normal();
viewDef->frustum[i][3] = -( viewDef->renderView.vieworg * viewDef->frustum[i].Normal() );
}
// eventually, plane five will be the rear clipping plane for fog
@ -998,16 +996,16 @@ static void R_SetupViewFrustum( void ) {
float dNear, dFar, dLeft, dUp;
dNear = r_znear.GetFloat();
if ( tr.viewDef->renderView.cramZNear ) {
if ( viewDef->renderView.cramZNear ) {
dNear *= 0.25f;
}
dFar = MAX_WORLD_SIZE;
dLeft = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_x * 0.5f ) );
dUp = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_y * 0.5f ) );
tr.viewDef->viewFrustum.SetOrigin( tr.viewDef->renderView.vieworg );
tr.viewDef->viewFrustum.SetAxis( tr.viewDef->renderView.viewaxis );
tr.viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp );
dLeft = dFar * tan( DEG2RAD( viewDef->renderView.fov_x * 0.5f ) );
dUp = dFar * tan( DEG2RAD( viewDef->renderView.fov_y * 0.5f ) );
viewDef->viewFrustum.SetOrigin( viewDef->renderView.vieworg );
viewDef->viewFrustum.SetAxis( viewDef->renderView.viewaxis );
viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp );
}
/*
@ -1115,11 +1113,11 @@ void R_RenderView( viewDef_t *parms ) {
// the four sides of the view frustum are needed
// for culling and portal visibility
R_SetupViewFrustum();
R_SetupViewFrustum( tr.viewDef );
// we need to set the projection matrix before doing
// portal-to-screen scissor box calculations
R_SetupProjection();
R_SetupProjection( tr.viewDef );
// identify all the visible portalAreas, and the entityDefs and
// lightDefs that are in them and pass culling.

View file

@ -554,23 +554,26 @@ to actually render the visible surfaces for this view
=================
*/
void RB_BeginDrawingView (void) {
const viewDef_t* viewDef = backEnd.viewDef;
// set the modelview matrix for the viewer
qglMatrixMode(GL_PROJECTION);
qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
qglLoadMatrixf( viewDef->projectionMatrix );
qglMatrixMode(GL_MODELVIEW);
// set the window clipping
qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
qglViewport( tr.viewportOffset[0] + viewDef->viewport.x1,
tr.viewportOffset[1] + viewDef->viewport.y1,
viewDef->viewport.x2 + 1 - viewDef->viewport.x1,
viewDef->viewport.y2 + 1 - viewDef->viewport.y1 );
// the scissor may be smaller than the viewport for subviews
qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
tr.viewportOffset[1] + backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1,
backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 );
backEnd.currentScissor = backEnd.viewDef->scissor;
qglScissor( tr.viewportOffset[0] + viewDef->viewport.x1 + viewDef->scissor.x1,
tr.viewportOffset[1] + viewDef->viewport.y1 + viewDef->scissor.y1,
viewDef->scissor.x2 + 1 - viewDef->scissor.x1,
viewDef->scissor.y2 + 1 - viewDef->scissor.y1 );
backEnd.currentScissor = viewDef->scissor;
// ensures that depth writes are enabled for the depth clear
GL_State( GLS_DEFAULT );
@ -852,6 +855,31 @@ void RB_DrawView( const void *data ) {
cmd = (const drawSurfsCommand_t *)data;
// with r_lockSurfaces enabled, we set the locked render view
// for the primary viewDef for all the "what should be drawn" calculations.
// now it must be reverted to the real render view so the scene gets rendered
// from the actual current players point of view
if(r_lockSurfaces.GetBool() && tr.primaryView == cmd->viewDef) {
viewDef_t* parms = cmd->viewDef;
const viewDef_t origParms = *parms;
*parms = tr.lockSurfacesRealViewDef; // actual current player/camera position
parms->renderWorld = origParms.renderWorld;
parms->floatTime = origParms.floatTime;
parms->drawSurfs = origParms.drawSurfs;
parms->numDrawSurfs = origParms.numDrawSurfs;
parms->maxDrawSurfs = origParms.maxDrawSurfs;
parms->viewLights = origParms.viewLights;
parms->viewEntitys = origParms.viewEntitys;
parms->connectedAreas = origParms.connectedAreas;
for( viewEntity_t* vModel = parms->viewEntitys ; vModel ; vModel = vModel->next ) {
myGlMultMatrix( vModel->modelMatrix,
parms->worldSpace.modelViewMatrix,
vModel->modelViewMatrix );
}
}
backEnd.viewDef = cmd->viewDef;
// we will need to do a new copyTexSubImage of the screen

View file

@ -490,6 +490,39 @@ bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) {
return false;
}
// DG: r_lockSurfaces needs special treatment
if ( r_lockSurfaces.GetBool() && tr.viewDef == tr.primaryView ) {
// we need the scissor for the "real" viewDef (actual camera position etc)
// so mirrors don't "float around" when looking around with r_lockSurfaces enabled
// So do the same calculation as before, but with real viewDef (but don't replace
// calculation above, so the whole mirror or whatever is skipped if not visible in
// locked view!)
viewDef_t* origViewDef = tr.viewDef;
tr.viewDef = &tr.lockSurfacesRealViewDef;
R_PreciseCullSurface( drawSurf, ndcBounds );
idScreenRect origScissor = scissor;
idScreenRect *v2 = &tr.viewDef->viewport;
scissor.x1 = v2->x1 + (int)( (v2->x2 - v2->x1 + 1 ) * 0.5f * ( ndcBounds[0][0] + 1.0f ));
scissor.y1 = v2->y1 + (int)( (v2->y2 - v2->y1 + 1 ) * 0.5f * ( ndcBounds[0][1] + 1.0f ));
scissor.x2 = v2->x1 + (int)( (v2->x2 - v2->x1 + 1 ) * 0.5f * ( ndcBounds[1][0] + 1.0f ));
scissor.y2 = v2->y1 + (int)( (v2->y2 - v2->y1 + 1 ) * 0.5f * ( ndcBounds[1][1] + 1.0f ));
// nudge a bit for safety
scissor.Expand();
scissor.Intersect( tr.viewDef->scissor );
// TBH I'm not 100% happy with how this is handled - you won't get reliable information
// on what's rendered in a mirror this way. Intersecting with the orig. scissor looks "best".
// For handling this "properly" we'd need the whole "locked viewDef vs real viewDef" thing
// for every subview (instead of just once for the primaryView) which would be a lot of
// work for a corner case...
scissor.Intersect( origScissor );
tr.viewDef = origViewDef;
} // DG end
// see what kind of subview we are making
if ( shader->GetSort() != SS_SUBVIEW ) {
for ( int i = 0 ; i < shader->GetNumStages() ; i++ ) {