Skip to content

Commit 2c59f4f

Browse files
committed
renderer: implement native sRGB support
1 parent 769e8e9 commit 2c59f4f

File tree

9 files changed

+247
-17
lines changed

9 files changed

+247
-17
lines changed

src/common/Color.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3838
#include "Compiler.h"
3939
#include "Math.h"
4040

41+
#define convertFromSRGB( v ) (v <= 0.04045f ? v * (1.0f / 12.92f) : pow((v + 0.055f) * (1.0f / 1.055f), 2.4f))
42+
4143
namespace Color {
4244

4345
/*
@@ -256,6 +258,20 @@ class BasicColor
256258
data_[ 3 ] = v;
257259
}
258260

261+
CONSTEXPR_FUNCTION_RELAXED component_type ConvertFromSRGB( component_type v ) NOEXCEPT
262+
{
263+
float f = float( v ) / 255.0f;
264+
f = convertFromSRGB( f );
265+
return component_type( f * 255 );
266+
}
267+
268+
CONSTEXPR_FUNCTION_RELAXED void ConvertFromSRGB() NOEXCEPT
269+
{
270+
SetRed( ConvertFromSRGB( Red() ) );
271+
SetGreen( ConvertFromSRGB( Green() ) );
272+
SetBlue( ConvertFromSRGB( Blue() ) );
273+
}
274+
259275
CONSTEXPR_FUNCTION_RELAXED BasicColor& operator*=( float factor ) NOEXCEPT
260276
{
261277
*this = *this * factor;

src/engine/renderer/tr_backend.cpp

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,78 @@ void GL_VertexAttribPointers( uint32_t attribBits )
707707
}
708708
}
709709

710+
GLint GL_ToSRGB_( GLint internalFormat, bool isSRGB )
711+
{
712+
if ( !isSRGB )
713+
{
714+
return internalFormat;
715+
}
716+
717+
switch ( internalFormat )
718+
{
719+
case GL_RGB:
720+
return GL_SRGB;
721+
case GL_RGBA:
722+
return GL_SRGB_ALPHA;
723+
case GL_RGB8:
724+
return GL_SRGB8;
725+
case GL_RGBA8:
726+
return GL_SRGB8_ALPHA8;
727+
// not used
728+
// case GL_COMPRESSED_RGB:
729+
// return GL_COMPRESSED_SRGB;
730+
case GL_COMPRESSED_RGBA:
731+
return GL_COMPRESSED_SRGB_ALPHA;
732+
// not used, core 4.2, ARB_texture_compression_bptc
733+
// case GL_COMPRESSED_RGBA_BPTC_UNORM:
734+
// return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
735+
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
736+
return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
737+
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
738+
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
739+
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
740+
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
741+
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
742+
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
743+
default:
744+
return internalFormat;
745+
}
746+
}
747+
748+
GLint GL_ToSRGB( GLint internalFormat, bool isSRGB )
749+
{
750+
GLint finalFormat = GL_ToSRGB_( internalFormat, isSRGB );
751+
752+
if ( isSRGB )
753+
{
754+
if ( finalFormat == internalFormat )
755+
{
756+
Log::Warn( "Missing sRGB conversion for GL format: %0#x", internalFormat );
757+
}
758+
else
759+
{
760+
Log::Debug( "Using sRGB GL format: %0#x", finalFormat );
761+
}
762+
}
763+
764+
return finalFormat;
765+
}
766+
767+
void GL_TexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * data, bool isSRGB )
768+
{
769+
GLint finalFormat = GL_ToSRGB( internalFormat, isSRGB );
770+
771+
glTexImage2D( target, level, finalFormat, width, height, border, format, type, data );
772+
773+
}
774+
775+
void GL_TexImage3D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * data, bool isSRGB )
776+
{
777+
GLint finalFormat = GL_ToSRGB( internalFormat, isSRGB );
778+
779+
glTexImage3D( target, level, finalFormat, width, height, depth, border, format, type, data );
780+
}
781+
710782
/*
711783
================
712784
RB_Hyperspace
@@ -1289,7 +1361,9 @@ void RB_RenderGlobalFog()
12891361
void RB_RenderBloom()
12901362
{
12911363
if ( ( backEnd.refdef.rdflags & ( RDF_NOWORLDMODEL | RDF_NOBLOOM ) )
1292-
|| !glConfig2.bloom || backEnd.viewParms.portalLevel > 0 ) {
1364+
|| !glConfig2.bloom || backEnd.viewParms.portalLevel > 0
1365+
|| !tr.worldLinearizeTexture )
1366+
{
12931367
return;
12941368
}
12951369

src/engine/renderer/tr_bsp.cpp

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,15 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
451451
return;
452452
}
453453

454+
int lightmapBits = IF_LIGHTMAP | IF_NOPICMIP;
455+
int deluxemapBits = IF_NORMALMAP | IF_NOPICMIP;
456+
457+
if ( tr.worldLinearizeLightMap )
458+
{
459+
lightmapBits |= IF_SRGB;
460+
deluxemapBits |= IF_SRGB;
461+
}
462+
454463
int len = l->filelen;
455464
if ( !len )
456465
{
@@ -493,7 +502,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
493502
LoadRGBEToBytes( va( "%s/%s", mapName, filename.c_str() ), &ldrImage, &width, &height );
494503

495504
imageParams_t imageParams = {};
496-
imageParams.bits = IF_NOPICMIP | IF_LIGHTMAP;
505+
imageParams.bits = lightmapBits;
497506
imageParams.filterType = filterType_t::FT_DEFAULT;
498507
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
499508

@@ -520,7 +529,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
520529
Log::Debug("...loading external lightmap '%s/%s'", mapName, filename);
521530

522531
imageParams_t imageParams = {};
523-
imageParams.bits = IF_NOPICMIP | IF_NORMALMAP;
532+
imageParams.bits = deluxemapBits;
524533
imageParams.filterType = filterType_t::FT_DEFAULT;
525534
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
526535

@@ -549,7 +558,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
549558

550559
if (!tr.worldDeluxeMapping || i % 2 == 0) {
551560
imageParams_t imageParams = {};
552-
imageParams.bits = IF_NOPICMIP | IF_LIGHTMAP;
561+
imageParams.bits = lightmapBits;
553562
imageParams.filterType = filterType_t::FT_LINEAR;
554563
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
555564

@@ -559,7 +568,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
559568
else if (tr.worldDeluxeMapping)
560569
{
561570
imageParams_t imageParams = {};
562-
imageParams.bits = IF_NOPICMIP | IF_NORMALMAP;
571+
imageParams.bits = deluxemapBits;
563572
imageParams.filterType = filterType_t::FT_LINEAR;
564573
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
565574

@@ -629,7 +638,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
629638
}
630639

631640
imageParams_t imageParams = {};
632-
imageParams.bits = IF_NOPICMIP | IF_LIGHTMAP;
641+
imageParams.bits = lightmapBits;
633642
imageParams.filterType = filterType_t::FT_DEFAULT;
634643
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
635644

@@ -972,6 +981,11 @@ static void ParseTriangleSurface( dsurface_t* ds, drawVert_t* verts, bspSurface_
972981

973982
cv->verts[ i ].lightColor = Color::Adapt( verts[ i ].color );
974983

984+
if ( tr.worldLinearizeLightMap )
985+
{
986+
cv->verts[ i ].lightColor.ConvertFromSRGB();
987+
}
988+
975989
if ( tr.overbrightBits < tr.mapOverBrightBits ) {
976990
R_ColorShiftLightingBytes( cv->verts[ i ].lightColor.ToArray() );
977991
}
@@ -3502,6 +3516,12 @@ void R_LoadLightGrid( lump_t *l )
35023516
{
35033517
ambientColor[ j ] = tmpAmbient[ j ] * ( 1.0f / 255.0f );
35043518
directedColor[ j ] = tmpDirected[ j ] * ( 1.0f / 255.0f );
3519+
3520+
if ( tr.worldLinearizeLightMap )
3521+
{
3522+
ambientColor[ j ] = convertFromSRGB( ambientColor[ j ] );
3523+
directedColor[ j ] = convertFromSRGB( directedColor[ j ] );
3524+
}
35053525
}
35063526

35073527
const float forceAmbient = r_forceAmbient.Get();
@@ -3766,6 +3786,70 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities )
37663786
tr.worldDeluxeMapping = glConfig2.deluxeMapping;
37673787
}
37683788

3789+
bool sRGBtex = false;
3790+
bool sRGBcolor = false;
3791+
bool sRGBlight = false;
3792+
3793+
s = strstr( value, "-sRGB" );
3794+
3795+
if ( s && ( s[5] == ' ' || s[5] == '\0' ) )
3796+
{
3797+
sRGBtex = true;
3798+
sRGBcolor = true;
3799+
sRGBlight = true;
3800+
}
3801+
3802+
s = strstr( value, "-nosRGB" );
3803+
3804+
if ( s && ( s[5] == ' ' || s[5] == '\0' ) )
3805+
{
3806+
sRGBtex = false;
3807+
sRGBcolor = false;
3808+
sRGBlight = true;
3809+
}
3810+
3811+
if ( strstr( value, "-sRGBlight" ) )
3812+
{
3813+
sRGBlight = true;
3814+
}
3815+
3816+
if ( strstr( value, "-nosRGBlight" ) )
3817+
{
3818+
sRGBlight = false;
3819+
}
3820+
3821+
if ( strstr( value, "-sRGBcolor" ) )
3822+
{
3823+
sRGBcolor = true;
3824+
}
3825+
3826+
if ( strstr( value, "-nosRGBcolor" ) )
3827+
{
3828+
sRGBcolor = false;
3829+
}
3830+
3831+
if ( strstr( value, "-sRGBtex" ) )
3832+
{
3833+
sRGBtex = true;
3834+
}
3835+
3836+
if ( strstr( value, "-nosRGBtex" ) )
3837+
{
3838+
sRGBtex = false;
3839+
}
3840+
3841+
if ( sRGBlight )
3842+
{
3843+
Log::Debug("map features lights in sRGB colorspace" );
3844+
tr.worldLinearizeLightMap = true;
3845+
}
3846+
3847+
if ( sRGBcolor && sRGBtex )
3848+
{
3849+
Log::Debug("map features lights computed with linear colors and textures" );
3850+
tr.worldLinearizeTexture = true;
3851+
}
3852+
37693853
continue;
37703854
}
37713855

@@ -4517,6 +4601,8 @@ void RE_LoadWorldMap( const char *name )
45174601
tr.overbrightBits = std::min( tr.mapOverBrightBits, r_overbrightBits.Get() ); // set by RE_LoadWorldMap
45184602
tr.mapLightFactor = 1.0f; // set by RE_LoadWorldMap
45194603
tr.identityLight = 1.0f; // set by RE_LoadWorldMap
4604+
tr.worldLinearizeTexture = false;
4605+
tr.worldLinearizeLightMap = false;
45204606

45214607
s_worldData = {};
45224608
Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );

src/engine/renderer/tr_image.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int
838838
GLenum target;
839839
GLenum format = GL_RGBA;
840840
GLenum internalFormat = GL_RGB;
841+
bool isSRGB = image->bits & IF_SRGB;
841842

842843
static const vec4_t oneClampBorder = { 1, 1, 1, 1 };
843844
static const vec4_t zeroClampBorder = { 0, 0, 0, 1 };
@@ -1076,9 +1077,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int
10761077
mipLayers = numLayers;
10771078

10781079
for( i = 0; i < numMips; i++ ) {
1079-
glTexImage3D( GL_TEXTURE_3D, i, internalFormat,
1080-
scaledWidth, scaledHeight, mipLayers,
1081-
0, format, GL_UNSIGNED_BYTE, nullptr );
1080+
GL_TexImage3D( GL_TEXTURE_3D, i, internalFormat, scaledWidth, scaledHeight, mipLayers, 0, format, GL_UNSIGNED_BYTE, nullptr, isSRGB );
10821081

10831082
if( mipWidth > 1 ) mipWidth >>= 1;
10841083
if( mipHeight > 1 ) mipHeight >>= 1;
@@ -1144,18 +1143,17 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int
11441143
}
11451144
break;
11461145
case GL_TEXTURE_CUBE_MAP:
1147-
glTexImage2D( target + i, 0, internalFormat, scaledWidth, scaledHeight, 0, format, GL_UNSIGNED_BYTE,
1148-
scaledBuffer );
1146+
GL_TexImage2D( target + i, 0, internalFormat, scaledWidth, scaledHeight, 0, format, GL_UNSIGNED_BYTE, scaledBuffer, isSRGB );
11491147
break;
11501148

11511149
default:
11521150
if ( image->bits & IF_PACKED_DEPTH24_STENCIL8 )
11531151
{
1154-
glTexImage2D( target, 0, internalFormat, scaledWidth, scaledHeight, 0, format, GL_UNSIGNED_INT_24_8, nullptr );
1152+
GL_TexImage2D( target, 0, internalFormat, scaledWidth, scaledHeight, 0, format, GL_UNSIGNED_INT_24_8, nullptr, isSRGB );
11551153
}
11561154
else
11571155
{
1158-
glTexImage2D( target, 0, internalFormat, scaledWidth, scaledHeight, 0, format, GL_UNSIGNED_BYTE, scaledBuffer );
1156+
GL_TexImage2D( target, 0, internalFormat, scaledWidth, scaledHeight, 0, format, GL_UNSIGNED_BYTE, scaledBuffer, isSRGB );
11591157
}
11601158

11611159
break;
@@ -1511,7 +1509,9 @@ image_t *R_CreateGlyph( const char *name, const byte *pic, int width, int height
15111509
image->uploadHeight = height;
15121510
image->internalFormat = GL_RGBA;
15131511

1514-
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pic );
1512+
bool isSRGB = true;
1513+
1514+
GL_TexImage2D( GL_TEXTURE_2D, 0, image->internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pic, isSRGB );
15151515

15161516
GL_CheckErrors();
15171517

@@ -2734,7 +2734,7 @@ static void R_CreateColorGradeImage()
27342734
}
27352735

27362736
imageParams_t imageParams = {};
2737-
imageParams.bits = IF_NOPICMIP;
2737+
imageParams.bits = IF_NOPICMIP | IF_SRGB;
27382738
imageParams.filterType = filterType_t::FT_LINEAR;
27392739
imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP;
27402740

@@ -3007,7 +3007,7 @@ qhandle_t RE_GenerateTexture( const byte *pic, int width, int height )
30073007
std::string name = Str::Format( "$generatedTexture%d", tr.numGeneratedTextures++ );
30083008

30093009
imageParams_t imageParams = {};
3010-
imageParams.bits = IF_NOPICMIP;
3010+
imageParams.bits = IF_NOPICMIP | IF_SRGB;
30113011
imageParams.filterType = filterType_t::FT_LINEAR;
30123012
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
30133013

src/engine/renderer/tr_init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
869869
GL_fboShim.glBindRenderbuffer( GL_RENDERBUFFER, 0 );
870870
glState.currentFBO = nullptr;
871871

872+
glEnable( GL_FRAMEBUFFER_SRGB );
873+
872874
GL_PolygonMode( GL_FRONT_AND_BACK, GL_FILL );
873875
GL_DepthMask( GL_TRUE );
874876
glDisable( GL_DEPTH_TEST );

src/engine/renderer/tr_local.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ enum class ssaoMode {
475475
IF_RGBE = BIT( 15 ),
476476
IF_ALPHATEST = BIT( 16 ), // FIXME: this is unused
477477
IF_ALPHA = BIT( 17 ),
478+
IF_SRGB = BIT( 18 ),
478479
IF_BC1 = BIT( 19 ),
479480
IF_BC2 = BIT( 20 ),
480481
IF_BC3 = BIT( 21 ),
@@ -1146,6 +1147,7 @@ enum class ssaoMode {
11461147

11471148
expression_t deformMagnitudeExp;
11481149

1150+
bool specularSRGB;
11491151
bool noFog; // used only for shaders that have fog disabled, so we can enable it for individual stages
11501152

11511153
bool useMaterialSystem = false;
@@ -2513,6 +2515,8 @@ enum class ssaoMode {
25132515
bool worldLightMapping;
25142516
bool worldDeluxeMapping;
25152517
bool worldHDR_RGBE;
2518+
bool worldLinearizeTexture;
2519+
bool worldLinearizeLightMap;
25162520

25172521
lightMode_t lightMode;
25182522
lightMode_t worldLight;
@@ -3020,6 +3024,9 @@ inline bool checkGLErrors()
30203024
void GL_VertexAttribsState( uint32_t stateBits );
30213025
void GL_VertexAttribPointers( uint32_t attribBits );
30223026
void GL_Cull( cullType_t cullType );
3027+
GLint GL_ToSRGB( GLint internalFormat, bool isSRGB );
3028+
void GL_TexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * data, bool isSRGB );
3029+
void GL_TexImage3D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * data, bool isSRGB );
30233030
void R_ShutdownBackend();
30243031

30253032
/*

0 commit comments

Comments
 (0)