From f7e4a38d4ed39b94ae86820b28867171fcede2af Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 30 Dec 2009 02:21:16 +0000 Subject: [PATCH] implemented support for caching compressed textures (.dds files), disabled by default git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9735 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_rmain.c | 177 ++++++++++++++----- gl_textures.c | 462 +++++++++++++++++++++++++++++++++++++++++--------- glquake.h | 18 ++ image.h | 1 - r_textures.h | 12 ++ vid.h | 1 + vid_shared.c | 12 ++ 7 files changed, 556 insertions(+), 127 deletions(-) diff --git a/gl_rmain.c b/gl_rmain.c index a4e56fac..eff356fa 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -31,9 +31,11 @@ rtexturepool_t *r_main_texturepool; static int r_frame = 0; ///< used only by R_GetCurrentTexture -qboolean r_loadnormalmap; -qboolean r_loadgloss; +static qboolean r_loadnormalmap; +static qboolean r_loadgloss; qboolean r_loadfog; +static qboolean r_loaddds; +static qboolean r_savedds; // // screen size info @@ -107,6 +109,9 @@ cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Ne cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"}; cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"}; +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_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"}; @@ -5006,9 +5011,13 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole unsigned char *pixels; unsigned char *bumppixels; unsigned char *basepixels = NULL; - int basepixels_width; - int basepixels_height; + int basepixels_width = 0; + int basepixels_height = 0; skinframe_t *skinframe; + rtexture_t *ddsbase = NULL; + qboolean ddshasalpha = false; + float ddsavgcolor[4]; + char basename[MAX_QPATH]; if (cls.state == ca_dedicated) return NULL; @@ -5020,9 +5029,15 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole if (skinframe && skinframe->base) return skinframe; - basepixels = loadimagepixelsbgra(name, complain, true); - if (basepixels == NULL) - return NULL; + Image_StripImageExtension(name, basename, sizeof(basename)); + + // 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); + if (basepixels == NULL) + return NULL; + } if (developer_loading.integer) Con_Printf("loading skin \"%s\"\n", name); @@ -5032,50 +5047,75 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true); skinframe->stain = NULL; skinframe->merged = NULL; - skinframe->base = r_texture_notexture; + skinframe->base = NULL; skinframe->pants = NULL; skinframe->shirt = NULL; - skinframe->nmap = r_texture_blanknormalmap; + skinframe->nmap = NULL; skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; skinframe->hasalpha = false; - basepixels_width = image_width; - basepixels_height = image_height; - skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL); - - if (textureflags & TEXF_ALPHA) + if (ddsbase) + { + skinframe->base = ddsbase; + skinframe->hasalpha = ddshasalpha; + VectorCopy(ddsavgcolor, skinframe->avgcolor); + if (r_loadfog && skinframe->hasalpha) + skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_mask.dds", skinframe->basename), textureflags | TEXF_ALPHA, NULL, NULL); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + } + else { - for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4) + basepixels_width = image_width; + basepixels_height = image_height; + skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL); + if (textureflags & TEXF_ALPHA) { - if (basepixels[j] < 255) + for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4) { - skinframe->hasalpha = true; - break; + if (basepixels[j] < 255) + { + skinframe->hasalpha = true; + break; + } } - } - if (r_loadfog && skinframe->hasalpha) - { - // has transparent pixels - pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); - for (j = 0;j < image_width * image_height * 4;j += 4) + if (r_loadfog && skinframe->hasalpha) { - pixels[j+0] = 255; - pixels[j+1] = 255; - pixels[j+2] = 255; - pixels[j+3] = basepixels[j+3]; + // has transparent pixels + pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + for (j = 0;j < image_width * image_height * 4;j += 4) + { + pixels[j+0] = 255; + pixels[j+1] = 255; + pixels[j+2] = 255; + pixels[j+3] = basepixels[j+3]; + } + skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL); + Mem_Free(pixels); } - skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL); - Mem_Free(pixels); } + R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + if (r_savedds && qglGetCompressedTexImageARB && skinframe->base) + R_SaveTextureDDSFile(skinframe->base, va("dds/%s.dds", skinframe->basename), true); + if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog) + R_SaveTextureDDSFile(skinframe->fog, va("dds/%s_mask.dds", skinframe->basename), true); } - R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]); - //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + if (r_loaddds) + { + if (r_loadnormalmap) + skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_norm.dds", skinframe->basename), textureflags | TEXF_ALPHA, NULL, NULL); + skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_glow.dds", skinframe->basename), textureflags, NULL, NULL); + if (r_loadgloss) + skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_gloss.dds", skinframe->basename), textureflags, NULL, NULL); + skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_pants.dds", skinframe->basename), textureflags, NULL, NULL); + skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_shirt.dds", skinframe->basename), textureflags, NULL, NULL); + } // _norm is the name used by tenebrae and has been adopted as standard - if (r_loadnormalmap) + if (r_loadnormalmap && skinframe->nmap == NULL) { if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL) { @@ -5098,14 +5138,46 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); Mem_Free(pixels); } + if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap) + R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), true); } - // _luma is supported for tenebrae compatibility - // (I think it's a very stupid name, but oh well) + + // _luma is supported only for tenebrae compatibility // _glow is the preferred name - if ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false))) {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);Mem_Free(pixels);pixels = NULL;} - if (r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false))) {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);Mem_Free(pixels);pixels = NULL;} - if ((pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false))) {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);Mem_Free(pixels);pixels = NULL;} - if ((pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false))) {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);Mem_Free(pixels);pixels = NULL;} + if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false)))) + { + 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) + R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), true); + Mem_Free(pixels);pixels = NULL; + } + + if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false))) + { + 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) + R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), true); + Mem_Free(pixels); + pixels = NULL; + } + + if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false))) + { + 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) + R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), true); + Mem_Free(pixels); + pixels = NULL; + } + + if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false))) + { + 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) + R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), true); + Mem_Free(pixels); + pixels = NULL; + } if (basepixels) Mem_Free(basepixels); @@ -5130,10 +5202,10 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co skinframe->stain = NULL; skinframe->merged = NULL; - skinframe->base = r_texture_notexture; + skinframe->base = NULL; skinframe->pants = NULL; skinframe->shirt = NULL; - skinframe->nmap = r_texture_blanknormalmap; + skinframe->nmap = NULL; skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; @@ -5198,10 +5270,10 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i skinframe->stain = NULL; skinframe->merged = NULL; - skinframe->base = r_texture_notexture; + skinframe->base = NULL; skinframe->pants = NULL; skinframe->shirt = NULL; - skinframe->nmap = r_texture_blanknormalmap; + skinframe->nmap = NULL; skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; @@ -5318,10 +5390,10 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co skinframe->stain = NULL; skinframe->merged = NULL; - skinframe->base = r_texture_notexture; + skinframe->base = NULL; skinframe->pants = NULL; skinframe->shirt = NULL; - skinframe->nmap = r_texture_blanknormalmap; + skinframe->nmap = NULL; skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; @@ -5365,10 +5437,10 @@ skinframe_t *R_SkinFrame_LoadMissing(void) skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true); skinframe->stain = NULL; skinframe->merged = NULL; - skinframe->base = r_texture_notexture; + skinframe->base = NULL; skinframe->pants = NULL; skinframe->shirt = NULL; - skinframe->nmap = r_texture_blanknormalmap; + skinframe->nmap = NULL; skinframe->gloss = NULL; skinframe->glow = NULL; skinframe->fog = NULL; @@ -5446,6 +5518,9 @@ void gl_main_start(void) r_texture_fogattenuation = NULL; r_texture_gammaramps = NULL; + r_loaddds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_load.integer; + r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer; + switch(vid.renderpath) { case RENDERPATH_GL20: @@ -5658,6 +5733,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_fog_exp2); Cvar_RegisterVariable(&r_drawfog); Cvar_RegisterVariable(&r_transparentdepthmasking); + Cvar_RegisterVariable(&r_texture_dds_load); + Cvar_RegisterVariable(&r_texture_dds_save); Cvar_RegisterVariable(&r_textureunits); Cvar_RegisterVariable(&gl_combine); Cvar_RegisterVariable(&r_glsl); @@ -8441,9 +8518,13 @@ texture_t *R_GetCurrentTexture(texture_t *t) if (t->currentskinframe->qpixels) R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping); t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; + if (!t->basetexture) + t->basetexture = r_texture_notexture; t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL; t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL; t->nmaptexture = t->currentskinframe->nmap; + if (!t->nmaptexture) + t->nmaptexture = r_texture_blanknormalmap; t->glosstexture = r_texture_black; t->glowtexture = t->currentskinframe->glow; t->fogtexture = t->currentskinframe->fog; @@ -8453,6 +8534,8 @@ texture_t *R_GetCurrentTexture(texture_t *t) t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap; t->backgroundglosstexture = r_texture_black; t->backgroundglowtexture = t->backgroundcurrentskinframe->glow; + if (!t->backgroundnmaptexture) + t->backgroundnmaptexture = r_texture_blanknormalmap; } else { diff --git a/gl_textures.c b/gl_textures.c index 318ddecb..3bd9bd1a 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -47,8 +47,6 @@ textypeinfo_t; static textypeinfo_t textype_palette = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA , 3, GL_UNSIGNED_BYTE}; static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA , 4, GL_UNSIGNED_BYTE}; -static textypeinfo_t textype_palette_compress = {TEXTYPE_PALETTE, 1, 4, 0.5f, GL_BGRA , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE}; -static textypeinfo_t textype_palette_alpha_compress = {TEXTYPE_PALETTE, 1, 4, 1.0f, GL_BGRA , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE}; static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , 3, GL_UNSIGNED_BYTE}; static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , 4, GL_UNSIGNED_BYTE}; static textypeinfo_t textype_rgba_compress = {TEXTYPE_RGBA , 4, 4, 0.5f, GL_RGBA , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE}; @@ -60,7 +58,10 @@ static textypeinfo_t textype_bgra_alpha_compress = {TEXTYPE_BGRA , 4, 4, 1. static textypeinfo_t textype_shadowmap16 = {TEXTYPE_SHADOWMAP,2,2, 2.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16_ARB, GL_UNSIGNED_SHORT}; static textypeinfo_t textype_shadowmap24 = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_ARB, GL_UNSIGNED_INT}; static textypeinfo_t textype_alpha = {TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , 4, GL_UNSIGNED_BYTE}; -static textypeinfo_t textype_alpha_compress = {TEXTYPE_ALPHA , 1, 4, 1.0f, GL_ALPHA , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE}; +static textypeinfo_t textype_dxt1 = {TEXTYPE_DXT1 , 4, 0, 0.5f, 0 , GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0}; +static textypeinfo_t textype_dxt1a = {TEXTYPE_DXT1A , 4, 0, 0.5f, 0 , GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0}; +static textypeinfo_t textype_dxt3 = {TEXTYPE_DXT3 , 4, 0, 1.0f, 0 , GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0}; +static textypeinfo_t textype_dxt5 = {TEXTYPE_DXT5 , 4, 0, 1.0f, 0 , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0}; typedef enum gltexturetype_e { @@ -73,7 +74,6 @@ typedef enum gltexturetype_e gltexturetype_t; static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB}; -static int gltexturetypebindingenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB}; static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2}; static int cubemapside[6] = { @@ -159,81 +159,37 @@ static int texturebuffersize = 0; static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) { - if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression) + switch(textype) { - if (flags & TEXF_ALPHA) - { - switch(textype) - { - case TEXTYPE_PALETTE: - return &textype_palette_alpha_compress; - case TEXTYPE_RGBA: - return &textype_rgba_alpha_compress; - case TEXTYPE_BGRA: - return &textype_bgra_alpha_compress; - case TEXTYPE_ALPHA: - return &textype_alpha_compress; - default: - Host_Error("R_GetTexTypeInfo: unknown texture format"); - return NULL; - } - } + 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.arb_texture_compression) + return (flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress; else - { - switch(textype) - { - case TEXTYPE_PALETTE: - return &textype_palette_compress; - case TEXTYPE_RGBA: - return &textype_rgba_compress; - case TEXTYPE_BGRA: - return &textype_bgra_compress; - case TEXTYPE_ALPHA: - return &textype_alpha_compress; - default: - Host_Error("R_GetTexTypeInfo: unknown texture format"); - return NULL; - } - } - } - else - { - if (flags & TEXF_ALPHA) - { - switch(textype) - { - case TEXTYPE_PALETTE: - return &textype_palette_alpha; - case TEXTYPE_RGBA: - return &textype_rgba_alpha; - case TEXTYPE_BGRA: - return &textype_bgra_alpha; - case TEXTYPE_ALPHA: - return &textype_alpha; - default: - Host_Error("R_GetTexTypeInfo: unknown texture format"); - return NULL; - } - } + return (flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba; + break; + case TEXTYPE_BGRA: + if ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.arb_texture_compression) + return (flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress; else - { - switch(textype) - { - case TEXTYPE_PALETTE: - return &textype_palette; - case TEXTYPE_RGBA: - return &textype_rgba; - case TEXTYPE_BGRA: - return &textype_bgra; - case TEXTYPE_SHADOWMAP: - return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24; - case TEXTYPE_ALPHA: - return &textype_alpha; - default: - Host_Error("R_GetTexTypeInfo: unknown texture format"); - return NULL; - } - } + return (flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra; + break; + case TEXTYPE_ALPHA: + return &textype_alpha; + case TEXTYPE_SHADOWMAP: + return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24; + default: + Host_Error("R_GetTexTypeInfo: unknown texture format"); + return NULL; } return NULL; // this line only to hush compiler warnings } @@ -400,7 +356,7 @@ static void GL_TextureMode_f (void) // only update already uploaded images if (glt->texnum && !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))) { - oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR if (glt->flags & TEXF_MIPMAP) { @@ -656,7 +612,7 @@ void R_Textures_Frame (void) // only update already uploaded images if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP) { - oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso);CHECKGLERROR @@ -781,7 +737,7 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int // we need to restore the texture binding after finishing the upload GL_ActiveTexture(0); - oldbindtexnum = R_Mesh_TexBound(0, gltexturetypebindingenums[glt->texturetype]); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR // these are rounded up versions of the size to do better resampling @@ -1001,6 +957,13 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden break; case TEXTYPE_SHADOWMAP: break; + case TEXTYPE_DXT1: + break; + case TEXTYPE_DXT1A: + case TEXTYPE_DXT3: + case TEXTYPE_DXT5: + flags |= TEXF_ALPHA; + break; case TEXTYPE_ALPHA: flags |= TEXF_ALPHA; break; @@ -1097,6 +1060,347 @@ rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL); } +int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed) +{ + gltexture_t *glt = (gltexture_t *)rt; + unsigned char *dds; + int oldbindtexnum; + int bytesperpixel = 0; + int bytesperblock = 0; + int dds_flags; + int dds_format_flags; + int dds_caps1; + int dds_caps2; + int ret; + int mip; + int mipmaps; + int mipinfo[16][4]; + int ddssize = 128; + GLint internalformat; + const char *ddsfourcc; + if (!rt) + return -1; // NULL pointer + if (!strcmp(gl_version, "2.0.5885 WinXP Release")) + return -2; // broken driver - crashes on reading internal format + if (!qglGetTexLevelParameteriv) + return -2; + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat); + switch(internalformat) + { + default: ddsfourcc = NULL;bytesperpixel = 4;break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break; + } + if (!bytesperblock && skipuncompressed) + return -3; // skipped + memset(mipinfo, 0, sizeof(mipinfo)); + mipinfo[0][0] = glt->tilewidth; + mipinfo[0][1] = glt->tileheight; + mipmaps = 1; + if (glt->flags & TEXF_MIPMAP) + { + for (mip = 1;mip < 16;mip++) + { + mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1; + mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1; + if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1) + { + mip++; + break; + } + } + mipmaps = mip; + } + for (mip = 0;mip < mipmaps;mip++) + { + mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel; + mipinfo[mip][3] = ddssize; + ddssize += mipinfo[mip][2]; + } + dds = Mem_Alloc(tempmempool, ddssize); + if (!dds) + return -4; + dds_caps1 = 0x1000; // DDSCAPS_TEXTURE + dds_caps2 = 0; + if (bytesperblock) + { + dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE + dds_format_flags = 0x4; // DDPF_FOURCC + } + else + { + dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH + dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS + } + if (mipmaps) + { + dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT + dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX + } + memcpy(dds, "DDS ", 4); + StoreLittleLong(dds+4, ddssize); + StoreLittleLong(dds+8, dds_flags); + StoreLittleLong(dds+12, mipinfo[0][1]); // height + StoreLittleLong(dds+16, mipinfo[0][0]); // width + StoreLittleLong(dds+24, 1); // depth + StoreLittleLong(dds+28, mipmaps); // mipmaps + StoreLittleLong(dds+76, 32); // format size + StoreLittleLong(dds+80, dds_format_flags); + StoreLittleLong(dds+108, dds_caps1); + StoreLittleLong(dds+112, dds_caps2); + if (bytesperblock) + { + StoreLittleLong(dds+20, mipinfo[0][2]); // linear size + memcpy(dds+84, ddsfourcc, 4); + for (mip = 0;mip < mipmaps;mip++) + { + qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR + } + } + else + { + StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch + StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel + dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks + for (mip = 0;mip < mipmaps;mip++) + { + qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR + } + } + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + ret = FS_WriteFile(filename, dds, ddssize); + Mem_Free(dds); + return ret ? ddssize : -5; +} + +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor) +{ + int i, size, dds_flags, dds_format_flags, dds_miplevels, dds_width, dds_height, textype; + int bytesperblock, bytesperpixel; + int mipcomplete; + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo; + int mip, mipwidth, mipheight, mipsize; + unsigned int c; + GLint oldbindtexnum; + const unsigned char *mippixels, *ddspixels; + unsigned char *dds; + fs_offset_t ddsfilesize; + unsigned int ddssize; + + if (cls.state == ca_dedicated) + return NULL; + + dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize); + ddssize = ddsfilesize; + + if (!dds) + return NULL; // not found + + if (memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32) + { + Mem_Free(dds); + Con_Printf("^1%s: not a DDS image\n", filename); + return NULL; + } + + dds_flags = BuffLittleLong(dds+8); + dds_format_flags = BuffLittleLong(dds+80); + dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1; + dds_width = BuffLittleLong(dds+16); + dds_height = BuffLittleLong(dds+12); + ddspixels = dds + 128; + + flags &= ~TEXF_ALPHA; + if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32) + { + // very sloppy BGRA 32bit identification + textype = TEXTYPE_BGRA; + bytesperblock = 0; + bytesperpixel = 4; + size = dds_width*dds_height*bytesperpixel; + // check alpha + for (i = 3;i < size;i += 4) + if (ddspixels[i] < 255) + break; + if (i < size) + flags |= TEXF_ALPHA; + } + else if (!memcmp(dds+84, "DXT1", 4)) + { + // we need to find out if this is DXT1 (opaque) or DXT1A (transparent) + // LordHavoc: it is my belief that this does not infringe on the + // patent because it is not decoding pixels... + textype = TEXTYPE_DXT1; + bytesperblock = 8; + bytesperpixel = 0; + size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock; + for (i = 0;i < size;i += bytesperblock) + if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256) + break; + if (i < size) + { + textype = TEXTYPE_DXT1A; + flags |= TEXF_ALPHA; + } + } + else if (!memcmp(dds+84, "DXT3", 4)) + { + textype = TEXTYPE_DXT3; + bytesperblock = 16; + bytesperpixel = 0; + size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock; + flags |= TEXF_ALPHA; + } + else if (!memcmp(dds+84, "DXT5", 4)) + { + textype = TEXTYPE_DXT5; + bytesperblock = 16; + bytesperpixel = 0; + size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock; + flags |= TEXF_ALPHA; + } + else + { + Mem_Free(dds); + Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename); + return NULL; + } + + // return whether this texture is transparent + if (hasalphaflag) + *hasalphaflag = (flags & TEXF_ALPHA) != 0; + + // calculate average color if requested + if (avgcolor) + { + float f; + Vector4Clear(avgcolor); + if (bytesperblock) + { + for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock) + { + c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3]; + avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F); + avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F); + avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F); + } + f = (float)bytesperblock / size; + avgcolor[0] *= (0.5f / 31.0f) * f; + avgcolor[1] *= (0.5f / 63.0f) * f; + avgcolor[2] *= (0.5f / 31.0f) * f; + avgcolor[3] = 1; // too hard to calculate + } + else + { + for (i = 0;i < size;i += 4) + { + avgcolor[0] += ddspixels[i+2]; + avgcolor[1] += ddspixels[i+1]; + avgcolor[2] += ddspixels[i]; + avgcolor[3] += ddspixels[i+3]; + } + f = (1.0f / 255.0f) * bytesperpixel / size; + avgcolor[0] *= f; + avgcolor[1] *= f; + avgcolor[2] *= f; + avgcolor[3] *= f; + } + } + + if (dds_miplevels > 1) + flags |= TEXF_MIPMAP; + else + flags &= ~TEXF_MIPMAP; + + // if S3TC is not supported, there's very little we can do about it + if (bytesperblock && !vid.support.ext_texture_compression_s3tc) + { + Mem_Free(dds); + Con_Printf("^1%s: DDS file is compressed but OpenGL driver does not support S3TC\n", filename); + return NULL; + } + + texinfo = R_GetTexTypeInfo(textype, flags); + + glt = (gltexture_t *)Mem_Alloc(texturemempool, sizeof(gltexture_t)); + strlcpy (glt->identifier, filename, sizeof(glt->identifier)); + glt->pool = pool; + glt->chain = pool->gltchain; + pool->gltchain = glt; + glt->inputwidth = dds_width; + glt->inputheight = dds_height; + glt->inputdepth = 1; + glt->flags = flags; + glt->textype = texinfo; + glt->texturetype = GLTEXTURETYPE_2D; + glt->inputdatasize = ddssize; + glt->glinternalformat = texinfo->glinternalformat; + glt->glformat = texinfo->glformat; + glt->gltype = texinfo->gltype; + glt->bytesperpixel = texinfo->internalbytesperpixel; + glt->sides = 1; + glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype]; + glt->tilewidth = dds_width; + glt->tileheight = dds_height; + glt->tiledepth = 1; + + // texture uploading can take a while, so make sure we're sending keepalives + CL_KeepaliveMessage(false); + + // upload the texture + // we need to restore the texture binding after finishing the upload + CHECKGLERROR + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + mippixels = ddspixels; + mipwidth = dds_width; + mipheight = dds_height; + mipcomplete = false; + for (mip = 0;mip < dds_miplevels+1;mip++) + { + mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; + if (mippixels + mipsize > dds + ddssize) + break; + if (bytesperblock) + { + qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, mipsize, mippixels);CHECKGLERROR + } + else + { + qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, mipwidth, mipheight, 0, glt->glformat, glt->gltype, mippixels);CHECKGLERROR + } + mippixels += mipsize; + if (mipwidth <= 1 && mipheight <= 1) + { + mipcomplete = true; + break; + } + if (mipwidth > 1) + mipwidth >>= 1; + if (mipheight > 1) + mipheight >>= 1; + } + if (dds_miplevels > 1 && !mipcomplete) + { + // need to set GL_TEXTURE_MAX_LEVEL + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR + } + GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + + Mem_Free(dds); + return (rtexture_t *)glt; +} + int R_TextureWidth(rtexture_t *rt) { return rt ? ((gltexture_t *)rt)->inputwidth : 0; diff --git a/glquake.h b/glquake.h index b8a22432..0385511e 100644 --- a/glquake.h +++ b/glquake.h @@ -124,6 +124,11 @@ typedef ptrdiff_t GLsizeiptrARB; #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_TEXTURE_BINDING_1D 0x8068 #define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 @@ -682,6 +687,11 @@ extern void (GLAPIENTRY *qglTexEnvi)(GLenum target, GLenum pname, GLint param); extern void (GLAPIENTRY *qglTexParameterf)(GLenum target, GLenum pname, GLfloat param); extern void (GLAPIENTRY *qglTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); extern void (GLAPIENTRY *qglTexParameteri)(GLenum target, GLenum pname, GLint param); +extern void (GLAPIENTRY *qglGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); +extern void (GLAPIENTRY *qglGetTexParameteriv)(GLenum target, GLenum pname, GLint *params); +extern void (GLAPIENTRY *qglGetTexLevelParameterfv)(GLenum target, GLint level, GLenum pname, GLfloat *params); +extern void (GLAPIENTRY *qglGetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params); +extern void (GLAPIENTRY *qglGetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); extern void (GLAPIENTRY *qglHint)(GLenum target, GLenum mode); extern void (GLAPIENTRY *qglGenTextures)(GLsizei n, GLuint *textures); @@ -910,6 +920,14 @@ extern void (GLAPIENTRY *qglGetCompressedTexImageARB)(GLenum target, GLint lod, #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 #endif +// GL_EXT_texture_compression_s3tc +#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif + // GL_ARB_occlusion_query extern void (GLAPIENTRY *qglGenQueriesARB)(GLsizei n, GLuint *ids); extern void (GLAPIENTRY *qglDeleteQueriesARB)(GLsizei n, const GLuint *ids); diff --git a/image.h b/image.h index a8f25a15..46c69a68 100644 --- a/image.h +++ b/image.h @@ -2,7 +2,6 @@ #ifndef IMAGE_H #define IMAGE_H - extern int image_width, image_height; diff --git a/r_textures.h b/r_textures.h index 07485408..bb603cff 100644 --- a/r_textures.h +++ b/r_textures.h @@ -39,6 +39,14 @@ typedef enum textype_e TEXTYPE_SHADOWMAP, // 8bit ALPHA (used for freetype fonts) TEXTYPE_ALPHA, + // 4x4 block compressed 15bit color (4 bits per pixel) + TEXTYPE_DXT1, + // 4x4 block compressed 15bit color plus 1bit alpha (4 bits per pixel) + TEXTYPE_DXT1A, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) + TEXTYPE_DXT3, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) + TEXTYPE_DXT5, } textype_t; @@ -88,6 +96,10 @@ rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *ide rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter); rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter); rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter); +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor); + +// saves a texture to a DDS file +int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed); // free a texture void R_FreeTexture(rtexture_t *rt); diff --git a/vid.h b/vid.h index ea09fd1e..b0c3b626 100644 --- a/vid.h +++ b/vid.h @@ -64,6 +64,7 @@ typedef struct viddef_support_s qboolean ext_framebuffer_object; qboolean ext_stencil_two_side; qboolean ext_texture_3d; + qboolean ext_texture_compression_s3tc; qboolean ext_texture_edge_clamp; qboolean ext_texture_filter_anisotropic; } diff --git a/vid_shared.c b/vid_shared.c index d4da4694..397f590f 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -198,6 +198,11 @@ void (GLAPIENTRY *qglTexEnvi)(GLenum target, GLenum pname, GLint param); void (GLAPIENTRY *qglTexParameterf)(GLenum target, GLenum pname, GLfloat param); void (GLAPIENTRY *qglTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); void (GLAPIENTRY *qglTexParameteri)(GLenum target, GLenum pname, GLint param); +void (GLAPIENTRY *qglGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglGetTexParameteriv)(GLenum target, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetTexLevelParameterfv)(GLenum target, GLint level, GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglGetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); void (GLAPIENTRY *qglHint)(GLenum target, GLenum mode); void (GLAPIENTRY *qglGenTextures)(GLsizei n, GLuint *textures); @@ -534,6 +539,11 @@ static dllfunction_t opengl110funcs[] = {"glTexParameterf", (void **) &qglTexParameterf}, {"glTexParameterfv", (void **) &qglTexParameterfv}, {"glTexParameteri", (void **) &qglTexParameteri}, + {"glGetTexImage", (void **) &qglGetTexImage}, + {"glGetTexParameterfv", (void **) &qglGetTexParameterfv}, + {"glGetTexParameteriv", (void **) &qglGetTexParameteriv}, + {"glGetTexLevelParameterfv", (void **) &qglGetTexLevelParameterfv}, + {"glGetTexLevelParameteriv", (void **) &qglGetTexLevelParameteriv}, {"glHint", (void **) &qglHint}, // {"glPixelStoref", (void **) &qglPixelStoref}, {"glPixelStorei", (void **) &qglPixelStorei}, @@ -824,6 +834,7 @@ void VID_CheckExtensions(void) vid.support.ext_framebuffer_object = GL_CheckExtension("GL_EXT_framebuffer_object", fbofuncs, "-nofbo", false); vid.support.ext_stencil_two_side = GL_CheckExtension("GL_EXT_stencil_two_side", stenciltwosidefuncs, "-nostenciltwoside", false); vid.support.ext_texture_3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false); + 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); // COMMANDLINEOPTION: GL: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing) @@ -841,6 +852,7 @@ void VID_CheckExtensions(void) // COMMANDLINEOPTION: GL: -nomtex disables GL_ARB_multitexture (required for faster map rendering) // COMMANDLINEOPTION: GL: -noocclusionquery disables GL_ARB_occlusion_query (which allows coronas to fade according to visibility, and potentially used for rendering optimizations) // COMMANDLINEOPTION: GL: -norectangle disables GL_ARB_texture_rectangle (required for bumpmapping) +// COMMANDLINEOPTION: GL: -nos3tc disables GL_EXT_texture_compression_s3tc (which allows use of .dds texture caching) // COMMANDLINEOPTION: GL: -noseparatestencil disables use of OpenGL2.0 glStencilOpSeparate and GL_ATI_separate_stencil extensions (which accelerate shadow rendering) // COMMANDLINEOPTION: GL: -noshaderobjects disables GL_ARB_shader_objects (required for vertex shader and fragment shader) // COMMANDLINEOPTION: GL: -noshadinglanguage100 disables GL_ARB_shading_language_100 (required for vertex shader and fragment shader) -- 2.39.2