Stencil shadows work again (thanks to Stephen Pridham), Renderer Sync #395

This commit is contained in:
Robert Beckebans 2022-03-05 18:27:27 +01:00
parent 816d53790d
commit f1668b7db8
34 changed files with 1046 additions and 503 deletions

View file

@ -15,7 +15,7 @@ Thank you for downloading RBDOOM-3-BFG.
_______________________________________
02 March 2022 - RBDOOM-3-BFG 1.4.0
06 March 2022 - RBDOOM-3-BFG 1.4.0
_______________________________
<img src="https://i.imgur.com/3sUxOZi.jpg">

View file

@ -60,7 +60,7 @@ public:
ID_TIME_T LoadFromGeneratedFile( ID_TIME_T sourceFileTime );
ID_TIME_T WriteGeneratedFile( ID_TIME_T sourceFileTime );
const bimageFile_t& GetFileHeader()
const bimageFile_t& GetFileHeader()
{
return fileData;
}
@ -78,6 +78,7 @@ public:
return images[i].data;
}
static void GetGeneratedFileName( idStr& gfn, const char* imageName );
private:
idStr imgName; // game path, including extension (except for cube maps), may be an image program
bimageFile_t fileData;

View file

@ -44,12 +44,11 @@ This is where the Binary image headers go that are also included by external too
struct bimageImage_t
{
int level;
int destZ;
int level; // mip
int destZ; // array slice
int width;
int height;
int dataSize;
// dataSize bytes follow
int dataSize; // dataSize bytes follow
};
#pragma pack( push, 1 )

View file

@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 2014-2018 Robert Beckebans
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -36,8 +37,15 @@ idList<Framebuffer*> Framebuffer::framebuffers;
globalFramebuffers_t globalFramebuffers;
Framebuffer* Framebuffer::Find( const char* name )
{
for( int i = 0; i < framebuffers.Num(); i++ )
{
if( idStr::Icmp( framebuffers[i]->fboName, name ) == 0 )
{
return framebuffers[i];
}
}
return nullptr;
}

View file

@ -54,8 +54,9 @@ public:
static void Init();
static void Shutdown();
static void CheckFramebuffers();
static Framebuffer* Find( const char* name );
static void ResizeFramebuffers();
void Bind();
bool IsBound();
@ -65,6 +66,7 @@ public:
void AddColorBuffer( int format, int index, int multiSamples = 0 );
void AddDepthBuffer( int format, int multiSamples = 0 );
void AddStencilBuffer( int format, int multiSamples = 0 );
void AttachImage2D( int target, const idImage* image, int index, int mipmapLod = 0 );
void AttachImage3D( const idImage* image );
@ -139,6 +141,7 @@ struct globalFramebuffers_t
Framebuffer* smaaEdgesFBO;
Framebuffer* smaaBlendFBO;
};
extern globalFramebuffers_t globalFramebuffers;
#endif // __FRAMEBUFFER_H__

View file

@ -407,6 +407,68 @@ This uses the "infinite far z" trick
idCVar r_centerX( "r_centerX", "0", CVAR_FLOAT, "projection matrix center adjust" );
idCVar r_centerY( "r_centerY", "0", CVAR_FLOAT, "projection matrix center adjust" );
inline float sgn( float a )
{
if( a > 0.0f )
{
return ( 1.0f );
}
if( a < 0.0f )
{
return ( -1.0f );
}
return ( 0.0f );
}
// clipPlane is a plane in camera space.
void ModifyProjectionMatrix( viewDef_t* viewDef, const idPlane& clipPlane )
{
static float s_flipMatrix[16] =
{
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
0, 0, -1, 0,
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 0, 1
};
idMat4 flipMatrix;
memcpy( &flipMatrix, &( s_flipMatrix[0] ), sizeof( float ) * 16 );
idVec4 vec = clipPlane.ToVec4();// * flipMatrix;
idPlane newPlane( vec[0], vec[1], vec[2], vec[3] );
// Calculate the clip-space corner point opposite the clipping plane
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
// transform it into camera space by multiplying it
// by the inverse of the projection matrix
//idVec4 q;
//q.x = (sgn(newPlane[0]) + viewDef->projectionMatrix[8]) / viewDef->projectionMatrix[0];
//q.y = (sgn(newPlane[1]) + viewDef->projectionMatrix[9]) / viewDef->projectionMatrix[5];
//q.z = -1.0F;
//q.w = (1.0F + viewDef->projectionMatrix[10]) / viewDef->projectionMatrix[14];
idMat4 unprojection;
R_MatrixFullInverse( viewDef->projectionMatrix, ( float* )&unprojection );
idVec4 q = unprojection * idVec4( sgn( newPlane[0] ), sgn( newPlane[1] ), 1.0f, 1.0f );
// Calculate the scaled plane vector
idVec4 c = newPlane.ToVec4() * ( 2.0f / ( q * newPlane.ToVec4() ) );
float matrix[16];
std::memcpy( matrix, viewDef->projectionMatrix, sizeof( float ) * 16 );
// Replace the third row of the projection matrix
matrix[2] = c[0];
matrix[6] = c[1];
matrix[10] = c[2] + 1.0f;
matrix[14] = c[3];
memcpy( viewDef->projectionMatrix, matrix, sizeof( float ) * 16 );
}
void R_SetupProjectionMatrix( viewDef_t* viewDef )
{
// random jittering is usefull when multiple
@ -493,6 +555,13 @@ void R_SetupProjectionMatrix( viewDef_t* viewDef )
viewDef->projectionMatrix[1 * 4 + 1] = -viewDef->projectionMatrix[1 * 4 + 1];
viewDef->projectionMatrix[1 * 4 + 3] = -viewDef->projectionMatrix[1 * 4 + 3];
}
// SP Begin
if( viewDef->isObliqueProjection )
{
R_ObliqueProjection( viewDef );
}
// SP End
}
@ -606,4 +675,39 @@ void R_MatrixFullInverse( const float a[16], float r[16] )
}
}
}
// RB end
// RB end
// SP begin
/*
=====================
R_ObliqueProjection - adjust near plane of previously set projection matrix to perform an oblique projection
credits to motorsep: https://github.com/motorsep/StormEngine2/blob/743a0f9581a10837a91cb296ff5a1114535e8d4e/neo/renderer/tr_frontend_subview.cpp#L225
=====================
*/
void R_ObliqueProjection( viewDef_t* parms )
{
float mvt[16]; // model view transpose
idPlane pB = parms->clipPlanes[0];
idPlane cp; // camera space plane
R_MatrixTranspose( parms->worldSpace.modelViewMatrix, mvt );
// transform plane (which is set to the surface we're mirroring about's plane) to camera space
R_GlobalPlaneToLocal( mvt, pB, cp );
// oblique projection adjustment code
idVec4 clipPlane( cp[0], cp[1], cp[2], cp[3] );
idVec4 q;
q[0] = ( ( clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f ) + parms->projectionMatrix[8] ) / parms->projectionMatrix[0];
q[1] = ( ( clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f ) + parms->projectionMatrix[9] ) / parms->projectionMatrix[5];
q[2] = -1.0f;
q[3] = ( 1.0f + parms->projectionMatrix[10] ) / parms->projectionMatrix[14];
// scaled plane vector
float d = 2.0f / ( clipPlane * q );
// Replace the third row of the projection matrix
parms->projectionMatrix[2] = clipPlane[0] * d;
parms->projectionMatrix[6] = clipPlane[1] * d;
parms->projectionMatrix[10] = clipPlane[2] * d + 1.0f;
parms->projectionMatrix[14] = clipPlane[3] * d;
}
// SP end

View file

