From 804c16d0a4c145dec2b24bcfb314cf453ae7e887 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Sat, 16 May 2020 17:40:30 +0200 Subject: [PATCH] First step at generating multiple env probes --- base/renderprogs/postprocess.ps.hlsl | 10 +- neo/renderer/OpenGL/RenderBackend_GL.cpp | 4 + neo/renderer/RenderBackend.cpp | 1 + neo/renderer/RenderCommon.h | 54 +++- neo/renderer/RenderSystem.cpp | 4 +- neo/renderer/RenderSystem_init.cpp | 5 +- neo/renderer/RenderWorld.cpp | 2 +- neo/renderer/RenderWorld_envprobes.cpp | 315 +++++++++++++++++++++++ neo/renderer/RenderWorld_local.h | 21 ++ neo/renderer/RenderWorld_portals.cpp | 2 + neo/renderer/tr_frontend_subview.cpp | 78 +++++- 11 files changed, 482 insertions(+), 14 deletions(-) create mode 100644 neo/renderer/RenderWorld_envprobes.cpp diff --git a/base/renderprogs/postprocess.ps.hlsl b/base/renderprogs/postprocess.ps.hlsl index 8a2e070f..1c086cc2 100644 --- a/base/renderprogs/postprocess.ps.hlsl +++ b/base/renderprogs/postprocess.ps.hlsl @@ -47,12 +47,12 @@ struct PS_OUT }; // *INDENT-ON* -#define USE_CHROMATIC_ABERRATION 0 +#define USE_CHROMATIC_ABERRATION 1 #define Chromatic_Amount 0.075 #define USE_TECHNICOLOR 0 // [0 or 1] -#define Technicolor_Amount 0.5 // [0.00 to 1.00] +#define Technicolor_Amount 1.0 // [0.00 to 1.00] #define Technicolor_Power 4.0 // [0.00 to 8.00] #define Technicolor_RedNegativeAmount 0.88 // [0.00 to 1.00] #define Technicolor_GreenNegativeAmount 0.88 // [0.00 to 1.00] @@ -62,9 +62,9 @@ struct PS_OUT #define Vibrance 0.5 // [-1.00 to 1.00] #define Vibrance_RGB_Balance float3( 1.0, 1.0, 1.0 ) -#define USE_CAS 1 +#define USE_CAS 0 -#define USE_DITHERING 0 +#define USE_DITHERING 1 #define Dithering_QuantizationSteps 8.0 // 8.0 = 2 ^ 3 quantization bits #define Dithering_NoiseBoost 1.0 #define Dithering_Wide 1.0 @@ -604,7 +604,7 @@ void main( PS_IN fragment, out PS_OUT result ) #endif #if USE_CHROMATIC_ABERRATION - ChromaticAberrationPass2( color ); + ChromaticAberrationPass( color ); #endif #if USE_TECHNICOLOR diff --git a/neo/renderer/OpenGL/RenderBackend_GL.cpp b/neo/renderer/OpenGL/RenderBackend_GL.cpp index c61d338c..c870fc4a 100644 --- a/neo/renderer/OpenGL/RenderBackend_GL.cpp +++ b/neo/renderer/OpenGL/RenderBackend_GL.cpp @@ -1931,6 +1931,7 @@ void idRenderBackend::StereoRenderExecuteBackEndCommands( const emptyCommand_t* { case RC_NOP: break; + case RC_DRAW_VIEW_GUI: case RC_DRAW_VIEW_3D: { @@ -1950,12 +1951,15 @@ void idRenderBackend::StereoRenderExecuteBackEndCommands( const emptyCommand_t* } } break; + case RC_SET_BUFFER: SetBuffer( cmds ); break; + case RC_COPY_RENDER: CopyRender( cmds ); break; + case RC_POST_PROCESS: { postProcessCommand_t* cmd = ( postProcessCommand_t* )cmds; diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index d65d051b..cf9cffa7 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -4398,6 +4398,7 @@ void idRenderBackend::FogAllLights() { return; } + renderLog.OpenMainBlock( MRB_FOG_ALL_LIGHTS ); renderLog.OpenBlock( "Render_FogAllLights", colorBlue ); diff --git a/neo/renderer/RenderCommon.h b/neo/renderer/RenderCommon.h index b96a932e..564903b7 100644 --- a/neo/renderer/RenderCommon.h +++ b/neo/renderer/RenderCommon.h @@ -3,7 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2012-2016 Robert Beckebans +Copyright (C) 2012-2020 Robert Beckebans Copyright (C) 2014-2016 Kot in Action Creative Artel This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -98,6 +98,7 @@ SURFACES class idRenderWorldLocal; struct viewEntity_t; struct viewLight_t; +struct viewEnvprobe_t; // drawSurf_t structures command the back end to render surfaces // a given srfTriangles_t may be used with multiple viewEntity_t, @@ -269,9 +270,20 @@ public: bool archived; // for demo writing // derived information + idPlane lightProject[4]; // old style light projection where Z and W are flipped and projected lights lightProject[3] is divided by ( zNear + zFar ) + idRenderMatrix baseLightProject; // global xyz1 to projected light strq + idRenderMatrix inverseBaseLightProject;// transforms the zero-to-one cube to exactly cover the light in world space + areaReference_t* references; // each area the light is present in will have a lightRef //idInteraction* firstInteraction; // doubly linked list //idInteraction* lastInteraction; + + idImage* irradianceImage; // cubemap image used for diffuse IBL by backend + idImage* radianceImage; // cubemap image used for specular IBL by backend + + // temporary helpers + int viewCount; // if == tr.viewCount, the envprobe is on the viewDef->viewEnvprobes list + viewEnvprobe_t* viewEnvprobe; }; // RB end @@ -441,6 +453,34 @@ struct viewEntity_t dynamicShadowVolumeParms_t* dynamicShadowVolumes; }; +// RB: viewEnvprobes are allocated on the frame temporary stack memory +// a viewEnvprobe contains everything that the back end needs out of an RenderEnvprobeLocal, +// which the front end may be modifying simultaniously if running in SMP mode. + +// this structure will be especially helpful when we switch RBDOOM-3-BFG to forward cluster shading +// because then we can evaluate all viewEnvprobes properly in each pixel shader along with all other lighting information +struct viewEnvprobe_t +{ + viewEnvprobe_t* next; + + // back end should NOT reference the lightDef, because it can change when running SMP + RenderEnvprobeLocal* envprobeDef; + + // for scissor clipping, local inside renderView viewport + // scissorRect.Empty() is true if the viewEntity_t was never actually + // seen through any portals + idScreenRect scissorRect; + + // R_AddSingleEnvprobe() determined that the light isn't actually needed + bool removeFromList; + + idVec3 globalOrigin; // global envprobe origin used by backend + + idRenderMatrix inverseBaseLightProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the light volume in world space + idImage* irradianceImage; // cubemap image used for diffuse IBL by backend + idImage* radianceImage; // cubemap image used for specular IBL by backend +}; +// RB end const int MAX_CLIP_PLANES = 1; // we may expand this to six for some subview issues @@ -529,7 +569,7 @@ struct viewDef_t int numDrawSurfs; // it is allocated in frame temporary memory int maxDrawSurfs; // may be resized - viewLight_t* viewLights; // chain of all viewLights effecting view + viewLight_t* viewLights; // chain of all viewLights effecting view viewEntity_t* viewEntitys; // chain of all viewEntities effecting view, including off screen ones casting shadows // we use viewEntities as a check to see if a given view consists solely // of 2D rendering, which we can optimize in certain ways. A 2D view will @@ -547,6 +587,15 @@ struct viewDef_t // crossing a closed door. This is used to avoid drawing interactions // when the light is behind a closed door. bool* connectedAreas; + + // RB: collect environment probes like lights + viewEnvprobe_t* viewEnvprobes; + + // RB: nearest probe for now + idRenderMatrix inverseBaseEnvProbeProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the environent probe volume in world space + idImage* irradianceImage; // cubemap image used for diffuse IBL by backend + idImage* radianceImage; // cubemap image used for specular IBL by backend + // RB end }; @@ -1026,6 +1075,7 @@ extern idCVar r_testGammaBias; // draw a grid pattern to test gamma levels extern idCVar r_singleLight; // suppress all but one light extern idCVar r_singleEntity; // suppress all but one entity +extern idCVar r_singleEnvprobe; // suppress all but one envprobe extern idCVar r_singleArea; // only draw the portal area the view is actually in extern idCVar r_singleSurface; // suppress all but one surface on each entity extern idCVar r_shadowPolygonOffset; // bias value added to depth test for stencil shadow drawing diff --git a/neo/renderer/RenderSystem.cpp b/neo/renderer/RenderSystem.cpp index 035799a1..ac234835 100644 --- a/neo/renderer/RenderSystem.cpp +++ b/neo/renderer/RenderSystem.cpp @@ -941,7 +941,6 @@ In split screen mode the rendering size is also smaller. */ void idRenderSystemLocal::PerformResolutionScaling( int& newWidth, int& newHeight ) { - float xScale = 1.0f; float yScale = 1.0f; resolutionScale.GetCurrentResolutionScale( xScale, yScale ); @@ -1057,7 +1056,7 @@ void idRenderSystemLocal::CaptureRenderToImage( const char* imageName, bool clea common->Printf( "write DC_CAPTURE_RENDER: %s\n", imageName ); } } - idImage* image = globalImages->GetImage( imageName ); + idImage* image = globalImages->GetImage( imageName ); if( image == NULL ) { image = globalImages->AllocImage( imageName ); @@ -1093,6 +1092,7 @@ void idRenderSystemLocal::CaptureRenderToFile( const char* fileName, bool fixAlp guiModel->EmitFullScreen(); guiModel->Clear(); + RenderCommandBuffers( frameData->cmdHead ); #if !defined(USE_VULKAN) diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index 0628d645..61e1d485 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -175,6 +175,7 @@ idCVar r_screenFraction( "r_screenFraction", "100", CVAR_RENDERER | CVAR_INTEGER idCVar r_usePortals( "r_usePortals", "1", CVAR_RENDERER | CVAR_BOOL, " 1 = use portals to perform area culling, otherwise draw everything" ); idCVar r_singleLight( "r_singleLight", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one light" ); idCVar r_singleEntity( "r_singleEntity", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one entity" ); +idCVar r_singleEnvprobe( "r_singleEnvprobe", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one environment probe" ); idCVar r_singleSurface( "r_singleSurface", "-1", CVAR_RENDERER | CVAR_INTEGER, "suppress all but one surface on each entity" ); idCVar r_singleArea( "r_singleArea", "0", CVAR_RENDERER | CVAR_BOOL, "only draw the portal area the view is actually in" ); idCVar r_orderIndexes( "r_orderIndexes", "1", CVAR_RENDERER | CVAR_BOOL, "perform index reorganization to optimize vertex use" ); @@ -1210,7 +1211,6 @@ void R_EnvShot_f( const idCmdArgs& args ) for( i = 0 ; i < 6 ; i++ ) { - ref = primary.renderView; extension = envDirection[ i ]; @@ -1219,7 +1219,7 @@ void R_EnvShot_f( const idCmdArgs& args ) ref.viewaxis = axis[i]; fullname.Format( "env/%s%s", baseName, extension ); - tr.TakeScreenshot( size, size, fullname, blends, &ref, TGA ); + tr.TakeScreenshot( size, size, fullname, blends, &ref, PNG ); } // restore the original resolution, axis and fov @@ -1851,7 +1851,6 @@ to skybox textures ( forward, back, left, right, up, down) */ void R_TransformEnvToSkybox_f( const idCmdArgs& args ) { - if( args.Argc() != 2 ) { common->Printf( "USAGE: envToSky \n" ); diff --git a/neo/renderer/RenderWorld.cpp b/neo/renderer/RenderWorld.cpp index 8325f9bc..ecf46857 100644 --- a/neo/renderer/RenderWorld.cpp +++ b/neo/renderer/RenderWorld.cpp @@ -1947,7 +1947,7 @@ void idRenderWorldLocal::GenerateAllInteractions() int size = interactionTableWidth * interactionTableHeight * sizeof( *interactionTable ); interactionTable = ( idInteraction** )R_ClearedStaticAlloc( size ); - // itterate through all lights + // iterate through all lights int count = 0; for( int i = 0; i < this->lightDefs.Num(); i++ ) { diff --git a/neo/renderer/RenderWorld_envprobes.cpp b/neo/renderer/RenderWorld_envprobes.cpp new file mode 100644 index 00000000..701c71e3 --- /dev/null +++ b/neo/renderer/RenderWorld_envprobes.cpp @@ -0,0 +1,315 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2020 Robert Beckebans + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#pragma hdrstop +#include "precompiled.h" + +#include "RenderCommon.h" + +/* +============= +R_SetEnvprobeDefViewEnvprobe + +If the envprobeDef is not already on the viewEnvprobe list, create +a viewEnvprobe and add it to the list with an empty scissor rect. +============= +*/ +viewEnvprobe_t* R_SetEnvprobeDefViewEnvprobe( RenderEnvprobeLocal* probe ) +{ + if( probe->viewCount == tr.viewCount ) + { + // already set up for this frame + return probe->viewEnvprobe; + } + probe->viewCount = tr.viewCount; + + // add to the view light chain + viewEnvprobe_t* vProbe = ( viewEnvprobe_t* )R_ClearedFrameAlloc( sizeof( *vProbe ), FRAME_ALLOC_VIEW_LIGHT ); + vProbe->envprobeDef = probe; + + // the scissorRect will be expanded as the envprobe bounds is accepted into visible portal chains + // and the scissor will be reduced in R_AddSingleEnvprobe based on the screen space projection + vProbe->scissorRect.Clear(); + + // link the view light + vProbe->next = tr.viewDef->viewEnvprobes; + tr.viewDef->viewEnvprobes = vProbe; + + probe->viewEnvprobe = vProbe; + + return vProbe; +} + + +/* +================ +CullEnvprobeByPortals + +Return true if the light frustum does not intersect the current portal chain. +================ +*/ +bool idRenderWorldLocal::CullEnvprobeByPortals( const RenderEnvprobeLocal* probe, const portalStack_t* ps ) +{ + if( r_useLightPortalCulling.GetInteger() == 1 ) + { + ALIGNTYPE16 frustumCorners_t corners; + idRenderMatrix::GetFrustumCorners( corners, probe->inverseBaseLightProject, bounds_zeroOneCube ); + for( int i = 0; i < ps->numPortalPlanes; i++ ) + { + if( idRenderMatrix::CullFrustumCornersToPlane( corners, ps->portalPlanes[i] ) == FRUSTUM_CULL_FRONT ) + { + return true; + } + } + + } + else if( r_useLightPortalCulling.GetInteger() >= 2 ) + { + + idPlane frustumPlanes[6]; + idRenderMatrix::GetFrustumPlanes( frustumPlanes, probe->baseLightProject, true, true ); + + // exact clip of light faces against all planes + for( int i = 0; i < 6; i++ ) + { + // the light frustum planes face inward, so the planes that have the + // view origin on the positive side will be the "back" faces of the light, + // which must have some fragment inside the the portal stack planes to be visible + if( frustumPlanes[i].Distance( tr.viewDef->renderView.vieworg ) <= 0.0f ) + { + continue; + } + + // calculate a winding for this frustum side + idFixedWinding w; + w.BaseForPlane( frustumPlanes[i] ); + for( int j = 0; j < 6; j++ ) + { + if( j == i ) + { + continue; + } + if( !w.ClipInPlace( frustumPlanes[j], ON_EPSILON ) ) + { + break; + } + } + if( w.GetNumPoints() <= 2 ) + { + continue; + } + + assert( ps->numPortalPlanes <= MAX_PORTAL_PLANES ); + assert( w.GetNumPoints() + ps->numPortalPlanes < MAX_POINTS_ON_WINDING ); + + // now clip the winding against each of the portalStack planes + // skip the last plane which is the last portal itself + for( int j = 0; j < ps->numPortalPlanes - 1; j++ ) + { + if( !w.ClipInPlace( -ps->portalPlanes[j], ON_EPSILON ) ) + { + break; + } + } + + if( w.GetNumPoints() > 2 ) + { + // part of the winding is visible through the portalStack, + // so the light is not culled + return false; + } + } + + // nothing was visible + return true; + } + + return false; +} + +/* +=================== +AddAreaViewEnvprobes + +This is the only point where lights get added to the viewLights list. +Any lights that are visible through the current portalStack will have their scissor rect updated. +=================== +*/ +void idRenderWorldLocal::AddAreaViewEnvprobes( int areaNum, const portalStack_t* ps ) +{ + portalArea_t* area = &portalAreas[ areaNum ]; + + for( areaReference_t* lref = area->envprobeRefs.areaNext; lref != &area->envprobeRefs; lref = lref->areaNext ) + { + RenderEnvprobeLocal* probe = lref->envprobe; + + // debug tool to allow viewing of only one light at a time + if( r_singleEnvprobe.GetInteger() >= 0 && r_singleEnvprobe.GetInteger() != probe->index ) + { + continue; + } + + // check for being closed off behind a door + // a light that doesn't cast shadows will still light even if it is behind a door + if( r_useLightAreaCulling.GetBool() //&& !envprobe->LightCastsShadows() + && probe->areaNum != -1 && !tr.viewDef->connectedAreas[ probe->areaNum ] ) + { + continue; + } + + // cull frustum + if( CullEnvprobeByPortals( probe, ps ) ) + { + // we are culled out through this portal chain, but it might + // still be visible through others + continue; + } + + viewEnvprobe_t* vProbe = R_SetEnvprobeDefViewEnvprobe( probe ); + + // expand the scissor rect + vProbe->scissorRect.Union( ps->rect ); + } +} + +CONSOLE_COMMAND( generateEnvironmentProbes, "Generate environment probes", idCmdSystem::ArgCompletion_MapName ) +{ + idStr fullname; + idStr baseName; + idMat3 axis[6], oldAxis; + idVec3 oldPosition; + renderView_t ref; + viewDef_t primary; + int blends; + const char* extension; + int size; + int res_w, res_h, old_fov_x, old_fov_y; + + static const char* envDirection[6] = { "_px", "_nx", "_py", "_ny", "_pz", "_nz" }; + + res_w = renderSystem->GetWidth(); + res_h = renderSystem->GetHeight(); + + baseName = tr.primaryWorld->mapName; + baseName.StripFileExtension(); + + size = 256; + blends = 1; + + if( !tr.primaryView ) + { + common->Printf( "No primary view.\n" ); + return; + } + + primary = *tr.primaryView; + + memset( &axis, 0, sizeof( axis ) ); + + // +X + axis[0][0][0] = 1; + axis[0][1][2] = 1; + axis[0][2][1] = 1; + + // -X + axis[1][0][0] = -1; + axis[1][1][2] = -1; + axis[1][2][1] = 1; + + // +Y + axis[2][0][1] = 1; + axis[2][1][0] = -1; + axis[2][2][2] = -1; + + // -Y + axis[3][0][1] = -1; + axis[3][1][0] = -1; + axis[3][2][2] = 1; + + // +Z + axis[4][0][2] = 1; + axis[4][1][0] = -1; + axis[4][2][1] = 1; + + // -Z + axis[5][0][2] = -1; + axis[5][1][0] = 1; + axis[5][2][1] = 1; + + // let's get the game window to a "size" resolution + if( ( res_w != size ) || ( res_h != size ) ) + { + cvarSystem->SetCVarInteger( "r_windowWidth", size ); + cvarSystem->SetCVarInteger( "r_windowHeight", size ); + R_SetNewMode( false ); // the same as "vid_restart" + } // FIXME that's a hack!! + + // so we return to that axis and fov after the fact. + oldPosition = primary.renderView.vieworg; + oldAxis = primary.renderView.viewaxis; + old_fov_x = primary.renderView.fov_x; + old_fov_y = primary.renderView.fov_y; + + for( int i = 0; i < tr.primaryWorld->envprobeDefs.Num(); i++ ) + { + RenderEnvprobeLocal* def = tr.primaryWorld->envprobeDefs[i]; + if( def == NULL ) + { + continue; + } + + for( int j = 0 ; j < 6 ; j++ ) + { + ref = primary.renderView; + + extension = envDirection[ j ]; + + ref.fov_x = ref.fov_y = 90; + + ref.vieworg = def->parms.origin; + ref.viewaxis = axis[j]; + fullname.Format( "env/%s_envprobe%i%s", baseName.c_str(), i, extension ); + + tr.TakeScreenshot( size, size, fullname, blends, &ref, PNG ); + //tr.CaptureRenderToFile( fullname, false ); + } + } + + // restore the original resolution, axis and fov + ref.vieworg = oldPosition; + ref.viewaxis = oldAxis; + ref.fov_x = old_fov_x; + ref.fov_y = old_fov_y; + cvarSystem->SetCVarInteger( "r_windowWidth", res_w ); + cvarSystem->SetCVarInteger( "r_windowHeight", res_h ); + R_SetNewMode( false ); // the same as "vid_restart" + + common->Printf( "Wrote a env set with the name %s\n", baseName ); +} + diff --git a/neo/renderer/RenderWorld_local.h b/neo/renderer/RenderWorld_local.h index 335aa181..67ed1f32 100644 --- a/neo/renderer/RenderWorld_local.h +++ b/neo/renderer/RenderWorld_local.h @@ -234,10 +234,31 @@ public: //-------------------------- // RenderWorld_portals.cpp + // if we hit this many planes, we will just stop cropping the + // view down, which is still correct, just conservative + static const int MAX_PORTAL_PLANES = 20; + + struct portalStack_t + { + const portal_t* p; + const portalStack_t* next; + // positive side is outside the visible frustum + int numPortalPlanes; + idPlane portalPlanes[MAX_PORTAL_PLANES + 1]; + idScreenRect rect; + }; + bool CullEntityByPortals( const idRenderEntityLocal* entity, const portalStack_t* ps ); void AddAreaViewEntities( int areaNum, const portalStack_t* ps ); + bool CullLightByPortals( const idRenderLightLocal* light, const portalStack_t* ps ); void AddAreaViewLights( int areaNum, const portalStack_t* ps ); + + // RB begin + bool CullEnvprobeByPortals( const RenderEnvprobeLocal* probe, const portalStack_t* ps ); + void AddAreaViewEnvprobes( int areaNum, const portalStack_t* ps ); + // RB end + void AddAreaToView( int areaNum, const portalStack_t* ps ); idScreenRect ScreenRectFromWinding( const idWinding* w, const viewEntity_t* space ); bool PortalIsFoggedOut( const portal_t* p ); diff --git a/neo/renderer/RenderWorld_portals.cpp b/neo/renderer/RenderWorld_portals.cpp index 45858f17..edb85e6a 100644 --- a/neo/renderer/RenderWorld_portals.cpp +++ b/neo/renderer/RenderWorld_portals.cpp @@ -414,6 +414,7 @@ void idRenderWorldLocal::AddAreaToView( int areaNum, const portalStack_t* ps ) // add the models and lights, using more precise culling to the planes AddAreaViewEntities( areaNum, ps ); AddAreaViewLights( areaNum, ps ); + AddAreaViewEnvprobes( areaNum, ps ); // RB } /* @@ -759,6 +760,7 @@ void idRenderWorldLocal::FindViewLightsAndEntities() // clear the visible lightDef and entityDef lists tr.viewDef->viewLights = NULL; tr.viewDef->viewEntitys = NULL; + tr.viewDef->viewEnvprobes = NULL; // RB // all areas are initially not visible, but each portal // chain that leads to them will expand the visible rectangle diff --git a/neo/renderer/tr_frontend_subview.cpp b/neo/renderer/tr_frontend_subview.cpp index 4589092d..6401920e 100644 --- a/neo/renderer/tr_frontend_subview.cpp +++ b/neo/renderer/tr_frontend_subview.cpp @@ -321,7 +321,6 @@ static void R_RemoteRender( const drawSurf_t* surf, textureStage_t* stage ) parms->isSubview = true; parms->isMirror = false; - tr.CropRenderSize( stageWidth, stageHeight ); tr.GetCroppedViewport( &parms->viewport ); @@ -512,9 +511,11 @@ bool R_GenerateSurfaceSubview( const drawSurf_t* drawSurf ) case DI_REMOTE_RENDER: R_RemoteRender( drawSurf, const_cast( &stage->texture ) ); break; + case DI_MIRROR_RENDER: R_MirrorRender( drawSurf, const_cast( &stage->texture ), scissor ); break; + case DI_XRAY_RENDER: R_XrayRender( drawSurf, const_cast( &stage->texture ), scissor ); break; @@ -543,6 +544,61 @@ bool R_GenerateSurfaceSubview( const drawSurf_t* drawSurf ) return true; } +/* +================= +R_EnvironmentProbeRender +================= +*/ +static void R_EnvironmentProbeRender( const RenderEnvprobeLocal* ) +{ +#if 0 + // remote views can be reused in a single frame + //if( stage->dynamicFrameCount == tr.frameCount ) + //{ + // return; + //} + + // issue a new view command + // copy the viewport size from the original + viewDef_t* parms = ( viewDef_t* )R_FrameAlloc( sizeof( *parms ) ); + *parms = *tr.viewDef; + parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons + + parms->isSubview = true; + //parms->isXraySubview = true; + + if( parms == NULL ) + { + return; + } + + int stageWidth = 256; + int stageHeight = 256; + + tr.CropRenderSize( stageWidth, stageHeight ); + + tr.GetCroppedViewport( &parms->viewport ); + + parms->scissor.x1 = 0; + parms->scissor.y1 = 0; + parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1; + parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1; + + parms->superView = tr.viewDef; + //parms->subviewSurface = surf; + + // generate render commands for it + R_RenderView( parms ); + + // copy this rendering to the image + //stage->dynamicFrameCount = tr.frameCount; + //stage->image = globalImages->scratchImage2; + + tr.CaptureRenderToImage( globalImages->scratchImage2->GetName(), true ); + tr.UnCrop(); +#endif +} + /* ================ R_GenerateSubViews @@ -583,5 +639,25 @@ bool R_GenerateSubViews( const drawSurf_t* const drawSurfs[], const int numDrawS } } + // RB: generate subviews for environment probes that need an update + if( tr.viewDef->areaNum != -1 ) + { + // go through each visible probe + int numViewProbes = 0; + + for( viewEnvprobe_t* vProbe = tr.viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next ) + { + numViewProbes++; + + if( !vProbe->envprobeDef->irradianceImage ) + { + R_EnvironmentProbeRender( vProbe->envprobeDef ); + + subviews = true; + } + } + } + // RB end + return subviews; }