From 3558031f52b2116fbf2bf4ef4660ec2576fbf831 Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 31 Jan 2010 19:05:20 +0000 Subject: [PATCH] added r_texture_convertsRGB_* cvars (default: OFF) which allow automatic conversion of sRGB textures to linear at load (only affects external textures - anything embedded in q1 formats is untouched because they were authored in linear) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9900 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_particles.c | 2 +- gl_draw.c | 8 ++++---- gl_rmain.c | 29 ++++++++++++++++++++--------- image.c | 28 ++++++++++++++++++++++++---- image.h | 4 ++-- jpeg.c | 2 +- model_brush.c | 6 +++--- r_sky.c | 8 ++++---- render.h | 6 ++++++ 9 files changed, 65 insertions(+), 28 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index eb850f06..5e17b0c2 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -2085,7 +2085,7 @@ static void R_InitParticleTexture (void) } #ifndef DUMPPARTICLEFONT - particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR, true); + particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR, true, r_texture_convertsRGB_particles.integer); if (!particletexture[tex_beam].texture) #endif { diff --git a/gl_draw.c b/gl_draw.c index 2675d414..19a52ed8 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -355,9 +355,9 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT); // load a high quality image from disk if possible - pixels = loadimagepixelsbgra(path, false, true); + pixels = loadimagepixelsbgra(path, false, true, r_texture_convertsRGB_2d.integer); if (pixels == NULL && !strncmp(path, "gfx/", 4)) - pixels = loadimagepixelsbgra(path+4, false, true); + pixels = loadimagepixelsbgra(path+4, false, true, r_texture_convertsRGB_2d.integer); if (pixels) { pic->width = image_width; @@ -443,9 +443,9 @@ rtexture_t *Draw_GetPicTexture(cachepic_t *pic) { if (pic->autoload && !pic->tex) { - pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true); + pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true, r_texture_convertsRGB_2d.integer); if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4)) - pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true); + pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true, r_texture_convertsRGB_2d.integer); if (pic->tex == NULL) pic->tex = draw_generatepic(pic->name, true); } diff --git a/gl_rmain.c b/gl_rmain.c index 11b2d3a7..ba4911de 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -112,6 +112,12 @@ cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the re cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"}; cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"}; +cvar_t r_texture_convertsRGB_2d = {0, "r_texture_convertsRGB_2d", "0", "load textures as sRGB and convert to linear for proper shading"}; +cvar_t r_texture_convertsRGB_skin = {0, "r_texture_convertsRGB_skin", "0", "load textures as sRGB and convert to linear for proper shading"}; +cvar_t r_texture_convertsRGB_cubemap = {0, "r_texture_convertsRGB_cubemap", "0", "load textures as sRGB and convert to linear for proper shading"}; +cvar_t r_texture_convertsRGB_skybox = {0, "r_texture_convertsRGB_skybox", "0", "load textures as sRGB and convert to linear for proper shading"}; +cvar_t r_texture_convertsRGB_particles = {0, "r_texture_convertsRGB_particles", "0", "load textures as sRGB and convert to linear for proper shading"}; + cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"}; static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"}; static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"}; @@ -5329,7 +5335,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole // check for DDS texture file first if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s.dds", basename), textureflags, &ddshasalpha, ddsavgcolor))) { - basepixels = loadimagepixelsbgra(name, complain, true); + basepixels = loadimagepixelsbgra(name, complain, true, r_texture_convertsRGB_skin.integer); if (basepixels == NULL) return NULL; } @@ -5414,13 +5420,13 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole // _norm is the name used by tenebrae and has been adopted as standard if (r_loadnormalmap && skinframe->nmap == NULL) { - if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL) + if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false, false)) != NULL) { skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); Mem_Free(pixels); pixels = NULL; } - else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false)) != NULL) + else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false, false)) != NULL) { pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value); @@ -5441,7 +5447,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole // _luma is supported only for tenebrae compatibility // _glow is the preferred name - if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false)))) + if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer)))) { skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow) @@ -5449,7 +5455,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole Mem_Free(pixels);pixels = NULL; } - if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false))) + if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer))) { skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss) @@ -5458,7 +5464,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole pixels = NULL; } - if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false))) + if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer))) { skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants) @@ -5467,7 +5473,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole pixels = NULL; } - if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false))) + if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer))) { skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt) @@ -5476,7 +5482,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole pixels = NULL; } - if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false))) + if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer))) { skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%s_reflect", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect) @@ -5820,7 +5826,7 @@ rtexture_t *R_LoadCubemap(const char *basename) // generate an image name based on the base and and suffix dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix); // load it - if ((image_buffer = loadimagepixelsbgra(name, false, false))) + if ((image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_cubemap.integer))) { // an image loaded, make sure width and height are equal if (image_width == image_height && (!cubemappixels || image_width == cubemapsize)) @@ -6179,6 +6185,11 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_transparentdepthmasking); Cvar_RegisterVariable(&r_texture_dds_load); Cvar_RegisterVariable(&r_texture_dds_save); + Cvar_RegisterVariable(&r_texture_convertsRGB_2d); + Cvar_RegisterVariable(&r_texture_convertsRGB_skin); + Cvar_RegisterVariable(&r_texture_convertsRGB_cubemap); + Cvar_RegisterVariable(&r_texture_convertsRGB_skybox); + Cvar_RegisterVariable(&r_texture_convertsRGB_particles); Cvar_RegisterVariable(&r_textureunits); Cvar_RegisterVariable(&gl_combine); Cvar_RegisterVariable(&r_glsl); diff --git a/image.c b/image.c index ef0aac4e..f9cd487e 100644 --- a/image.c +++ b/image.c @@ -775,6 +775,24 @@ void Image_StripImageExtension (const char *in, char *out, size_t size_out) strlcpy(out, in, size_out); } +static unsigned char image_linearfromsrgb[256]; + +void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels) +{ + int i; + // this math from http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt + if (!image_linearfromsrgb[255]) + for (i = 0;i < 256;i++) + image_linearfromsrgb[i] = i < 11 ? (int)(i / 12.92f) : (int)(pow((i/256.0f + 0.055f)/1.0555f, 2.4)*256.0f); + for (i = 0;i < numpixels;i++) + { + pout[i*4+0] = image_linearfromsrgb[pin[i*4+0]]; + pout[i*4+1] = image_linearfromsrgb[pin[i*4+1]]; + pout[i*4+2] = image_linearfromsrgb[pin[i*4+2]]; + pout[i*4+3] = pin[i*4+3]; + } +} + typedef struct imageformat_s { const char *formatstring; @@ -854,7 +872,7 @@ imageformat_t imageformats_other[] = }; int fixtransparentpixels(unsigned char *data, int w, int h); -unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans) +unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans, qboolean convertsRGB) { fs_offset_t filesize; imageformat_t *firstformat, *format; @@ -932,6 +950,8 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo } } } + if (convertsRGB) + Image_MakeLinearColorsFromsRGB(data, data, image_width * image_height); return data; } else @@ -956,11 +976,11 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo return NULL; } -rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans) +rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean convertsRGB) { unsigned char *data; rtexture_t *rt; - if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans))) + if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, convertsRGB))) return 0; rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, TEXTYPE_BGRA, flags, NULL); Mem_Free(data); @@ -1108,7 +1128,7 @@ void Image_FixTransparentPixels_f(void) Con_Printf("Processing %s... ", filename); Image_StripImageExtension(filename, buf, sizeof(buf)); dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf); - if(!(data = loadimagepixelsbgra(filename, true, false))) + if(!(data = loadimagepixelsbgra(filename, true, false, false))) return; if((n = fixtransparentpixels(data, image_width, image_height))) { diff --git a/image.h b/image.h index 46c69a68..61bcc9c6 100644 --- a/image.h +++ b/image.h @@ -23,13 +23,13 @@ void Image_StripImageExtension (const char *in, char *out, size_t size_out); unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize); // loads a texture, as pixel data -unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans); +unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans, qboolean convertsRGB); // loads an 8bit pcx image into a 296x194x8bit buffer, with cropping as needed qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight); // loads a texture, as a texture -rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans); +rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean convertsRGB); // writes an upside down BGR image into a TGA qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data, unsigned char *buffer); diff --git a/jpeg.c b/jpeg.c index 359a3cd0..74bd708e 100644 --- a/jpeg.c +++ b/jpeg.c @@ -1048,7 +1048,7 @@ qboolean Image_Compress(const char *imagename, size_t maxsize, void **buf, size_ } // load the image - imagedata = loadimagepixelsbgra(imagename, true, false); + imagedata = loadimagepixelsbgra(imagename, true, false, false); if(!imagedata) return false; diff --git a/model_brush.c b/model_brush.c index 7b965f45..8e830b08 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1567,7 +1567,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) // LordHavoc: HL sky textures are entirely different than quake if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == mtheight * 2) { - data = loadimagepixelsbgra(tx->name, false, false); + data = loadimagepixelsbgra(tx->name, false, false, r_texture_convertsRGB_skin.integer); if (data && image_width == image_height * 2) { R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); @@ -4546,7 +4546,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) if (developer_loading.integer) Con_Printf("Using external lightmaps\n"); FS_StripExtension(loadmodel->name, mapname, sizeof(mapname)); - inpixels[0] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, 0), false, false); + inpixels[0] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, 0), false, false, false); if(!inpixels[0]) return; @@ -4566,7 +4566,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) for(count = 1; ; ++count) { - inpixels[count] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, count), false, false); + inpixels[count] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, count), false, false, false); if(!inpixels[count]) break; // we got all of them if(image_width != size || image_height != size) diff --git a/r_sky.c b/r_sky.c index a701d799..d5db3e61 100644 --- a/r_sky.c +++ b/r_sky.c @@ -109,13 +109,13 @@ int R_LoadSkyBox(void) success = 0; for (i=0; i<6; i++) { - if (dpsnprintf(name, sizeof(name), "%s_%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false))) + if (dpsnprintf(name, sizeof(name), "%s_%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_skybox.integer))) { - if (dpsnprintf(name, sizeof(name), "%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false))) + if (dpsnprintf(name, sizeof(name), "%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_skybox.integer))) { - if (dpsnprintf(name, sizeof(name), "env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false))) + if (dpsnprintf(name, sizeof(name), "env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_skybox.integer))) { - if (dpsnprintf(name, sizeof(name), "gfx/env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false))) + if (dpsnprintf(name, sizeof(name), "gfx/env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_skybox.integer))) continue; } } diff --git a/render.h b/render.h index b7e8f853..ee9e7590 100644 --- a/render.h +++ b/render.h @@ -195,6 +195,12 @@ extern cvar_t r_smoothnormals_areaweighting; extern cvar_t r_test; +extern cvar_t r_texture_convertsRGB_2d; +extern cvar_t r_texture_convertsRGB_skin; +extern cvar_t r_texture_convertsRGB_cubemap; +extern cvar_t r_texture_convertsRGB_skybox; +extern cvar_t r_texture_convertsRGB_particles; + #include "gl_backend.h" extern rtexture_t *r_texture_blanknormalmap; -- 2.39.2