@ -68,4 +68,8 @@ void R_SetupProjectionMatrix2( const viewDef_t* viewDef, const float zNear, cons
void R_MatrixFullInverse( const float in[16], float r[16] );
// RB end
// SP begin
void R_ObliqueProjection( viewDef_t* viewDef );
// SP end
#endif /* !__GLMATRIX_H__ */

View file

@ -5,6 +5,7 @@ Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2021 Robert Beckebans
Copyright (C) 2016-2017 Dustin Land
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -28,6 +29,9 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#ifndef IMAGE_H_
#define IMAGE_H_
enum textureType_t
{
TT_DISABLED,
@ -35,7 +39,7 @@ enum textureType_t
TT_CUBIC,
// RB begin
TT_2D_ARRAY,
TT_2D_MULTISAMPLE
TT_2D_MULTISAMPLE,
// RB end
};
@ -101,6 +105,8 @@ enum textureFormat_t
FMT_RGBA32F, // 128 bpp
FMT_R32F, // 32 bpp
FMT_R11G11B10F, // 32 bpp
FMT_R8,
FMT_DEPTH_STENCIL, // 32 bpp
// RB end
};
@ -157,6 +163,7 @@ public:
int numLevels; // if 0, will be 1 for NEAREST / LINEAR filters, otherwise based on size
bool gammaMips; // if true, mips will be generated with gamma correction
bool readback; // 360 specific - cpu reads back from this texture, so allocate with cached memory
bool isRenderTarget;
};
/*
@ -175,8 +182,8 @@ ID_INLINE idImageOpts::idImageOpts()
textureType = TT_2D;
gammaMips = false;
readback = false;
};
isRenderTarget = false;
}
/*
========================
@ -229,6 +236,8 @@ typedef enum
TD_R32F,
TD_R11G11B10F, // memory efficient HDR RGB format with only 32bpp
// RB end
TD_R8F, // Stephen: Added for ambient occlusion render target.
TD_DEPTH_STENCIL, // depth buffer and stencil buffer
} textureUsage_t;
typedef enum
@ -238,7 +247,8 @@ typedef enum
CF_CAMERA, // _forward, _back, etc, rotated and flipped as needed before sending to GL
CF_PANORAMA, // TODO latlong encoded HDRI panorama typically used by Substance or Blender
CF_2D_ARRAY, // not a cube map but not a single 2d texture either
CF_2D_PACKED_MIPCHAIN // usually 2d but can be an octahedron, packed mipmaps into single 2d texture atlas and limited to dim^2
CF_2D_PACKED_MIPCHAIN, // usually 2d but can be an octahedron, packed mipmaps into single 2d texture atlas and limited to dim^2
CF_SINGLE, // SP: A single texture cubemap. All six sides in one image.
} cubeFiles_t;
enum imageFileType_t
@ -266,7 +276,7 @@ public:
return imgName;
}
// Makes this image active on the current GL texture unit.
// Makes this image active on the current texture unit.
// automatically enables or disables cube mapping
// May perform file loading if the image was not preloaded.
void Bind();
@ -365,12 +375,6 @@ public:
int width, int height, const void* data,
int pixelPitch = 0 );
// SetPixel is assumed to be a fast memory write on consoles, degenerating to a
// SubImageUpload on PCs. Used to update the page mapping images.
// We could remove this now, because the consoles don't use the intermediate page mapping
// textures now that they can pack everything into the virtual page table images.
void SetPixel( int mipLevel, int x, int y, const void* data, int dataSize );
// some scratch images are dynamically resized based on the display window size. This
// simply purges the image and recreates it if the sizes are different, so it should not be
// done under any normal circumstances, and probably not at all on consoles.
@ -405,7 +409,9 @@ public:
textureFilter_t filter,
textureRepeat_t repeat,
textureUsage_t usage,
textureSamples_t samples = SAMPLE_1, cubeFiles_t cubeFiles = CF_2D );
textureSamples_t samples = SAMPLE_1,
cubeFiles_t cubeFiles = CF_2D,
bool isRenderTarget = false );
void GenerateCubeImage( const byte* pic[6], int size,
textureFilter_t filter, textureUsage_t usage );
@ -433,13 +439,14 @@ public:
private:
friend class idImageManager;
void DeriveOpts();
void AllocImage();
void SetSamplerState( textureFilter_t tf, textureRepeat_t tr );
void DeriveOpts();
void AllocImage();
void SetSamplerState( textureFilter_t tf, textureRepeat_t tr );
// parameters that define this image
idStr imgName; // game path, including extension (except for cube maps), may be an image program
cubeFiles_t cubeFiles; // If this is a cube map, and if so, what kind
int cubeMapSize;
void ( *generatorFunction )( idImage* image ); // NULL for files
textureUsage_t usage; // Used to determine the type of compression to use
idImageOpts opts; // Parameters that determine the storage method
@ -526,7 +533,7 @@ public:
// grid pattern.
// Will automatically execute image programs if needed.
idImage* ImageFromFile( const char* name,
textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap = CF_2D );
textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap = CF_2D, int cubeMapSize = 0 );
// look for a loaded image, whatever the parameters
idImage* GetImage( const char* name ) const;
@ -656,6 +663,11 @@ void R_VerticalFlip( byte* data, int width, int height );
void R_VerticalFlipRGB16F( byte* data, int width, int height );
void R_RotatePic( byte* data, int width );
void R_ApplyCubeMapTransforms( int i, byte* data, int size );
// SP begin
// This method takes in a cubemap from a single image. Depending on the side (0-5),
// the image will be extracted from data and returned. The dimensions will be size x size.
byte* R_GenerateCubeMapSideFromSingleImage( byte* data, int srcWidth, int srcHeight, int size, int side );
// SP end
idVec4 R_CalculateMipRect( uint dimensions, uint mip );
int R_CalculateUsedAtlasPixels( int dimensions );
@ -672,7 +684,7 @@ IMAGEFILES
void R_LoadImage( const char* name, byte** pic, int* width, int* height, ID_TIME_T* timestamp, bool makePowerOf2, textureUsage_t* usage );
// pic is in top to bottom raster format
bool R_LoadCubeImages( const char* cname, cubeFiles_t extensions, byte* pic[6], int* size, ID_TIME_T* timestamp );
bool R_LoadCubeImages( const char* cname, cubeFiles_t extensions, byte* pic[6], int* size, ID_TIME_T* timestamp, int cubeMapSize = 0 );
/*
====================================================================
@ -685,3 +697,4 @@ IMAGEPROGRAM
void R_LoadImageProgram( const char* name, byte** pic, int* width, int* height, ID_TIME_T* timestamp, textureUsage_t* usage = NULL );
const char* R_ParsePastImageProgram( idLexer& src );
#endif

View file

@ -366,7 +366,7 @@ Loading of the image may be deferred for dynamic loading.
==============
*/
idImage* idImageManager::ImageFromFile( const char* _name, textureFilter_t filter,
textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap )
textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap, int cubeMapSize )
{
if( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 )
@ -845,17 +845,18 @@ int idImageManager::LoadLevelImages( bool pacifier )
int loadCount = 0;
for( int i = 0 ; i < images.Num() ; i++ )
{
idImage* image = images[ i ];
if( pacifier )
{
common->UpdateLevelLoadPacifier();
}
idImage* image = images[ i ];
if( image->generatorFunction )
{
continue;
}
if( image->levelLoadReferenced && !image->IsLoaded() )
{
loadCount++;

View file

@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2012-2021 Robert Beckebans
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -1514,7 +1515,7 @@ R_LoadCubeImages
Loads six files with proper extensions
=======================
*/
bool R_LoadCubeImages( const char* imgName, cubeFiles_t extensions, byte* pics[6], int* outSize, ID_TIME_T* timestamp )
bool R_LoadCubeImages( const char* imgName, cubeFiles_t extensions, byte* pics[6], int* outSize, ID_TIME_T* timestamp, int cubeMapSize )
{
int i, j;
const char* cameraSides[6] = { "_forward.tga", "_back.tga", "_left.tga", "_right.tga",
@ -1546,6 +1547,74 @@ bool R_LoadCubeImages( const char* imgName, cubeFiles_t extensions, byte* pics[6
*timestamp = 0;
}
if( extensions == CF_SINGLE && cubeMapSize != 0 )
{
ID_TIME_T thisTime;
byte* thisPic[1];
thisPic[0] = nullptr;
if( pics )
{
R_LoadImageProgram( imgName, thisPic, &width, &height, &thisTime );
}
else
{
// load just the timestamps
R_LoadImageProgram( imgName, nullptr, &width, &height, &thisTime );
}
if( thisTime == FILE_NOT_FOUND_TIMESTAMP )
{
return false;
}
if( timestamp )
{
if( thisTime > *timestamp )
{
*timestamp = thisTime;
}
}
if( pics )
{
*outSize = cubeMapSize;
for( int i = 0; i < 6; i++ )
{
pics[i] = R_GenerateCubeMapSideFromSingleImage( thisPic[0], width, height, cubeMapSize, i );
switch( i )
{
case 0: // forward
R_RotatePic( pics[i], cubeMapSize );
break;
case 1: // back
R_RotatePic( pics[i], cubeMapSize );
R_HorizontalFlip( pics[i], cubeMapSize, cubeMapSize );
R_VerticalFlip( pics[i], cubeMapSize, cubeMapSize );
break;
case 2: // left
R_VerticalFlip( pics[i], cubeMapSize, cubeMapSize );
break;
case 3: // right
R_HorizontalFlip( pics[i], cubeMapSize, cubeMapSize );
break;
case 4: // up
R_RotatePic( pics[i], cubeMapSize );
break;
case 5: // down
R_RotatePic( pics[i], cubeMapSize );
break;
}
}
R_StaticFree( thisPic[0] );
}
return true;
}
for( i = 0 ; i < 6 ; i++ )
{
idStr::snPrintf( fullName, sizeof( fullName ), "%s%s", imgName, sides[i] );

View file

@ -229,7 +229,7 @@ static void R_DepthImage( idImage* image )
#else
int msaaSamples = 0;
#endif
image->GenerateImage( NULL, renderSystem->GetWidth(), renderSystem->GetHeight(), TF_NEAREST, TR_CLAMP, TD_DEPTH );//, msaaSamples );
image->GenerateImage( NULL, renderSystem->GetWidth(), renderSystem->GetHeight(), TF_NEAREST, TR_CLAMP, TD_DEPTH_STENCIL );//, msaaSamples );
// RB end
}
@ -272,7 +272,7 @@ static void R_EnvprobeImage_HDR( idImage* image )
static void R_EnvprobeImage_Depth( idImage* image )
{
image->GenerateImage( NULL, ENVPROBE_CAPTURE_SIZE, ENVPROBE_CAPTURE_SIZE, TF_NEAREST, TR_CLAMP, TD_DEPTH );
image->GenerateImage( NULL, ENVPROBE_CAPTURE_SIZE, ENVPROBE_CAPTURE_SIZE, TF_NEAREST, TR_CLAMP, TD_DEPTH_STENCIL );
}
static void R_SMAAImage_ResNative( idImage* image )
@ -294,8 +294,24 @@ static void R_HierarchicalZBufferImage_ResNative( idImage* image )
{
image->GenerateImage( NULL, renderSystem->GetWidth(), renderSystem->GetHeight(), TF_NEAREST_MIPMAP, TR_CLAMP, TD_R32F );
}
static void R_R8Image_ResNative_Linear( idImage* image )
{
image->GenerateImage( NULL, renderSystem->GetWidth(), renderSystem->GetHeight(), TF_LINEAR, TR_CLAMP, TD_LOOKUP_TABLE_MONO );
}
// RB end
static void R_HDR_RGBA8Image_ResNative( idImage* image )
{
// FIXME
#if defined(USE_HDR_MSAA)
int msaaSamples = glConfig.multisamples;
#else
int msaaSamples = 0;
#endif
image->GenerateImage( NULL, renderSystem->GetWidth(), renderSystem->GetHeight(), TF_NEAREST, TR_CLAMP, TD_LOOKUP_TABLE_RGBA ); //, msaaSamples );
}
static void R_AlphaNotchImage( idImage* image )
{
byte data[2][4];

View file

@ -82,10 +82,14 @@ int BitsForFormat( textureFormat_t format )
// RB end
case FMT_DEPTH:
return 32;
case FMT_DEPTH_STENCIL:
return 32;
case FMT_X16:
return 16;
case FMT_Y16_X16:
return 32;
case FMT_R8:
return 4;
default:
assert( 0 );
return 0;
@ -114,6 +118,12 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DEPTH;
break;
// sp begin
case TD_DEPTH_STENCIL:
opts.format = FMT_DEPTH_STENCIL;
break;
// sp end
case TD_SHADOW_ARRAY:
opts.format = FMT_SHADOW_ARRAY;
break;
@ -134,6 +144,10 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_R32F;
break;
case TD_R8F:
opts.format = FMT_R8;
break;
case TD_R11G11B10F:
opts.format = FMT_R11G11B10F;
break;
@ -273,7 +287,6 @@ void idImage::GetGeneratedName( idStr& _name, const textureUsage_t& _usage, cons
}
}
/*
===============
ActuallyLoadImage
@ -319,11 +332,11 @@ void idImage::ActuallyLoadImage( bool fromBackEnd )
{
opts.textureType = TT_2D_ARRAY;
}
else if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA )
else if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_SINGLE )
{
opts.textureType = TT_CUBIC;
repeat = TR_CLAMP;
R_LoadCubeImages( GetName(), cubeFiles, NULL, NULL, &sourceFileTime );
R_LoadCubeImages( GetName(), cubeFiles, NULL, NULL, &sourceFileTime, cubeMapSize );
}
else
{
@ -423,7 +436,9 @@ void idImage::ActuallyLoadImage( bool fromBackEnd )
{
opts.format = ( textureFormat_t )header.format;
}
opts.textureType = ( textureType_t )header.textureType;
if( cvarSystem->GetCVarBool( "fs_buildresources" ) )
{
// for resource gathering write this image to the preload file for this map
@ -454,12 +469,12 @@ void idImage::ActuallyLoadImage( bool fromBackEnd )
//else if( toolUsage )
// binarizeReason = va( "binarize: tool usage '%s'", generatedName.c_str() );
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA )
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_SINGLE )
{
int size;
byte* pics[6];
if( !R_LoadCubeImages( GetName(), cubeFiles, pics, &size, &sourceFileTime ) || size == 0 )
if( !R_LoadCubeImages( GetName(), cubeFiles, pics, &size, &sourceFileTime, cubeMapSize ) || size == 0 )
{
idLib::Warning( "Couldn't load cube image: %s", GetName() );
defaulted = true; // RB
@ -750,7 +765,7 @@ void idImage::Reload( bool force )
if( !force )
{
ID_TIME_T current;
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA )
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_SINGLE )
{
R_LoadCubeImages( imgName, cubeFiles, NULL, NULL, &current );
}
@ -778,7 +793,7 @@ void idImage::Reload( bool force )
GenerateImage
================
*/
void idImage::GenerateImage( const byte* pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, textureSamples_t samples, cubeFiles_t _cubeFiles )
void idImage::GenerateImage( const byte* pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, textureSamples_t samples, cubeFiles_t _cubeFiles, bool isRenderTarget )
{
PurgeImage();
@ -792,6 +807,7 @@ void idImage::GenerateImage( const byte* pic, int width, int height, textureFilt
opts.height = height;
opts.numLevels = 0;
opts.samples = samples;
opts.isRenderTarget = isRenderTarget;
// RB
if( cubeFiles == CF_2D_PACKED_MIPCHAIN )
@ -940,6 +956,8 @@ void idImage::GenerateShadowArray( int width, int height, textureFilter_t filter
opts.width = width;
opts.height = height;
opts.numLevels = 0;
opts.isRenderTarget = true;
DeriveOpts();
// if we don't have a rendering context, just return after we
@ -980,6 +998,7 @@ void idImage::UploadScratch( const byte* data, int cols, int rows )
{
rows /= 6;
const byte* pic[6];
for( int i = 0; i < 6; i++ )
{
pic[i] = data + cols * rows * 4 * i;
@ -990,6 +1009,7 @@ void idImage::UploadScratch( const byte* data, int cols, int rows )
GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA );
return;
}
if( opts.width != cols || opts.height != rows )
{
opts.width = cols;

View file

@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2021 Robert Beckebans
Copyright (C) 2021 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -628,3 +629,77 @@ int R_CalculateUsedAtlasPixels( int dimensions )
return numPixels;
}
// SP begin
byte* R_GenerateCubeMapSideFromSingleImage( byte* data, int srcWidth, int srcHeight, int size, int side )
{
size_t x = 0, y = 0;
switch( side )
{
case 0:
{
// negative Z, front
x = size;
y = size;
break;
}
case 1:
{
// positive Z, back
x = 3 * size;
y = size;
break;
}
case 2:
{
// negative X, left
x = 0;
y = size;
break;
}
case 3:
{
// positive X, right
x = size * 2;
y = size;
break;
}
case 4:
{
// positive Y, top
x = size;
y = 0;
break;
}
case 5:
{
// negative Y, bottom
x = size;
y = 2 * ( size_t )size;
break;
}
default:
{
common->Warning( "Invalid side when generating cube map images" );
return nullptr;
}
}
const size_t copySize = ( size_t )size * ( size_t )size * 4;
byte* out = ( byte* )R_StaticAlloc( copySize, TAG_IMAGE );
uint32_t* out_p = ( uint32_t* )out;
const uint32_t* in_p = ( uint32_t* )data + x + y * srcWidth;
for( int j = 0; j < size; j++ )
{
for( int i = 0; i < size; i++ )
{
out_p[i + j * size] = in_p[i + j * srcWidth];
}
}
return out;
}
// SP end

View file

@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2021 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -390,6 +391,42 @@ static void R_ImageAdd( byte* data1, int width1, int height1, byte* data2, int w
}
}
// SP begin
static void R_CombineRgba( byte* data1, int width1, int height1, byte* data2, int width2, int height2, byte* data3, int width3, int height3 )
{
assert( width1 == width2 );
//assert(width2 == width3);
assert( height1 == height2 );
for( int j = 0; j < 4 * height1; j += 4 )
{
for( int i = 0; i < 4 * width1; i += 4 )
{
// Assume that these textures are all grayscale images. just take the r channel of each and set them to
// the respective rgb.
byte r = data1[i + j * width1];
byte g = data2[i + j * width1];
byte b = 255;
if( data3 && width1 == width3 )
{
b = data3[i + j * width1];
}
byte a = 255;
data1[0 + i + j * width1] = r;
data1[1 + i + j * width1] = g;
data1[2 + i + j * width1] = b;
data1[3 + i + j * width1] = a;
}
}
}
// SP end
// we build a canonical token form of the image program here
static char parseBuffer[MAX_IMAGE_NAME];
@ -710,6 +747,56 @@ static bool R_ParseImageProgram_r( idLexer& src, byte** pic, int* width, int* he
return true;
}
if( !token.Icmp( "combineRgba" ) )
{
byte* pic2 = nullptr;
byte* pic3 = nullptr;
int width2, height2;
int width3, height3;
MatchAndAppendToken( src, "(" );
if( !R_ParseImageProgram_r( src, pic, width, height, timestamps, usage ) )
{
return false;
}
MatchAndAppendToken( src, "," );
if( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, usage ) )
{
if( pic )
{
R_StaticFree( *pic );
*pic = NULL;
}
return false;
}
MatchAndAppendToken( src, "," );
if( !R_ParseImageProgram_r( src, pic2 ? &pic3 : NULL, &width3, &height3, timestamps, usage ) )
{
if( pic )
{
R_StaticFree( *pic );
*pic = NULL;
}
return false;
}
// process it
if( pic )
{
R_CombineRgba( *pic, *width, *height, pic2, width2, height2, pic3, width3, height3 );
R_StaticFree( pic2 );
R_StaticFree( pic3 );
}
MatchAndAppendToken( src, ")" );
return true;
}
// if we are just parsing instead of loading or checking,
// don't do the R_LoadImage
if( !timestamps && !pic )

View file

@ -5,6 +5,7 @@ Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2016 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -89,6 +90,7 @@ void idMaterial::CommonInit()
surfaceFlags = SURFTYPE_NONE;
materialFlags = 0;
sort = SS_BAD;
subViewType = SUBVIEW_NONE;
stereoEye = 0;
coverage = MC_BAD;
cullType = CT_FRONT_SIDED;
@ -186,6 +188,11 @@ void idMaterial::FreeData()
Mem_Free( stages[i].newStage );
stages[i].newStage = NULL;
}
if( stages[i].stencilStage != nullptr )
{
Mem_Free( stages[i].stencilStage );
stages[i].stencilStage = nullptr;
}
}
R_StaticFree( stages );
stages = NULL;
@ -1268,6 +1275,11 @@ void idMaterial::ParseFragmentMap( idLexer& src, newShaderStage_t* newStage )
cubeMap = CF_CAMERA;
continue;
}
if( !token.Icmp( "cubeMapSingle" ) )
{
cubeMap = CF_SINGLE;
continue;
}
if( !token.Icmp( "nearest" ) )
{
tf = TF_NEAREST;
@ -1329,6 +1341,207 @@ void idMaterial::ParseFragmentMap( idLexer& src, newShaderStage_t* newStage )
}
}
/*
===============
idMaterial::ParseStencilCompare
===============
*/
void idMaterial::ParseStencilCompare( const idToken& token, stencilComp_t* stencilComp )
{
if( !token.Icmp( "Greater" ) )
{
*stencilComp = STENCIL_COMP_GREATER;
return;
}
if( !token.Icmp( "GEqual" ) )
{
*stencilComp = STENCIL_COMP_GEQUAL;
return;
}
if( !token.Icmp( "Less" ) )
{
*stencilComp = STENCIL_COMP_LESS;
return;
}
if( !token.Icmp( "LEqual" ) )
{
*stencilComp = STENCIL_COMP_LEQUAL;
return;
}
if( !token.Icmp( "Equal" ) )
{
*stencilComp = STENCIL_COMP_EQUAL;
return;
}
if( !token.Icmp( "NotEqual" ) )
{
*stencilComp = STENCIL_COMP_NOTEQUAL;
return;
}
if( !token.Icmp( "Always" ) )
{
*stencilComp = STENCIL_COMP_ALWAYS;
return;
}
if( !token.Icmp( "Never" ) )
{
*stencilComp = STENCIL_COMP_NEVER;
return;
}
common->Warning( "Material %s expected a valid stencil comparison function. Got %s", GetName(), token.c_str() );
}
/*
===============
idMaterial::ParseStencilOperation
===============
*/
void idMaterial::ParseStencilOperation( const idToken& token, stencilOperation_t* stencilOp )
{
if( !token.Icmp( "Keep" ) )
{
*stencilOp = STENCIL_OP_KEEP;
return;
}
if( !token.Icmp( "Zero" ) )
{
*stencilOp = STENCIL_OP_ZERO;
return;
}
if( !token.Icmp( "Replace" ) )
{
*stencilOp = STENCIL_OP_REPLACE;
return;
}
if( !token.Icmp( "IncrSat" ) )
{
*stencilOp = STENCIL_OP_INCRSAT;
return;
}
if( !token.Icmp( "DecrSat" ) )
{
*stencilOp = STENCIL_OP_DECRSAT;
return;
}
if( !token.Icmp( "Invert" ) )
{
*stencilOp = STENCIL_OP_INVERT;
return;
}
if( !token.Icmp( "IncrWrap" ) )
{
*stencilOp = STENCIL_OP_INCRWRAP;
return;
}
if( !token.Icmp( "DecrWrap" ) )
{
*stencilOp = STENCIL_OP_DECRWRAP;
return;
}
common->Warning( "Material %s expected a valid stencil operation function. Got %s", GetName(), token.c_str() );
}
/*
===============
idMaterial::ParseStencil
===============
*/
void idMaterial::ParseStencil( idLexer& src, stencilStage_t* stencilStage )
{
idToken token;
src.ReadToken( &token );
if( token.Icmp( "{" ) )
{
common->Warning( "Material %s Missing { after stencil", GetName() );
return;
}
while( 1 )
{
if( TestMaterialFlag( MF_DEFAULTED ) ) // we have a parse error
{
return;
}
if( !src.ExpectAnyToken( &token ) )
{
SetMaterialFlag( MF_DEFAULTED );
return;
}
if( !token.Icmp( "}" ) )
{
break;
}
if( !token.Icmp( "Ref" ) )
{
src.ReadTokenOnLine( &token );
if( !token.IsNumeric() )
{
common->Warning( "Material %s expected number for stencil ref value. Got %s", GetName(), token.c_str() );
continue;
}
if( token.GetIntValue() > 255 || token.GetIntValue() < 0 )
{
common->Warning( "Material %s expected stencil ref value between 0 and 255. Got %s", GetName(), token.c_str() );
continue;
}
stencilStage->ref = token.GetIntValue();
continue;
}
if( !token.Icmp( "Comp" ) )
{
src.ReadTokenOnLine( &token );
ParseStencilCompare( token, &stencilStage->comp );
continue;
}
if( !token.Icmp( "Pass" ) )
{
src.ReadTokenOnLine( &token );
ParseStencilOperation( token, &stencilStage->pass );
continue;
}
if( !token.Icmp( "Fail" ) )
{
src.ReadTokenOnLine( &token );
ParseStencilOperation( token, &stencilStage->fail );
continue;
}
if( !token.Icmp( "ZFail" ) )
{
src.ReadTokenOnLine( &token );
ParseStencilOperation( token, &stencilStage->zFail );
continue;
}
common->Warning( "Material %s expected a valid stencil keyword. Got %s.", GetName(), token.c_str() );
}
}
/*
===============
idMaterial::MultiplyTextureMatrix
@ -1400,10 +1613,12 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
textureRepeat_t trp;
textureUsage_t td;
cubeFiles_t cubeMap;
int cubeMapSize = 0; // SP: The size of the cubemap for subimage uploading to the cubemap targets.
char imageName[MAX_IMAGE_NAME];
int a, b;
int matrix[2][3];
newShaderStage_t newStage;
stencilStage_t stencilStage; // SP
if( numStages >= MAX_SHADER_STAGES )
{
@ -1490,6 +1705,30 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
ts->texgen = TG_SCREEN;
continue;
}
if( !token.Icmp( "guiRenderMap" ) )
{
// Emit fullscreen view of the gui to this dynamically generated texture
ts->dynamic = DI_GUI_RENDER;
ts->width = src.ParseInt();
ts->height = src.ParseInt();
continue;
}
#if 0
if( !token.Icmp( "renderTargetMap" ) )
{
// Emit fullscreen view of the gui to this dynamically generated texture
idToken otherMaterialToken;
ts->dynamic = DI_RENDER_TARGET;
src.ReadToken( &otherMaterialToken );
ts->renderTargetMaterial = declManager->FindMaterial( otherMaterialToken.c_str() );
ts->width = src.ParseInt();
ts->height = src.ParseInt();
continue;
}
#endif
if( !token.Icmp( "screen" ) )
{
ts->texgen = TG_SCREEN;
@ -1550,6 +1789,21 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
continue;
}
if( !token.Icmp( "cubeMapSingle" ) )
{
str = R_ParsePastImageProgram( src );
idStr::Copynz( imageName, str, sizeof( imageName ) );
cubeMap = CF_SINGLE;
td = TD_HIGHQUALITY_CUBE;
continue;
}
if( !token.Icmp( "cubeMapSize" ) )
{
cubeMapSize = src.ParseInt();
continue;
}
if( !token.Icmp( "cameraCubeMap" ) )
{
str = R_ParsePastImageProgram( src );
@ -1921,6 +2175,16 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
continue;
}
// SP Begin
if( !token.Icmp( "stencil" ) )
{
ParseStencil( src, &stencilStage );
ss->stencilStage = ( stencilStage_t* )Mem_Alloc( sizeof( stencilStage_t ), TAG_MATERIAL );
*ss->stencilStage = stencilStage;
continue;
}
// SP End
common->Warning( "unknown token '%s' in material '%s'", token.c_str(), GetName() );
SetMaterialFlag( MF_DEFAULTED );
@ -1990,7 +2254,7 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
// now load the image with all the parms we parsed for the coverage stage
if( imageName[0] )
{
coverageTS->image = globalImages->ImageFromFile( imageName, tf, trp, TD_COVERAGE, cubeMap );
coverageTS->image = globalImages->ImageFromFile( imageName, tf, trp, TD_COVERAGE, cubeMap, cubeMapSize );
if( !coverageTS->image )
{
coverageTS->image = globalImages->defaultImage;
@ -2006,7 +2270,7 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
// now load the image with all the parms we parsed
if( imageName[0] )
{
ts->image = globalImages->ImageFromFile( imageName, tf, trp, td, cubeMap );
ts->image = globalImages->ImageFromFile( imageName, tf, trp, td, cubeMap, cubeMapSize );
if( !ts->image )
{
ts->image = globalImages->defaultImage;
@ -2314,7 +2578,6 @@ void idMaterial::ParseMaterial( idLexer& src )
continue;
}
// polygonOffset
else if( !token.Icmp( "polygonOffset" ) )
{
@ -2448,6 +2711,15 @@ void idMaterial::ParseMaterial( idLexer& src )
{
sort = SS_SUBVIEW;
coverage = MC_OPAQUE;
subViewType = SUBVIEW_MIRROR;
continue;
}
// direct portal
else if( !token.Icmp( "directPortal" ) )
{
sort = SS_SUBVIEW;
coverage = MC_OPAQUE;
subViewType = SUBVIEW_DIRECT_PORTAL;
continue;
}
// noFog

View file

@ -5,6 +5,7 @@ Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2020 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -97,7 +98,9 @@ typedef enum
DI_CUBE_RENDER,
DI_MIRROR_RENDER,
DI_XRAY_RENDER,
DI_REMOTE_RENDER
DI_REMOTE_RENDER,
DI_GUI_RENDER,
DI_RENDER_TARGET,
} dynamicidImage_t;
// note: keep opNames[] in sync with changes
@ -205,6 +208,61 @@ typedef enum
SVC_INVERSE_MODULATE
} stageVertexColor_t;
// SP Begin
typedef enum
{
STENCIL_COMP_GREATER,
STENCIL_COMP_GEQUAL,
STENCIL_COMP_LESS,
STENCIL_COMP_LEQUAL,
STENCIL_COMP_EQUAL,
STENCIL_COMP_NOTEQUAL,
STENCIL_COMP_ALWAYS,
STENCIL_COMP_NEVER
} stencilComp_t;
typedef enum
{
STENCIL_OP_KEEP,
STENCIL_OP_ZERO,
STENCIL_OP_REPLACE,
STENCIL_OP_INCRSAT,
STENCIL_OP_DECRSAT,
STENCIL_OP_INVERT,
STENCIL_OP_INCRWRAP,
STENCIL_OP_DECRWRAP
} stencilOperation_t;
typedef struct
{
// The value to be compared against (if Comp is anything else than always) and/or the value to be written to the buffer
// (if either Pass, Fail or ZFail is set to replace).
byte ref = 0;
// An 8 bit mask as an 0255 integer, used when comparing the reference value with the contents of the buffer
// (referenceValue & readMask) comparisonFunction (stencilBufferValue & readMask).
byte readMask = 255;
// An 8 bit mask as an 0255 integer, used when writing to the buffer.Note that, like other write masks,
// it specifies which bits of stencil buffer will be affected by write
// (i.e.WriteMask 0 means that no bits are affected and not that 0 will be written).
byte writeMask = 255;
// Function used to compare the reference value to the current contents of the buffer.
stencilComp_t comp = STENCIL_COMP_ALWAYS;
// What to do with the contents of the buffer if the stencil test(and the depth test) passes.
stencilOperation_t pass = STENCIL_OP_KEEP;
// What to do with the contents of the buffer if the stencil test fails.
stencilOperation_t fail = STENCIL_OP_KEEP;
// What to do with the contents of the buffer if the stencil test passes, but the depth test fails.
stencilOperation_t zFail = STENCIL_OP_KEEP;
} stencilStage_t;
// SP End
static const int MAX_FRAGMENT_IMAGES = 8;
static const int MAX_VERTEX_PARMS = 4;
@ -234,6 +292,7 @@ typedef struct
// if the surface is alpha tested
float privatePolygonOffset; // a per-stage polygon offset
stencilStage_t* stencilStage;
newShaderStage_t* newStage; // vertex / fragment program based stage
} shaderStage_t;
@ -267,6 +326,13 @@ typedef enum
SS_POST_PROCESS = 100 // after a screen copy to texture
} materialSort_t;
enum SubViewType : uint16_t
{
SUBVIEW_NONE,
SUBVIEW_MIRROR,
SUBVIEW_DIRECT_PORTAL
};
typedef enum
{
CT_FRONT_SIDED,
@ -377,6 +443,7 @@ typedef enum
// won't collect light from any angle
} surfaceFlags_t;
class idSoundEmitter;
// RB: predefined Quake 1 light styles
@ -497,6 +564,16 @@ public:
return hasSubview;
}
bool IsPortalSubView() const
{
return subViewType == SubViewType::SUBVIEW_DIRECT_PORTAL;
}
bool IsMirrorSubView() const
{
return subViewType == SubViewType::SUBVIEW_MIRROR;
}
// returns true if the material will generate shadows, not making a
// distinction between global and no-self shadows
bool SurfaceCastsShadow() const
@ -882,6 +959,9 @@ private:
void ParseVertexParm( idLexer& src, newShaderStage_t* newStage );
void ParseVertexParm2( idLexer& src, newShaderStage_t* newStage );
void ParseFragmentMap( idLexer& src, newShaderStage_t* newStage );
void ParseStencilCompare( const idToken& token, stencilComp_t* stencilComp );
void ParseStencilOperation( const idToken& token, stencilOperation_t* stencilOp );
void ParseStencil( idLexer& src, stencilStage_t* stencilStage );
void ParseStage( idLexer& src, const textureRepeat_t trpDefault = TR_REPEAT );
void ParseDeform( idLexer& src );
void ParseDecalInfo( idLexer& src );
@ -939,6 +1019,7 @@ private:
materialCoverage_t coverage;
cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED
SubViewType subViewType; // SP added
bool shouldCreateBackSides;
bool fogLight;

View file

@ -2489,8 +2489,9 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, idList<InputChannel>& pPerIndex
numPrimitives = 1;
}
pMesh->mFaceSize.AssureSize( numPrimitives );
//pMesh->mFacePosIndices.AssureSize( indices.Num() / numOffsets );
const int startFaceSize = pMesh->mFaceSize.Num();
pMesh->mFaceSize.AssureSize( Max( pMesh->mFaceSize.Size(), numPrimitives ) );
size_t appendedVerts = 0;
for( size_t a = 0; a < numPrimitives; a++ )
@ -2519,7 +2520,7 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, idList<InputChannel>& pPerIndex
}
// store the face size to later reconstruct the face from
pMesh->mFaceSize[a] = numPoints;
pMesh->mFaceSize[startFaceSize + a] = numPoints;
// gather that number of vertices
for( size_t b = 0; b < numPoints; b++ )

View file

@ -719,7 +719,6 @@ idRenderModelMD5::LoadBinaryModel
*/
bool idRenderModelMD5::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp )
{
if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) )
{
return false;

View file

@ -455,7 +455,38 @@ void Framebuffer::AddDepthBuffer( int format, int multiSamples )
if( notCreatedYet )
{
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthBuffer );
}
GL_CheckErrors();
}
void Framebuffer::AddStencilBuffer( int format, int multiSamples )
{
stencilFormat = format;
bool notCreatedYet = stencilBuffer == 0;
if( notCreatedYet )
{
glGenRenderbuffers( 1, &stencilBuffer );
}
glBindRenderbuffer( GL_RENDERBUFFER, stencilBuffer );
if( multiSamples > 0 )
{
glRenderbufferStorageMultisample( GL_RENDERBUFFER, multiSamples, format, width, height );
msaaSamples = true;
}
else
{
glRenderbufferStorage( GL_RENDERBUFFER, format, width, height );
}
if( notCreatedYet )
{
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilBuffer );
}
GL_CheckErrors();
@ -486,7 +517,7 @@ void Framebuffer::AttachImageDepth( int target, const idImage* image )
return;
}
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, image->texnum, 0 );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, target, image->texnum, 0 );
}
void Framebuffer::AttachImageDepthLayer( const idImage* image, int layer )

