diff --git a/neo/renderer/Image.h b/neo/renderer/Image.h index 34515a378..b61b731ad 100644 --- a/neo/renderer/Image.h +++ b/neo/renderer/Image.h @@ -409,8 +409,10 @@ class idImageManager { idImage * fogImage; // increasing alpha is denser fog idImage * fogEnterImage; // adjust fogImage alpha based on terminator plane idImage * cinematicImage; - idImage * scratchImage; - idImage * scratchImage2; + + unsigned nextScratchImage; + idImage * scratchImages[8]; // DG: replacing scratchImage(2) with an array of scratch images + idImage * scratchImage; // but keep original "_scratch" around, it's used by gamecode idImage * accumImage; idImage * currentRenderImage; // for SS_POST_PROCESS shaders idImage * scratchCubeMapImage; @@ -427,6 +429,14 @@ class idImageManager { void SetNormalPalette(); void ChangeTextureFilter(); + // Get a (hopefully) unused scratch image, used for rendering subviews like mirrors etc + // it just cycles through the scratch images.. we used to have only two so I guess the + // chance of using (overwriting) one that's already in use is slim enough.. + idImage * GetNextScratchImage() + { + return scratchImages[ nextScratchImage++ % ( sizeof(scratchImages)/sizeof(scratchImages[0]) ) ]; + } + idList images; idStrList ddsList; idHashIndex ddsHash; diff --git a/neo/renderer/Image_init.cpp b/neo/renderer/Image_init.cpp index 89d9c578a..0daade0be 100644 --- a/neo/renderer/Image_init.cpp +++ b/neo/renderer/Image_init.cpp @@ -1468,7 +1468,7 @@ idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorF idImage *image; int hash; - if ( !name ) { + if ( !_name ) { common->FatalError( "idImageManager::ImageFromFunction: NULL name" ); } @@ -2001,8 +2001,17 @@ void idImageManager::Init() { // cinematicImage is used for cinematic drawing // scratchImage is used for screen wipes/doublevision etc.. cinematicImage = ImageFromFunction("_cinematic", R_RGBA8Image ); + + // DG: to allow mirrors mirroring mirrors or cameras filming mirrors or similar nonsense, + // I added multiple scratchImages used by subviews (instead of just _scratch and _scratch2) + nextScratchImage = 0; + for( int i=0; i < sizeof(scratchImages)/sizeof(scratchImages[0]); ++i ) { + idStr scratchName = idStr::Format("_scratch%d", i); + scratchImages[i] = ImageFromFunction(scratchName, R_RGBA8Image ); + } + // keeping _scratch around, it's used by gamecode scratchImage = ImageFromFunction("_scratch", R_RGBA8Image ); - scratchImage2 = ImageFromFunction("_scratch2", R_RGBA8Image ); + accumImage = ImageFromFunction("_accum", R_RGBA8Image ); scratchCubeMapImage = ImageFromFunction("_scratchCubeMap", makeNormalizeVectorCubeMap ); currentRenderImage = ImageFromFunction("_currentRender", R_RGBA8Image ); diff --git a/neo/renderer/RenderSystem.cpp b/neo/renderer/RenderSystem.cpp index bf50950ad..1d5b99ce0 100644 --- a/neo/renderer/RenderSystem.cpp +++ b/neo/renderer/RenderSystem.cpp @@ -834,12 +834,12 @@ void idRenderSystemLocal::CropRenderSize( int width, int height, bool makePowerO height >>= 1; } + currentRenderCrop++; + if ( currentRenderCrop == MAX_RENDER_CROPS ) { common->Error( "idRenderSystemLocal::CropRenderSize: currentRenderCrop == MAX_RENDER_CROPS" ); } - currentRenderCrop++; - rc = &renderCrops[currentRenderCrop]; rc->x = 0; diff --git a/neo/renderer/draw_common.cpp b/neo/renderer/draw_common.cpp index 0cabbfdd0..640b04738 100644 --- a/neo/renderer/draw_common.cpp +++ b/neo/renderer/draw_common.cpp @@ -155,6 +155,10 @@ void RB_PrepareStageTexturing( const shaderStage_t *pStage, const drawSurf_t *s } if ( pStage->texture.texgen == TG_GLASSWARP ) { + // DG: this doesn't work with the scratchImage array, and the shader is missing anyway + // so I commented out the code and added this warning + common->Warning( "RB_PrepareStageTexturing(): Someone is trying to use the glasswarp shader, but it's not implemented..." ); +#if 0 if ( tr.backEndRenderer == BE_ARB2 /*|| tr.backEndRenderer == BE_NV30*/ ) { qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP ); qglEnable( GL_FRAGMENT_PROGRAM_ARB ); @@ -192,6 +196,7 @@ void RB_PrepareStageTexturing( const shaderStage_t *pStage, const drawSurf_t *s GL_SelectTexture( 0 ); } +#endif // 0 } if ( pStage->texture.texgen == TG_REFLECT_CUBE ) { diff --git a/neo/renderer/tr_subview.cpp b/neo/renderer/tr_subview.cpp index d3049cc6a..f03898525 100644 --- a/neo/renderer/tr_subview.cpp +++ b/neo/renderer/tr_subview.cpp @@ -35,6 +35,8 @@ typedef struct { idMat3 axis; } orientation_t; +static idCVar r_maxMirrorRecursion( "r_maxMirrorRecursion", "2", CVAR_RENDERER | /*CVAR_ARCHIVE |*/ CVAR_INTEGER, + "how deep subviews with mirrors can watch each other", 0, MAX_RENDER_CROPS-3 ); /* ================= @@ -330,7 +332,7 @@ static void R_RemoteRender( drawSurf_t *surf, textureStage_t *stage ) { // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; if (!stage->image) { - stage->image = globalImages->scratchImage; + stage->image = globalImages->GetNextScratchImage(); } tr.CaptureRenderToImage( stage->image->imgName ); @@ -381,7 +383,7 @@ void R_MirrorRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect sciss // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; - stage->image = globalImages->scratchImage; + stage->image = globalImages->GetNextScratchImage(); tr.CaptureRenderToImage( stage->image->imgName ); tr.UnCrop(); @@ -431,7 +433,7 @@ void R_XrayRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; - stage->image = globalImages->scratchImage2; + stage->image = globalImages->GetNextScratchImage(); tr.CaptureRenderToImage( stage->image->imgName ); tr.UnCrop(); @@ -531,9 +533,18 @@ bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) { case DI_REMOTE_RENDER: R_RemoteRender( drawSurf, const_cast(&stage->texture) ); break; - case DI_MIRROR_RENDER: + case DI_MIRROR_RENDER: { + // DG: prevent mirrors from mirroring each other to infinity + // and also prevent tr.renderCrops from overflowing (with some extra wiggle + // room in case other cropping things are involved) + int maxDepth = Min(r_maxMirrorRecursion.GetInteger(), MAX_RENDER_CROPS-3); + if ( tr.currentRenderCrop >= maxDepth ) { + const_cast(stage->texture).image = NULL; + return false; + } R_MirrorRender( drawSurf, const_cast(&stage->texture), scissor ); break; + } case DI_XRAY_RENDER: R_XrayRender( drawSurf, const_cast(&stage->texture), scissor ); break;