Skip to content

Commit 1f1f6ea

Browse files
committed
renderer: implement native sRGB support
1 parent 430b387 commit 1f1f6ea

File tree

9 files changed

+238
-17
lines changed

9 files changed

+238
-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: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,14 @@ 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+
}
461+
454462
int len = l->filelen;
455463
if ( !len )
456464
{
@@ -493,7 +501,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
493501
LoadRGBEToBytes( va( "%s/%s", mapName, filename.c_str() ), &ldrImage, &width, &height );
494502

495503
imageParams_t imageParams = {};
496-
imageParams.bits = IF_NOPICMIP | IF_LIGHTMAP;
504+
imageParams.bits = lightmapBits;
497505
imageParams.filterType = filterType_t::FT_DEFAULT;
498506
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
499507

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

522530
imageParams_t imageParams = {};
523-
imageParams.bits = IF_NOPICMIP | IF_NORMALMAP;
531+
imageParams.bits = deluxemapBits;
524532
imageParams.filterType = filterType_t::FT_DEFAULT;
525533
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
526534

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

550558
if (!tr.worldDeluxeMapping || i % 2 == 0) {
551559
imageParams_t imageParams = {};
552-
imageParams.bits = IF_NOPICMIP | IF_LIGHTMAP;
560+
imageParams.bits = lightmapBits;
553561
imageParams.filterType = filterType_t::FT_LINEAR;
554562
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
555563

@@ -559,7 +567,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
559567
else if (tr.worldDeluxeMapping)
560568
{
561569
imageParams_t imageParams = {};
562-
imageParams.bits = IF_NOPICMIP | IF_NORMALMAP;
570+
imageParams.bits = deluxemapBits;
563571
imageParams.filterType = filterType_t::FT_LINEAR;
564572
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
565573

@@ -629,7 +637,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName )
629637
}
630638

631639
imageParams_t imageParams = {};
632-
imageParams.bits = IF_NOPICMIP | IF_LIGHTMAP;
640+
imageParams.bits = lightmapBits;
633641
imageParams.filterType = filterType_t::FT_DEFAULT;
634642
imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP;
635643

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

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

983+
if ( tr.worldLinearizeLightMap )
984+
{
985+
cv->verts[ i ].lightColor.ConvertFromSRGB();
986+
}
987+
975988
if ( tr.overbrightBits < tr.mapOverBrightBits ) {
976989
R_ColorShiftLightingBytes( cv->verts[ i ].lightColor.ToArray() );
977990
}
@@ -3502,6 +3515,12 @@ void R_LoadLightGrid( lump_t *l )
35023515
{
35033516
ambientColor[ j ] = tmpAmbient[ j ] * ( 1.0f / 255.0f );
35043517
directedColor[ j ] = tmpDirected[ j ] * ( 1.0f / 255.0f );
3518+
3519+
if ( tr.worldLinearizeLightMap )
3520+
{
3521+
ambientColor[ j ] = convertFromSRGB( ambientColor[ j ] );
3522+
directedColor[ j ] = convertFromSRGB( directedColor[ j ] );
3523+
}
35053524
}
35063525

35073526
const float forceAmbient = r_forceAmbient.Get();
@@ -3766,6 +3785,70 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities )
37663785
tr.worldDeluxeMapping = glConfig2.deluxeMapping;
37673786
}
37683787

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

@@ -4517,6 +4600,8 @@ void RE_LoadWorldMap( const char *name )
45174600
tr.overbrightBits = std::min( tr.mapOverBrightBits, r_overbrightBits.Get() ); // set by RE_LoadWorldMap
45184601
tr.mapLightFactor = 1.0f; // set by RE_LoadWorldMap
45194602
tr.identityLight = 1.0f; // set by RE_LoadWorldMap
4603+
tr.worldLinearizeTexture = false;
4604+
tr.worldLinearizeLightMap = false;
45204605

45214606
s_worldData = {};
45224607
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)