View file

@ -53,6 +53,7 @@ idImage::idImage( const char* name ) : imgName( name )
repeat = TR_REPEAT;
usage = TD_DEFAULT;
cubeFiles = CF_2D;
cubeMapSize = 0;
referencedOutsideLevelLoad = false;
levelLoadReferenced = false;
@ -416,16 +417,6 @@ void idImage::SetSamplerState( textureFilter_t tf, textureRepeat_t tr )
SetTexParameters();
}
/*
========================
idImage::SetPixel
========================
*/
void idImage::SetPixel( int mipLevel, int x, int y, const void* data, int dataSize )
{
SubImageUpload( mipLevel, x, y, 0, 1, 1, data );
}
/*
========================
idImage::SetTexParameters
@ -677,6 +668,12 @@ void idImage::AllocImage()
dataType = GL_UNSIGNED_BYTE;
break;
case FMT_DEPTH_STENCIL:
internalFormat = GL_DEPTH24_STENCIL8;
dataFormat = GL_DEPTH_STENCIL;
dataType = GL_UNSIGNED_INT_24_8;
break;
case FMT_SHADOW_ARRAY:
internalFormat = GL_DEPTH_COMPONENT;
dataFormat = GL_DEPTH_COMPONENT;

View file

@ -2374,6 +2374,14 @@ void idRenderBackend::ImGui_Shutdown()
void idRenderBackend::ImGui_RenderDrawLists( ImDrawData* draw_data )
{
/*
if( draw_data->CmdListsCount == 0 )
{
// Nothing to do.
return;
}
*/
#if IMGUI_BFGUI
tr.guiModel->EmitImGui( draw_data );

