From 6e35898f26d4755cde2bb8182c02de57e50dd028 Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 10 Apr 2011 12:50:11 +0000 Subject: [PATCH] implemented support for GL_EXT_texture_sRGB to preserve precision if supported (otherwise it just converts to linear and uses regular texture formats) renamed r_texture_convertsRGB_ cvars to r_texture_sRGB_ and broke out the individual skin textures as separate cvars added vid.forcetextype which allows particular renderpaths to force desired texture component layouts (GL_RGBA for GLES, otherwise GL_BGRA) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11045 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=3a0aa3feb14ad0af4e0c2fb3408d6cca0132ddcf --- cl_particles.c | 4 +- gl_draw.c | 10 +-- gl_rmain.c | 56 ++++++++-------- gl_textures.c | 173 ++++++++++++++++++++++++++++++++----------------- glquake.h | 20 ++++++ image.c | 6 +- image.h | 4 +- model_brush.c | 21 +++--- model_sprite.c | 2 +- r_lightning.c | 2 +- r_shadow.c | 2 +- r_sky.c | 10 +-- r_textures.h | 22 ++++++- render.h | 14 ++-- vid.h | 3 + vid_sdl.c | 7 ++ vid_shared.c | 12 +++- vid_wgl.c | 4 ++ 18 files changed, 245 insertions(+), 127 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index 6efe27a6..392b46b7 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -2140,7 +2140,7 @@ static void R_InitParticleTexture (void) Image_WriteTGABGRA ("particles/particlefont.tga", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata); #endif - decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE); + decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE, false); particlefonttexture = decalskinframe->base; Mem_Free(particletexturedata); @@ -2159,7 +2159,7 @@ static void R_InitParticleTexture (void) } #ifndef DUMPPARTICLEFONT - particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, r_texture_convertsRGB_particles.integer != 0); + particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, r_texture_sRGB_skin_diffuse.integer != 0); if (!particletexture[tex_beam].texture) #endif { diff --git a/gl_draw.c b/gl_draw.c index 50fcb81e..5e76d3d6 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -371,9 +371,9 @@ reload: pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT); // load a high quality image from disk if possible - pixels = loadimagepixelsbgra(path, false, true, r_texture_convertsRGB_2d.integer != 0, NULL); + pixels = loadimagepixelsbgra(path, false, true, false, NULL); if (pixels == NULL && !strncmp(path, "gfx/", 4)) - pixels = loadimagepixelsbgra(path+4, false, true, r_texture_convertsRGB_2d.integer != 0, NULL); + pixels = loadimagepixelsbgra(path+4, false, true, false, NULL); if (pixels) { pic->hasalpha = false; @@ -392,7 +392,7 @@ reload: pic->width = image_width; pic->height = image_height; if (!pic->autoload) - pic->tex = R_LoadTexture2D(drawtexturepool, path, image_width, image_height, pixels, TEXTYPE_BGRA, pic->texflags & (pic->hasalpha ? ~0 : ~TEXF_ALPHA), -1, NULL); + pic->tex = R_LoadTexture2D(drawtexturepool, path, image_width, image_height, pixels, r_texture_sRGB_2d.integer ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, pic->texflags & (pic->hasalpha ? ~0 : ~TEXF_ALPHA), -1, NULL); } else { @@ -472,9 +472,9 @@ rtexture_t *Draw_GetPicTexture(cachepic_t *pic) { if (pic->autoload && !pic->tex) { - pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true, r_texture_convertsRGB_2d.integer != 0); + pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true, r_texture_sRGB_2d.integer != 0); if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4)) - pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true, r_texture_convertsRGB_2d.integer != 0); + pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true, r_texture_sRGB_2d.integer != 0); if (pic->tex == NULL) pic->tex = draw_generatepic(pic->name, true); } diff --git a/gl_rmain.c b/gl_rmain.c index 0d331be3..870bfb60 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -131,11 +131,13 @@ 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_texture_sRGB_2d = {0, "r_texture_sRGB_2d", "0", "load textures as sRGB"}; +cvar_t r_texture_sRGB_skin_diffuse = {0, "r_texture_sRGB_skin_diffuse", "0", "load textures as sRGB"}; +cvar_t r_texture_sRGB_skin_gloss = {0, "r_texture_sRGB_skin_gloss", "0", "load textures as sRGB"}; +cvar_t r_texture_sRGB_skin_glow = {0, "r_texture_sRGB_skin_glow", "0", "load textures as sRGB"}; +cvar_t r_texture_sRGB_skin_reflect = {0, "r_texture_sRGB_skin_reflect", "0", "load textures as sRGB"}; +cvar_t r_texture_sRGB_cubemap = {0, "r_texture_sRGB_cubemap", "0", "load textures as sRGB"}; +cvar_t r_texture_sRGB_skybox = {0, "r_texture_sRGB_skybox", "0", "load textures as sRGB"}; 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"}; @@ -3168,7 +3170,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, miplevel))) { - basepixels = loadimagepixelsbgra(name, complain, true, r_texture_convertsRGB_skin.integer != 0, &miplevel); + basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel); if (basepixels == NULL) return NULL; } @@ -3206,7 +3208,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole { basepixels_width = image_width; basepixels_height = image_height; - skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL); + skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, r_texture_sRGB_skin_diffuse.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL); if (textureflags & TEXF_ALPHA) { for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4) @@ -3285,18 +3287,18 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole // _luma is supported only for tenebrae compatibility // _glow is the preferred name mymiplevel = savemiplevel; - if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer != 0, &mymiplevel)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer != 0, &mymiplevel)))) + if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, false, &mymiplevel)))) { - skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_glow.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow) R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), true, true); Mem_Free(pixels);pixels = NULL; } mymiplevel = savemiplevel; - if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer != 0, &mymiplevel))) + if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_gloss.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss) R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), true, true); Mem_Free(pixels); @@ -3304,9 +3306,9 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole } mymiplevel = savemiplevel; - if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer != 0, &mymiplevel))) + if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_diffuse.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants) R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), true, false); Mem_Free(pixels); @@ -3314,9 +3316,9 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole } mymiplevel = savemiplevel; - if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer != 0, &mymiplevel))) + if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_diffuse.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt) R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), true, false); Mem_Free(pixels); @@ -3324,9 +3326,9 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole } mymiplevel = savemiplevel; - if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false, r_texture_convertsRGB_skin.integer != 0, &mymiplevel))) + if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%s_reflect", skinframe->basename), false, false, false, &mymiplevel))) { - skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%s_reflect", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%s_reflect", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_reflect.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect) R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), true, true); Mem_Free(pixels); @@ -3340,7 +3342,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole } // this is only used by .spr32 sprites, HL .spr files, HL .bsp files -skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height) +skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB) { int i; unsigned char *temp1, *temp2; @@ -3381,7 +3383,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); Mem_Free(temp1); } - skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_BGRA, textureflags, -1, NULL); + skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL); if (textureflags & TEXF_ALPHA) { for (i = 3;i < width * height * 4;i += 4) @@ -3668,7 +3670,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, r_texture_convertsRGB_cubemap.integer != 0, NULL))) + if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) { // an image loaded, make sure width and height are equal if (image_width == image_height && (!cubemappixels || image_width == cubemapsize)) @@ -3697,7 +3699,7 @@ rtexture_t *R_LoadCubemap(const char *basename) if (developer_loading.integer) Con_Printf("loading cubemap \"%s\"\n", basename); - cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, r_texture_sRGB_cubemap.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); Mem_Free(cubemappixels); } else @@ -4071,11 +4073,13 @@ 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_texture_sRGB_2d); + Cvar_RegisterVariable(&r_texture_sRGB_skin_diffuse); + Cvar_RegisterVariable(&r_texture_sRGB_skin_gloss); + Cvar_RegisterVariable(&r_texture_sRGB_skin_glow); + Cvar_RegisterVariable(&r_texture_sRGB_skin_reflect); + Cvar_RegisterVariable(&r_texture_sRGB_cubemap); + Cvar_RegisterVariable(&r_texture_sRGB_skybox); Cvar_RegisterVariable(&r_textureunits); Cvar_RegisterVariable(&gl_combine); Cvar_RegisterVariable(&r_viewfbo); diff --git a/gl_textures.c b/gl_textures.c index bb33548d..f86ddc44 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -74,28 +74,43 @@ typedef struct textypeinfo_s } textypeinfo_t; - -static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; -static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; -static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 }; -static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 , 0 }; -static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 , 0 }; -static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 , 0 }; -static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER, 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; -static textypeinfo_t textype_colorbuffer16f = {TEXTYPE_COLORBUFFER16F,8,8,8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT }; -static textypeinfo_t textype_colorbuffer32f = {TEXTYPE_COLORBUFFER32F,16,16,16.0f,GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT }; - +// framebuffer texture formats +static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_colorbuffer = {TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_colorbuffer16f = {TEXTYPE_COLORBUFFER16F, 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT }; +static textypeinfo_t textype_colorbuffer32f = {TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT }; + +// image formats: +static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 }; +static textypeinfo_t textype_sRGB_palette = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_palette_alpha = {TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_alpha_compress = {TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_alpha = {TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_compress = {TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 }; typedef enum gltexturetype_e { @@ -214,34 +229,25 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) { switch(textype) { - case TEXTYPE_DXT1: - return &textype_dxt1; - case TEXTYPE_DXT1A: - return &textype_dxt1a; - case TEXTYPE_DXT3: - return &textype_dxt3; - case TEXTYPE_DXT5: - return &textype_dxt5; - case TEXTYPE_PALETTE: - return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette; - case TEXTYPE_RGBA: - if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) - return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress; - return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba; - case TEXTYPE_BGRA: - if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) - return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress; - return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra; - case TEXTYPE_ALPHA: - return &textype_alpha; - case TEXTYPE_SHADOWMAP: - return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24; - case TEXTYPE_COLORBUFFER: - return &textype_colorbuffer; - case TEXTYPE_COLORBUFFER16F: - return &textype_colorbuffer16f; - case TEXTYPE_COLORBUFFER32F: - return &textype_colorbuffer32f; + case TEXTYPE_DXT1: return &textype_dxt1; + case TEXTYPE_DXT1A: return &textype_dxt1a; + case TEXTYPE_DXT3: return &textype_dxt3; + case TEXTYPE_DXT5: return &textype_dxt5; + case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette; + case TEXTYPE_RGBA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba); + case TEXTYPE_BGRA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra); + case TEXTYPE_ALPHA: return &textype_alpha; + case TEXTYPE_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24; + case TEXTYPE_COLORBUFFER: return &textype_colorbuffer; + case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f; + case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f; + case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1; + case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a; + case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3; + case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5; + case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette; + case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba); + case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra); default: Host_Error("R_GetTexTypeInfo: unknown texture format"); break; @@ -1484,10 +1490,59 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; textypeinfo_t *texinfo, *texinfo2; unsigned char *temppixels = NULL; + qboolean swaprb; if (cls.state == ca_dedicated) return NULL; + // see if we need to swap red and blue (BGRA <-> RGBA conversion) + swaprb = false; + switch(textype) + { + case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break; + case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break; + case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break; + case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break; + default: break; + } + if (swaprb) + { + // swap bytes + static int rgbaswapindices[4] = {2, 1, 0, 3}; + size = width * height * depth * sides * 4; + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices); + data = temppixels; + } + + // if sRGB texture formats are not supported, convert input to linear and upload as normal types + if (!vid.support.ext_texture_srgb) + { + qboolean convertsRGB = false; + switch(textype) + { + case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break; + case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break; + case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break; + case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break; + case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;convertsRGB = true;break; + case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break; + case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break; + default: + break; + } + if (convertsRGB && data) + { + size = width * height * depth * sides * 4; + if (!temppixels) + { + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + memcpy(temppixels, data, size); + } + Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides); + } + } + if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map) { Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n"); @@ -1507,21 +1562,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden return NULL; } - if (textype == TEXTYPE_RGBA) - { - // swap bytes - static int rgbaswapindices[4] = {2, 1, 0, 3}; - textype = TEXTYPE_BGRA; - texinfo = R_GetTexTypeInfo(textype, flags); - temppixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * depth * sides * 4); - Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices); - data = temppixels; - } - // clear the alpha flag if the texture has no transparent pixels switch(textype) { case TEXTYPE_PALETTE: + case TEXTYPE_SRGB_PALETTE: if (flags & TEXF_ALPHA) { flags &= ~TEXF_ALPHA; @@ -1540,6 +1585,8 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden break; case TEXTYPE_RGBA: case TEXTYPE_BGRA: + case TEXTYPE_SRGB_RGBA: + case TEXTYPE_SRGB_BGRA: if (flags & TEXF_ALPHA) { flags &= ~TEXF_ALPHA; @@ -1559,10 +1606,14 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden case TEXTYPE_SHADOWMAP: break; case TEXTYPE_DXT1: + case TEXTYPE_SRGB_DXT1: break; case TEXTYPE_DXT1A: + case TEXTYPE_SRGB_DXT1A: case TEXTYPE_DXT3: + case TEXTYPE_SRGB_DXT3: case TEXTYPE_DXT5: + case TEXTYPE_SRGB_DXT5: flags |= TEXF_ALPHA; break; case TEXTYPE_ALPHA: diff --git a/glquake.h b/glquake.h index c5b1b529..120c453e 100644 --- a/glquake.h +++ b/glquake.h @@ -614,6 +614,26 @@ extern void (GLAPIENTRY *qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); #define GL_LUMINANCE_ALPHA16F_ARB 0x881F #endif +// GL_EXT_texture_sRGB +#ifndef GL_SRGB_EXT +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif + extern void (GLAPIENTRY *qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height); extern void (GLAPIENTRY *qglClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); diff --git a/image.c b/image.c index bec68ec5..e35dd33d 100644 --- a/image.c +++ b/image.c @@ -1004,14 +1004,14 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo } extern cvar_t gl_picmip; -rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean convertsRGB) +rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB) { unsigned char *data; rtexture_t *rt; int miplevel = R_PicmipForFlags(flags); - if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, convertsRGB, &miplevel))) + if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, false, &miplevel))) return 0; - rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, TEXTYPE_BGRA, flags, miplevel, NULL); + rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, flags, miplevel, NULL); Mem_Free(data); return rt; } diff --git a/image.h b/image.h index c553a97e..10d190dd 100644 --- a/image.h +++ b/image.h @@ -29,7 +29,7 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo 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, qboolean convertsRGB); +rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB); // writes an upside down BGR image into a TGA qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data); @@ -49,5 +49,7 @@ void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned cha void Image_FixTransparentPixels_f(void); extern cvar_t r_fixtrans_auto; +void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels); + #endif diff --git a/model_brush.c b/model_brush.c index a04e96c1..e59393a6 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1578,8 +1578,8 @@ void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesp } } - loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_solidtexture", 0 , (unsigned char *) solidpixels, w, h); - loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_alphatexture", TEXF_ALPHA, (unsigned char *) alphapixels, w, h); + loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_solidtexture", 0 , (unsigned char *) solidpixels, w, h, bytesperpixel == 4 && r_texture_sRGB_skybox.integer); + loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_alphatexture", TEXF_ALPHA, (unsigned char *) alphapixels, w, h, bytesperpixel == 4 && r_texture_sRGB_skybox.integer); Mem_Free(solidpixels); Mem_Free(alphapixels); } @@ -1595,9 +1595,9 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) unsigned char *data, *mtdata; const char *s; char mapname[MAX_QPATH], name[MAX_QPATH]; - unsigned char zero[4]; - - memset(zero, 0, sizeof(zero)); + unsigned char zeroopaque[4], zerotrans[4]; + Vector4Set(zeroopaque, 0, 0, 0, 255); + Vector4Set(zerotrans, 0, 0, 0, 128); loadmodel->data_textures = NULL; @@ -1770,9 +1770,9 @@ 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(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s/%s", mapname, tx->name), false, false, r_texture_convertsRGB_skin.integer != 0, NULL); + data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s/%s", mapname, tx->name), false, false, r_texture_sRGB_skin_diffuse.integer != 0, NULL); if (!data) - data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), false, false, r_texture_convertsRGB_skin.integer != 0, NULL); + data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), false, false, r_texture_sRGB_skin_diffuse.integer != 0, NULL); if (data && image_width == image_height * 2) { R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); @@ -1802,7 +1802,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) { tx->width = image_width; tx->height = image_height; - skinframe = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP, pixels, image_width, image_height); + skinframe = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP, pixels, image_width, image_height, true); } if (freepixels) Mem_Free(freepixels); @@ -1822,8 +1822,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae { // replace the texture with transparent black - Vector4Set(zero, 128, 128, 128, 128); - tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zero, 1, 1); + tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zerotrans, 1, 1, false); tx->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_REFLECTION; } else if (!strncmp(tx->name,"*lava",5) @@ -1838,7 +1837,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae { // replace the texture with black - tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, 0, zero, 1, 1); + tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, 0, zeroopaque, 1, 1, false); tx->basematerialflags |= MATERIALFLAG_REFLECTION; } else if (!strncmp(tx->name, "sky", 3)) diff --git a/model_sprite.c b/model_sprite.c index 7c80ef48..3588c61d 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -212,7 +212,7 @@ static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version } else //if (version == SPRITEHL_VERSION || version == SPRITE_VERSION) Image_Copy8bitBGRA(datapointer, pixels, width*height, palette ? palette : palette_bgra_transparent); - skinframe = R_SkinFrame_LoadInternalBGRA(name, texflags, pixels, width, height); + skinframe = R_SkinFrame_LoadInternalBGRA(name, texflags, pixels, width, height, false); Mem_Free(pixels); } } diff --git a/r_lightning.c b/r_lightning.c index af966a96..67d32ae8 100644 --- a/r_lightning.c +++ b/r_lightning.c @@ -144,7 +144,7 @@ void r_lightningbeams_setuptexture(void) } } - r_lightningbeamtexture = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, BEAMWIDTH, BEAMHEIGHT); + r_lightningbeamtexture = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, BEAMWIDTH, BEAMHEIGHT, false); Mem_Free(noise1); Mem_Free(noise2); Mem_Free(data); diff --git a/r_shadow.c b/r_shadow.c index ed371f12..d479f125 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -1762,7 +1762,7 @@ static void R_Shadow_MakeTextures_MakeCorona(void) pixels[y][x][3] = 255; } } - r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32); + r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false); } static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z) diff --git a/r_sky.c b/r_sky.c index 4aa4d7fb..eabb9968 100644 --- a/r_sky.c +++ b/r_sky.c @@ -109,20 +109,20 @@ 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, r_texture_convertsRGB_skybox.integer != 0, NULL))) + if (dpsnprintf(name, sizeof(name), "%s_%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) { - if (dpsnprintf(name, sizeof(name), "%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, r_texture_convertsRGB_skybox.integer != 0, NULL))) + if (dpsnprintf(name, sizeof(name), "%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) { - 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 != 0, NULL))) + if (dpsnprintf(name, sizeof(name), "env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) { - 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 != 0, NULL))) + if (dpsnprintf(name, sizeof(name), "gfx/env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) continue; } } } temp = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height*4); Image_CopyMux (temp, image_buffer, image_width, image_height, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, indices); - skyboxskinframe[i] = R_SkinFrame_LoadInternalBGRA(va("skyboxside%d", i), TEXF_CLAMP | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), temp, image_width, image_height); + skyboxskinframe[i] = R_SkinFrame_LoadInternalBGRA(va("skyboxside%d", i), TEXF_CLAMP | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), temp, image_width, image_height, r_texture_sRGB_skybox.integer != 0); Mem_Free(image_buffer); Mem_Free(temp); success++; diff --git a/r_textures.h b/r_textures.h index b66201c4..4265c5eb 100644 --- a/r_textures.h +++ b/r_textures.h @@ -43,8 +43,6 @@ typedef enum textype_e TEXTYPE_RGBA, // 32bit BGRA (preferred format due to faster uploads on most hardware) TEXTYPE_BGRA, - // 16bit D16 (16bit depth) or 32bit S8D24 (24bit depth, 8bit stencil unused) - TEXTYPE_SHADOWMAP, // 8bit ALPHA (used for freetype fonts) TEXTYPE_ALPHA, // 4x4 block compressed 15bit color (4 bits per pixel) @@ -55,12 +53,30 @@ typedef enum textype_e TEXTYPE_DXT3, // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) TEXTYPE_DXT5, + + // 8bit paletted in sRGB colorspace + TEXTYPE_SRGB_PALETTE, + // 32bit RGBA in sRGB colorspace + TEXTYPE_SRGB_RGBA, + // 32bit BGRA (preferred format due to faster uploads on most hardware) in sRGB colorspace + TEXTYPE_SRGB_BGRA, + // 4x4 block compressed 15bit color (4 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT1, + // 4x4 block compressed 15bit color plus 1bit alpha (4 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT1A, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT3, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT5, + // this represents the same format as the framebuffer, for fast copies TEXTYPE_COLORBUFFER, // this represents an RGBA half_float texture (4 16bit floats) TEXTYPE_COLORBUFFER16F, // this represents an RGBA float texture (4 32bit floats) - TEXTYPE_COLORBUFFER32F + TEXTYPE_COLORBUFFER32F, + // 16bit D16 (16bit depth) or 32bit S8D24 (24bit depth, 8bit stencil unused) + TEXTYPE_SHADOWMAP } textype_t; diff --git a/render.h b/render.h index c1911e08..9cfd6f2e 100644 --- a/render.h +++ b/render.h @@ -143,7 +143,7 @@ void R_SkinFrame_Purge(void); skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ); skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add); skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain); -skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height); +skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB); skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height); skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette); skinframe_t *R_SkinFrame_LoadMissing(void); @@ -199,11 +199,13 @@ 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; +extern cvar_t r_texture_sRGB_2d; +extern cvar_t r_texture_sRGB_skin_diffuse; +extern cvar_t r_texture_sRGB_skin_gloss; +extern cvar_t r_texture_sRGB_skin_glow; +extern cvar_t r_texture_sRGB_skin_reflect; +extern cvar_t r_texture_sRGB_cubemap; +extern cvar_t r_texture_sRGB_skybox; #include "gl_backend.h" diff --git a/vid.h b/vid.h index ebde4ff4..ff691aac 100644 --- a/vid.h +++ b/vid.h @@ -67,6 +67,7 @@ typedef struct viddef_support_s qboolean ext_texture_compression_s3tc; qboolean ext_texture_edge_clamp; qboolean ext_texture_filter_anisotropic; + qboolean ext_texture_srgb; } viddef_support_t; @@ -122,6 +123,8 @@ typedef struct viddef_s // blit to the window) unsigned int *softpixels; unsigned int *softdepthpixels; + + int forcetextype; // always use GL_BGRA for D3D, always use GL_RGBA for GLES, etc } viddef_t; // global video state diff --git a/vid_sdl.c b/vid_sdl.c index ea18c921..5302620f 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -1685,6 +1685,9 @@ void GLES_Init(void) // LordHavoc: report supported extensions Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions ); + + // GLES devices in general do not like GL_BGRA, so use GL_RGBA + vid.forcetextype = TEXTYPE_RGBA; vid.support.gl20shaders = true; vid.support.amd_texture_texture4 = false; @@ -1709,6 +1712,7 @@ void GLES_Init(void) vid.support.ext_texture_compression_s3tc = false; vid.support.ext_texture_edge_clamp = true; vid.support.ext_texture_filter_anisotropic = false; // probably don't want to use it... + vid.support.ext_texture_srgb = false; qglGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_2d); if (vid.support.ext_texture_filter_anisotropic) @@ -2516,8 +2520,11 @@ void VID_Finish (void) case RENDERPATH_SOFT: DPSOFTRAST_Finish(); #if SETVIDEOMODE + if (!r_test.integer) + { SDL_BlitSurface(vid_softsurface, NULL, screen, NULL); SDL_Flip(screen); + } #else { SDL_Surface *screen = SDL_GetWindowSurface(window); diff --git a/vid_shared.c b/vid_shared.c index b2e2636e..81f6feef 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -92,7 +92,7 @@ cvar_t v_color_white_g = {CVAR_SAVE, "v_color_white_g", "1", "desired color of w cvar_t v_color_white_b = {CVAR_SAVE, "v_color_white_b", "1", "desired color of white"}; cvar_t v_hwgamma = {CVAR_SAVE, "v_hwgamma", "1", "enables use of hardware gamma correction ramps if available (note: does not work very well on Windows2000 and above), values are 0 = off, 1 = attempt to use hardware gamma, 2 = use hardware gamma whether it works or not"}; cvar_t v_glslgamma = {CVAR_SAVE, "v_glslgamma", "0", "enables use of GLSL to apply gamma correction ramps if available (note: overrides v_hwgamma)"}; -cvar_t v_psycho = {0, "v_psycho", "0", "easter egg (does not work on Windows2000 or above)"}; +cvar_t v_psycho = {0, "v_psycho", "0", "easter egg"}; // brand of graphics chip const char *gl_vendor; @@ -857,6 +857,9 @@ void VID_CheckExtensions(void) else Con_DPrintf("Using GLSL 1.00\n"); + // GL drivers generally prefer GL_BGRA + vid.forcetextype = GL_BGRA; + vid.support.amd_texture_texture4 = GL_CheckExtension("GL_AMD_texture_texture4", NULL, "-notexture4", false); vid.support.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false); vid.support.arb_draw_buffers = GL_CheckExtension("GL_ARB_draw_buffers", drawbuffersfuncs, "-nodrawbuffers", false); @@ -879,6 +882,7 @@ void VID_CheckExtensions(void) vid.support.ext_texture_compression_s3tc = GL_CheckExtension("GL_EXT_texture_compression_s3tc", NULL, "-nos3tc", false); vid.support.ext_texture_edge_clamp = GL_CheckExtension("GL_EXT_texture_edge_clamp", NULL, "-noedgeclamp", false) || GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "-noedgeclamp", false); vid.support.ext_texture_filter_anisotropic = GL_CheckExtension("GL_EXT_texture_filter_anisotropic", NULL, "-noanisotropy", false); + vid.support.ext_texture_srgb = GL_CheckExtension("GL_EXT_texture_sRGB", NULL, "-nosrgb", false); // COMMANDLINEOPTION: GL: -noshaders disables use of OpenGL 2.0 shaders (which allow pixel shader effects, can improve per pixel lighting performance and capabilities) // COMMANDLINEOPTION: GL: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing) // COMMANDLINEOPTION: GL: -noblendminmax disables GL_EXT_blend_minmax @@ -902,6 +906,7 @@ void VID_CheckExtensions(void) // COMMANDLINEOPTION: GL: -notexturegather disables GL_ARB_texture_gather (which provides fetch4 sampling) // COMMANDLINEOPTION: GL: -notexturenonpoweroftwo disables GL_ARB_texture_non_power_of_two (which saves video memory if it is supported, but crashes on some buggy drivers) // COMMANDLINEOPTION: GL: -novbo disables GL_ARB_vertex_buffer_object (which accelerates rendering) +// COMMANDLINEOPTION: GL: -nosrgb disables GL_EXT_texture_sRGB (which is used for higher quality non-linear texture gamma) if (vid.support.arb_draw_buffers) qglGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, (GLint*)&vid.maxdrawbuffers); @@ -1290,6 +1295,7 @@ int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate, vid.stereobuffer = vid.mode.stereobuffer; vid.samples = vid.mode.samples; vid.stencil = vid.mode.bitsperpixel > 16; + Con_Printf("Video Mode: %s %dx%dx%dx%.2fhz%s%s\n", mode.fullscreen ? "fullscreen" : "window", mode.width, mode.height, mode.bitsperpixel, mode.refreshrate, mode.stereobuffer ? " stereo" : "", mode.samples > 1 ? va(" (%ix AA)", mode.samples) : ""); Cvar_SetValueQuick(&vid_fullscreen, vid.mode.fullscreen); @@ -1492,6 +1498,9 @@ void VID_Soft_SharedSetup(void) memset(&vid.support, 0, sizeof(vid.support)); Cvar_SetQuick(&gl_info_extensions, ""); + // DPSOFTRAST requires BGRA + vid.forcetextype = TEXTYPE_BGRA; + vid.forcevbo = false; vid.support.arb_depth_texture = true; vid.support.arb_draw_buffers = true; @@ -1508,6 +1517,7 @@ void VID_Soft_SharedSetup(void) //vid.support.ext_texture_compression_s3tc = true; vid.support.ext_texture_filter_anisotropic = true; vid.support.ati_separate_stencil = true; + vid.support.ext_texture_srgb = false; vid.maxtexturesize_2d = 16384; vid.maxtexturesize_3d = 512; diff --git a/vid_wgl.c b/vid_wgl.c index acfece3a..37b4a112 100644 --- a/vid_wgl.c +++ b/vid_wgl.c @@ -1569,6 +1569,9 @@ qboolean VID_InitModeDX(viddef_mode_t *mode, int version) memset(&vid.support, 0, sizeof(vid.support)); Cvar_SetQuick(&gl_info_extensions, ""); + // D3D9 requires BGRA + vid.forcetextype = TEXTYPE_BGRA; + vid.forcevbo = false; vid.support.arb_depth_texture = true; vid.support.arb_draw_buffers = vid_d3d9caps.NumSimultaneousRTs > 1; @@ -1585,6 +1588,7 @@ qboolean VID_InitModeDX(viddef_mode_t *mode, int version) vid.support.ext_texture_compression_s3tc = true; vid.support.ext_texture_filter_anisotropic = true; vid.support.ati_separate_stencil = (vid_d3d9caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) != 0; + vid.support.ext_texture_srgb = false; // FIXME use D3DSAMP_SRGBTEXTURE if CheckDeviceFormat agrees vid.maxtexturesize_2d = min(vid_d3d9caps.MaxTextureWidth, vid_d3d9caps.MaxTextureHeight); vid.maxtexturesize_3d = vid_d3d9caps.MaxVolumeExtent; -- 2.39.2