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
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"};
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;
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);
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)
{
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);
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->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->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 = 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;
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:
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);
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;
t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
t->backgroundglosstexture = r_texture_black;
t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
+ if (!t->backgroundnmaptexture)
+ t->backgroundnmaptexture = r_texture_blanknormalmap;
}
else
{
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};
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
{
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] =
{
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
}
// 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)
{
// 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
// 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
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;
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;
#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
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);
#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);
#ifndef IMAGE_H
#define IMAGE_H
-
extern int image_width, image_height;
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;
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);
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;
}
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);
{"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},
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)
// 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)