View file

@ -220,7 +220,6 @@ void idRenderProgManager::LoadShader( shader_t& shader )
idStr hlslCode( hlslFileBuffer );
idStr programHLSL = StripDeadCode( hlslCode, inFile, compileMacros, shader.builtin );
programGLSL = ConvertCG2GLSL( programHLSL, inFile.c_str(), shader.stage, programUniforms, false, hasGPUSkinning, shader.vertexLayout );
fileSystem->WriteFile( outFileHLSL, programHLSL.c_str(), programHLSL.Length(), "fs_savepath" );
fileSystem->WriteFile( outFileGLSL, programGLSL.c_str(), programGLSL.Length(), "fs_savepath" );
fileSystem->WriteFile( outFileUniforms, programUniforms.c_str(), programUniforms.Length(), "fs_savepath" );

View file

@ -4804,9 +4804,13 @@ void idRenderBackend::Bloom( const viewDef_t* _viewDef )
return;
}
renderLog.OpenMainBlock( MRB_BLOOM );
renderLog.OpenBlock( "Render_Bloom", colorBlue );
RENDERLOG_PRINTF( "---------- RB_Bloom( avg = %f, max = %f, key = %f ) ----------\n", hdrAverageLuminance, hdrMaxLuminance, hdrKey );
// BRIGHTPASS
renderLog.OpenBlock( "Brightpass" );
//GL_CheckErrors();
@ -4887,6 +4891,10 @@ void idRenderBackend::Bloom( const viewDef_t* _viewDef )
// Draw
DrawElementsWithCounters( &unitSquareSurface );
renderLog.CloseBlock(); // Brightpass
renderLog.OpenBlock( "Bloom Ping Pong" );
// BLOOM PING PONG rendering
renderProgManager.BindShader_HDRGlareChromatic();
@ -4918,9 +4926,14 @@ void idRenderBackend::Bloom( const viewDef_t* _viewDef )
DrawElementsWithCounters( &unitSquareSurface );
renderLog.CloseBlock(); // Bloom Ping Pong
renderProgManager.Unbind();
GL_State( GLS_DEFAULT );
renderLog.CloseBlock(); // Render_Bloom
renderLog.CloseMainBlock(); // MRB_BLOOM
}
@ -5027,8 +5040,6 @@ void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef
GL_Viewport( 0, 0, aoScreenWidth, aoScreenHeight );
GL_Scissor( 0, 0, aoScreenWidth, aoScreenHeight );
if( downModulateScreen )
{
if( r_ssaoFiltering.GetBool() )
@ -5294,7 +5305,6 @@ void idRenderBackend::DrawScreenSpaceGlobalIllumination( const viewDef_t* _viewD
glClearColor( 0, 0, 0, 1 );
GL_SelectTexture( 0 );
//globalImages->currentDepthImage->Bind();
for( int i = 0; i < MAX_HIERARCHICAL_ZBUFFERS; i++ )
{
@ -5709,7 +5719,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
//GL_CheckErrors();
#if !defined(USE_VULKAN)
#if !defined( USE_VULKAN ) && !defined( USE_NVRHI )
// bind one global Vertex Array Object (VAO)
glBindVertexArray( glConfig.global_vao );
#endif

View file

@ -605,6 +605,7 @@ struct viewDef_t
bool isEditor;
bool is2Dgui;
bool isObliqueProjection; // true if this view has an oblique projection
int numClipPlanes; // mirrors will often use a single clip plane
idPlane clipPlanes[MAX_CLIP_PLANES]; // in world space, the positive side
// of the plane is the visible side
@ -653,6 +654,8 @@ struct viewDef_t
idImage* irradianceImage; // cubemap image used for diffuse IBL by backend
idImage* radianceImages[3]; // cubemap image used for specular IBL by backend
idVec4 radianceImageBlends; // blending weights
Framebuffer* targetRender; // The framebuffer to render to
};
@ -802,9 +805,6 @@ const idMaterial* R_RemapShaderBySkin( const idMaterial* shader, const idDeclSki
//====================================================
enum vertexLayoutType_t
{
LAYOUT_UNKNOWN = 0, // RB: TODO -1
@ -1188,6 +1188,7 @@ extern idCVar r_shadowMapRegularDepthBiasScale;
extern idCVar r_shadowMapSunDepthBiasScale;
extern idCVar r_hdrAutoExposure;
extern idCVar r_hdrAdaptionRate;
extern idCVar r_hdrMinLuminance;
extern idCVar r_hdrMaxLuminance;
extern idCVar r_hdrKey;
@ -1253,8 +1254,8 @@ struct vidMode_t
// RB begin
vidMode_t()
{
width = 640;
height = 480;
width = SCREEN_WIDTH;
height = SCREEN_HEIGHT;
displayHz = 60;
}
@ -1476,6 +1477,8 @@ TR_FRONTEND_DEFORM
drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf );
drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf, deform_t deformType );
/*
=============================================================

View file

@ -37,7 +37,7 @@ TODO: Emit statistics to the logfile at the end of views and frames.
================================================================================================
*/
idCVar r_logLevel( "r_logLevel", "2", CVAR_INTEGER, "1 = blocks only, 2 = everything", 1, 2 );
idCVar r_logLevel( "r_logLevel", "0", CVAR_INTEGER, "1 = blocks only, 2 = everything", 1, 2 );
static const int LOG_LEVEL_BLOCKS_ONLY = 1;
static const int LOG_LEVEL_EVERYTHING = 2;
@ -53,12 +53,13 @@ const char* renderLogMainBlockLabels[] =
ASSERT_ENUM_STRING( MRB_DRAW_INTERACTIONS, 6 ),
ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES, 7 ),
ASSERT_ENUM_STRING( MRB_FOG_ALL_LIGHTS, 8 ),
ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES_POST, 9 ),
ASSERT_ENUM_STRING( MRB_DRAW_DEBUG_TOOLS, 10 ),
ASSERT_ENUM_STRING( MRB_CAPTURE_COLORBUFFER, 11 ),
ASSERT_ENUM_STRING( MRB_POSTPROCESS, 12 ),
ASSERT_ENUM_STRING( MRB_DRAW_GUI, 13 ),
ASSERT_ENUM_STRING( MRB_TOTAL, 14 )
ASSERT_ENUM_STRING( MRB_BLOOM, 9 ),
ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES_POST, 10 ),
ASSERT_ENUM_STRING( MRB_DRAW_DEBUG_TOOLS, 11 ),
ASSERT_ENUM_STRING( MRB_CAPTURE_COLORBUFFER, 12 ),
ASSERT_ENUM_STRING( MRB_POSTPROCESS, 13 ),
ASSERT_ENUM_STRING( MRB_DRAW_GUI, 14 ),
ASSERT_ENUM_STRING( MRB_TOTAL, 15 )
};
#if defined( USE_VULKAN )
@ -107,6 +108,11 @@ FIXME: this is not thread safe on the PC
*/
void PC_BeginNamedEvent( const char* szName, const idVec4& color )
{
if( r_logLevel.GetInteger() <= 0 )
{
return;
}
#if defined( USE_VULKAN )
// start an annotated group of calls under the this name
@ -190,6 +196,11 @@ PC_EndNamedEvent
*/
void PC_EndNamedEvent()
{
if( r_logLevel.GetInteger() <= 0 )
{
return;
}
#if defined( USE_VULKAN )
// SRS - Prefer VK_EXT_debug_utils over VK_EXT_debug_marker/VK_EXT_debug_report (deprecated by VK_EXT_debug_utils)
if( vkcontext.debugUtilsSupportAvailable )
@ -284,308 +295,7 @@ idRenderLog
idRenderLog renderLog;
#if !defined( STUB_RENDER_LOG )
/*
========================
idRenderLog::idRenderLog
========================
*/
idRenderLog::idRenderLog()
{
activeLevel = 0;
indentString[0] = '\0';
indentLevel = 0;
// logFile = NULL;
frameStartTime = 0;
closeBlockTime = 0;
logLevel = 0;
}
/*
========================
idRenderLog::StartFrame
========================
*/
void idRenderLog::StartFrame()
{
if( r_logFile.GetInteger() == 0 )
{
return;
}
// open a new logfile
indentLevel = 0;
indentString[0] = '\0';
activeLevel = r_logLevel.GetInteger();
/*
struct tm* newtime;
time_t aclock;
char ospath[ MAX_OSPATH ];
char qpath[128];
sprintf( qpath, "renderlogPC_%04i.txt", r_logFile.GetInteger() );
//idStr finalPath = fileSystem->RelativePathToOSPath( qpath );
sprintf( ospath, "%s", qpath );
*/
/*
for ( int i = 0; i < 9999 ; i++ ) {
char qpath[128];
sprintf( qpath, "renderlog_%04i.txt", r_logFile.GetInteger() );
idStr finalPath = fileSystem->RelativePathToOSPath( qpath );
fileSystem->RelativePathToOSPath( qpath, ospath, MAX_OSPATH ,FSPATH_BASE );
if ( !fileSystem->FileExists( finalPath.c_str() ) ) {
break; // use this name
}
}
*/
common->SetRefreshOnPrint( false ); // problems are caused if this print causes a refresh...
/*
if( logFile != NULL )
{
fileSystem->CloseFile( logFile );
logFile = NULL;
}
logFile = fileSystem->OpenFileWrite( ospath );
if( logFile == NULL )
{
idLib::Warning( "Failed to open logfile %s", ospath );
return;
}
idLib::Printf( "Opened logfile %s\n", ospath );
// write the time out to the top of the file
time( &aclock );
newtime = localtime( &aclock );
const char* str = asctime( newtime );
logFile->Printf( "// %s", str );
logFile->Printf( "// %s\n\n", com_version.GetString() );
*/
frameStartTime = Sys_Microseconds();
closeBlockTime = frameStartTime;
OpenBlock( "Frame" );
}
/*
========================
idRenderLog::EndFrame
========================
*/
void idRenderLog::EndFrame()
{
PC_EndFrame();
//if( logFile != NULL )
if( r_logFile.GetInteger() != 0 )
{
if( r_logFile.GetInteger() == 1 )
{
Close();
}
// log is open, so decrement r_logFile and stop if it is zero
//r_logFile.SetInteger( r_logFile.GetInteger() - 1 );
//idLib::Printf( "Frame logged.\n" );
return;
}
}
/*
========================
idRenderLog::Close
========================
*/
void idRenderLog::Close()
{
//if( logFile != NULL )
if( r_logFile.GetInteger() != 0 )
{
CloseBlock();
//idLib::Printf( "Closing logfile\n" );
//fileSystem->CloseFile( logFile );
//logFile = NULL;
activeLevel = 0;
}
}
/*
========================
idRenderLog::OpenMainBlock
========================
*/
void idRenderLog::OpenMainBlock( renderLogMainBlock_t block )
{
}
/*
========================
idRenderLog::CloseMainBlock
========================
*/
void idRenderLog::CloseMainBlock()
{
}
/*
========================
idRenderLog::OpenBlock
========================
*/
void idRenderLog::OpenBlock( const char* label )
{
// Allow the PIX functionality even when logFile is not running.
PC_BeginNamedEvent( label );
//if( logFile != NULL )
if( r_logFile.GetInteger() != 0 )
{
LogOpenBlock( RENDER_LOG_INDENT_MAIN_BLOCK, "%s", label );
}
}
/*
========================
idRenderLog::CloseBlock
========================
*/
void idRenderLog::CloseBlock()
{
PC_EndNamedEvent();
//if( logFile != NULL )
if( r_logFile.GetInteger() != 0 )
{
LogCloseBlock( RENDER_LOG_INDENT_MAIN_BLOCK );
}
}
/*
========================
idRenderLog::Printf
========================
*/
void idRenderLog::Printf( const char* fmt, ... )
{
#if !defined(USE_VULKAN)
if( activeLevel <= LOG_LEVEL_BLOCKS_ONLY )
{
return;
}
//if( logFile == NULL )
if( r_logFile.GetInteger() == 0 || !glConfig.gremedyStringMarkerAvailable )
{
return;
}
va_list marker;
char msg[4096];
idStr out = indentString;
va_start( marker, fmt );
idStr::vsnPrintf( msg, sizeof( msg ), fmt, marker );
va_end( marker );
msg[sizeof( msg ) - 1] = '\0';
out.Append( msg );
glStringMarkerGREMEDY( out.Length(), out.c_str() );
//logFile->Printf( "%s", indentString );
//va_start( marker, fmt );
//logFile->VPrintf( fmt, marker );
//va_end( marker );
// logFile->Flush(); this makes it take waaaay too long
#endif
}
/*
========================
idRenderLog::LogOpenBlock
========================
*/
void idRenderLog::LogOpenBlock( renderLogIndentLabel_t label, const char* fmt, ... )
{
uint64 now = Sys_Microseconds();
//if( logFile != NULL )
if( r_logFile.GetInteger() != 0 )
{
//if( now - closeBlockTime >= 1000 )
//{
//logFile->Printf( "%s%1.1f msec gap from last closeblock\n", indentString, ( now - closeBlockTime ) * ( 1.0f / 1000.0f ) );
//}
#if !defined(USE_VULKAN)
if( glConfig.gremedyStringMarkerAvailable )
{
//Printf( fmt, args );
//Printf( " {\n" );
//logFile->Printf( "%s", indentString );
//logFile->VPrintf( fmt, args );
//logFile->Printf( " {\n" );
va_list marker;
char msg[4096];
idStr out = indentString;
va_start( marker, fmt );
idStr::vsnPrintf( msg, sizeof( msg ), fmt, marker );
va_end( marker );
msg[sizeof( msg ) - 1] = '\0';
out.Append( msg );
out += " {";
glStringMarkerGREMEDY( out.Length(), out.c_str() );
}
#endif
}
Indent( label );
if( logLevel >= MAX_LOG_LEVELS )
{
idLib::Warning( "logLevel %d >= MAX_LOG_LEVELS", logLevel );
}
logLevel++;
}
/*
========================
idRenderLog::LogCloseBlock
========================
*/
void idRenderLog::LogCloseBlock( renderLogIndentLabel_t label )
{
closeBlockTime = Sys_Microseconds();
//assert( logLevel > 0 );
logLevel--;
Outdent( label );
//if( logFile != NULL )
//{
//}
}
#else // !STUB_RENDER_LOG
// RB begin
/*
@ -708,6 +418,4 @@ void idRenderLog::CloseBlock()
{
PC_EndNamedEvent();
}
// RB end
#endif // !STUB_RENDER_LOG
// RB end

View file

@ -35,9 +35,6 @@ Contains the RenderLog declaration.
================================================================================================
*/
#if 1 //defined(ID_RETAIL) && !defined(ID_RETAIL_INTERNAL)
#define STUB_RENDER_LOG
#endif
enum renderLogMainBlock_t
{
@ -51,6 +48,7 @@ enum renderLogMainBlock_t
MRB_DRAW_INTERACTIONS,
MRB_DRAW_SHADER_PASSES,
MRB_FOG_ALL_LIGHTS,
MRB_BLOOM,
MRB_DRAW_SHADER_PASSES_POST,
MRB_DRAW_DEBUG_TOOLS,
MRB_CAPTURE_COLORBUFFER,
@ -73,102 +71,7 @@ enum renderLogIndentLabel_t
// using this macro avoids printf parameter overhead if the renderlog isn't active
#define RENDERLOG_PRINTF( ... ) if ( renderLog.activeLevel ) renderLog.Printf( __VA_ARGS__ );
#if !defined( STUB_RENDER_LOG )
/*
================================================
idRenderLog contains block-based performance-tuning information. It combines
logfile, and msec accumulation code.
================================================
*/
class idRenderLog
{
public:
idRenderLog();
void StartFrame();
void EndFrame();
void Close();
int Active()
{
return activeLevel; // returns greater than 1 for more detailed logging
}
// The label must be a constant string literal and may not point to a temporary.
void OpenMainBlock( renderLogMainBlock_t block );
void CloseMainBlock();
void OpenBlock( const char* label );
void CloseBlock();
void Indent( renderLogIndentLabel_t label = RENDER_LOG_INDENT_DEFAULT );
void Outdent( renderLogIndentLabel_t label = RENDER_LOG_INDENT_DEFAULT );
void Printf( VERIFY_FORMAT_STRING const char* fmt, ... );
static const int MAX_LOG_LEVELS = 20;
int activeLevel;
renderLogIndentLabel_t indentLabel[MAX_LOG_LEVELS];
char indentString[MAX_LOG_LEVELS * 4];
int indentLevel;
const char* lastLabel;
renderLogMainBlock_t lastMainBlock;
// idFile* logFile;
struct logStats_t
{
uint64 startTiming;
int startDraws;
int startIndexes;
};
uint64 frameStartTime;
uint64 closeBlockTime;
logStats_t logStats[MAX_LOG_LEVELS];
int logLevel;
void LogOpenBlock( renderLogIndentLabel_t label, const char* fmt, ... );
void LogCloseBlock( renderLogIndentLabel_t label );
};
/*
========================
idRenderLog::Indent
========================
*/
ID_INLINE void idRenderLog::Indent( renderLogIndentLabel_t label )
{
//if( logFile != NULL )
if( r_logFile.GetInteger() != 0 )
{
indentLabel[indentLevel] = label;
indentLevel++;
for( int i = 4; i > 0; i-- )
{
indentString[indentLevel * 4 - i] = ' ';
}
indentString[indentLevel * 4] = '\0';
}
}
/*
========================
idRenderLog::Outdent
========================
*/
ID_INLINE void idRenderLog::Outdent( renderLogIndentLabel_t label )
{
//if( logFile != NULL && indentLevel > 0 )
if( r_logFile.GetInteger() != 0 && indentLevel > 0 )
{
indentLevel--;
assert( indentLabel[indentLevel] == label ); // indent and outdent out of sync ?
indentString[indentLevel * 4] = '\0';
}
}
#else // !STUB_RENDER_LOG
/*
================================================
@ -207,8 +110,6 @@ public:
int activeLevel;
};
#endif // !STUB_RENDER_LOG
extern idRenderLog renderLog;
#endif // !__RENDERLOG_H__

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2016 Robert Beckebans
Copyright (C) 2014-2021 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").

View file

@ -1074,6 +1074,7 @@ void idRenderWorldLocal::RenderScene( const renderView_t* renderView )
// setup view parms for the initial view
viewDef_t* parms = ( viewDef_t* )R_ClearedFrameAlloc( sizeof( *parms ), FRAME_ALLOC_VIEW_DEF );
parms->renderView = *renderView;
parms->targetRender = nullptr;
if( tr.takingScreenshot )
{
@ -1102,6 +1103,7 @@ void idRenderWorldLocal::RenderScene( const renderView_t* renderView )
parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
parms->isSubview = false;
parms->isObliqueProjection = false;
parms->initialViewAreaOrigin = renderView->vieworg;
parms->renderWorld = this;

View file

@ -719,7 +719,7 @@ void idRenderWorldLocal::WriteRenderLight( idDemoFile* f, qhandle_t handle, cons
ReadRenderLight
================
*/
void idRenderWorldLocal::ReadRenderLight( )
void idRenderWorldLocal::ReadRenderLight()
{
renderLight_t light;
int index, i;

View file

@ -78,6 +78,7 @@ static VkFormat VK_GetFormatFromTextureFormat( const textureFormat_t format )
case FMT_DXT5:
return VK_FORMAT_BC3_UNORM_BLOCK;
case FMT_DEPTH:
case FMT_DEPTH_STENCIL:
return vkcontext.depthFormat;
case FMT_X16:
return VK_FORMAT_R16_UNORM;

View file

@ -386,6 +386,8 @@ static void R_AddSingleLight( viewLight_t* vLight )
vLight->entityInteractionState[ edef->index ] = viewLight_t::INTERACTION_NO;
// The table is updated at interaction::AllocAndLink() and interaction::UnlinkAndFree()
// TODO(Stephen): interactionTableRow is null if renderDef is used in a gui.sub
const idInteraction* inter = interactionTableRow[ edef->index ];
const renderEntity_t& eParms = edef->parms;

View file

@ -1133,11 +1133,21 @@ drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf )
return NULL;
}
return R_DeformDrawSurf( drawSurf, drawSurf->material->Deform() );
}
/*
=================
R_DeformDrawSurf
=================
*/
drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf, deform_t deformType )
{
if( r_skipDeforms.GetBool() )
{
return drawSurf;
}
switch( drawSurf->material->Deform() )
switch( deformType )
{
case DFRM_SPRITE:
return R_AutospriteDeform( drawSurf );
@ -1160,4 +1170,4 @@ drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf )
default:
return NULL;
}
}
}

View file

@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014 Robert Beckebans
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -228,6 +229,7 @@ static viewDef_t* R_MirrorViewBySurface( const drawSurf_t* drawSurf )
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->targetRender = nullptr;
parms->isSubview = true;
parms->isMirror = true;
@ -271,6 +273,97 @@ static viewDef_t* R_MirrorViewBySurface( const drawSurf_t* drawSurf )
return parms;
}
/*
========================
R_PortalViewBySurface
========================
*/
static viewDef_t* R_PortalViewBySurface( const drawSurf_t* surf )
{
if( !surf->space->entityDef->parms.remoteRenderView )
{
return nullptr;
}
// copy the viewport size from the original
viewDef_t* parms = ( viewDef_t* )R_FrameAlloc( sizeof( *parms ) );
*parms = *tr.viewDef;
idMat3 viewaxis = parms->renderView.viewaxis;
idMat3 remoteViewAxis = surf->space->entityDef->parms.remoteRenderView->viewaxis;
const idVec3 orig = parms->renderView.vieworg;
float fov_x = parms->renderView.fov_x;
float fov_y = parms->renderView.fov_y;
parms->renderView = *surf->space->entityDef->parms.remoteRenderView;
parms->renderView.fov_x = fov_x;
parms->renderView.fov_y = fov_y;
idAngles ang = viewaxis.ToAngles();
idAngles angleDiff;
idMat3 surfViewAxis;
// Difference in view axis
idPlane originalPlane, plane;
R_PlaneForSurface( surf->frontEndGeo, originalPlane );
R_LocalPlaneToGlobal( surf->space->modelMatrix, originalPlane, plane );
orientation_t surface;
surface.origin = plane.Normal() * -plane[3];
surface.axis[0] = plane.Normal();
surface.axis[0].NormalVectors( surface.axis[1], surface.axis[2] );
surface.axis[2] = -surface.axis[2];
surfViewAxis = surface.axis;
idAngles surfAng = surfViewAxis.ToAngles();
angleDiff = surfAng - ang;
idAngles origAngle = parms->renderView.viewaxis.ToAngles();
origAngle = origAngle - angleDiff;
origAngle.yaw -= 180;
origAngle.Normalize180();
parms->renderView.viewaxis = origAngle.ToMat3();
// Direction vector in camera space.
const idMat3 inverseSurfView = surfViewAxis.Transpose();
idVec3 dirToPortal = ( surf->space->entityDef->parms.origin - orig ) * inverseSurfView;
dirToPortal.z = -dirToPortal.z;
parms->renderView.vieworg += dirToPortal * remoteViewAxis;
// Set up oblique view clipping plane
parms->numClipPlanes = 1;
parms->clipPlanes[0] = remoteViewAxis[0];
parms->clipPlanes[0][3] = -( surf->space->entityDef->parms.remoteRenderView->vieworg * parms->clipPlanes[0].Normal() );
float dist = parms->clipPlanes[0].Dist();
float viewdist = parms->renderView.vieworg * parms->clipPlanes[0].Normal();
float fDist = -dist + viewdist;
// fudge avoids depth precision artifacts when performing oblique projection
static const float fudge = 2.f;
if( fDist > fudge || fDist < -fudge )
{
if( fDist < 0.f )
{
fDist += fudge;
}
else
{
fDist -= fudge;
}
}
parms->clipPlanes[0][3] = fDist;
parms->isObliqueProjection = true;
parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
parms->initialViewAreaOrigin = parms->renderView.vieworg;
parms->isSubview = true;
parms->isMirror = false;
return parms;
}
/*
========================
R_XrayViewBySurface
@ -519,29 +612,54 @@ bool R_GenerateSurfaceSubview( const drawSurf_t* drawSurf )
case DI_XRAY_RENDER:
R_XrayRender( drawSurf, const_cast<textureStage_t*>( &stage->texture ), scissor );
break;
case DI_GUI_RENDER:
case DI_RENDER_TARGET:
return false;
}
}
return true;
}
// issue a new view command
parms = R_MirrorViewBySurface( drawSurf );
if( parms == NULL )
if( shader->IsMirrorSubView() )
{
return false;
// issue a new view command
parms = R_MirrorViewBySurface( drawSurf );
if( parms == NULL )
{
return false;
}
parms->scissor = scissor;
parms->superView = tr.viewDef;
parms->subviewSurface = drawSurf;
// triangle culling order changes with mirroring
parms->isMirror = ( ( ( int )parms->isMirror ^ ( int )tr.viewDef->isMirror ) != 0 );
// generate render commands for it
R_RenderView( parms );
return true;
}
else if( shader->IsPortalSubView() )
{
parms = R_PortalViewBySurface( drawSurf );
if( parms == nullptr )
{
return false;
}
parms->scissor = scissor;
parms->superView = tr.viewDef;
parms->subviewSurface = drawSurf;
R_RenderView( parms );
return true;
}
parms->scissor = scissor;
parms->superView = tr.viewDef;
parms->subviewSurface = drawSurf;
// triangle culling order changes with mirroring
parms->isMirror = ( ( ( int )parms->isMirror ^ ( int )tr.viewDef->isMirror ) != 0 );
// generate render commands for it
R_RenderView( parms );
return true;
return false;
}
/*

View file

@ -1,5 +1,5 @@
REM 7z a RBDOOM-3-BFG-1.3.1.1-lite-win64-20220109-git-xxxxxxx.7z -r base/env/ base/maps/*.lightgrid base/maps/*_extra_ents.map -x!generated
set filename=RBDOOM-3-BFG-1.4.0.7-lite-win64-20220302-git-xxxxxxx.7z
set filename=RBDOOM-3-BFG-1.4.0.8-lite-win64-20220305-git-xxxxxxx.7z
7z a %filename% README.md RELEASE-NOTES.md base/devtools.cfg base/modelviewer.cfg base/extract_resources.cfg base/convert_maps_to_valve220.cfg base/def/*.def base/materials/*.mtr base/textures/common base/textures/editor base/maps/zoomaps -x!generated -xr!autosave -xr!*.xcf -xr!*.blend
7z a %filename% README.md RELEASE-NOTES.md base/_tb/fgd/*.fgd
7z a %filename% README.md RELEASE-NOTES.md tools/trenchbroom -xr!TrenchBroom-nomanual* -xr!TrenchBroom.pdb