cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
+cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambigous, 2: texture format only"};
+cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
qboolean gl_filter_force = false;
int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
GLTEXTURETYPE_2D,
GLTEXTURETYPE_3D,
GLTEXTURETYPE_CUBEMAP,
- GLTEXTURETYPE_RECTANGLE,
GLTEXTURETYPE_TOTAL
}
gltexturetype_t;
-static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
-static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2, 2};
+static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
+static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2};
static int cubemapside[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
// d3d stuff the backend needs
void *d3dtexture;
#ifdef SUPPORTD3D
+ qboolean d3disdepthsurface; // for depth/stencil surfaces
int d3dformat;
int d3dusage;
int d3dpool;
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)
+ 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.arb_texture_compression)
+ 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:
else
Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
- if (glt->texnum)
+ switch(vid.renderpath)
{
- CHECKGLERROR
- qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+ case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_CGGL:
+ if (glt->texnum)
+ {
+ CHECKGLERROR
+ qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+ }
+ break;
+ case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+ if (glt->d3disdepthsurface)
+ IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
+ else if (glt->tiledepth > 1)
+ IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
+ else if (glt->sides == 6)
+ IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
+ else
+ IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
+ glt->d3dtexture = NULL;
+#endif
+ break;
+ case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
}
if (glt->inputtexels)
typedef struct glmode_s
{
- char *name;
+ const char *name;
int minification, magnification;
}
glmode_t;
#ifdef SUPPORTD3D
typedef struct d3dmode_s
{
- char *name;
+ const char *name;
int m1, m2;
}
d3dmode_t;
for (glt = pool->gltchain;glt;glt = glt->chain)
{
// only update already uploaded images
- if (glt->d3dtexture && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
+ if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
{
if (glt->flags & TEXF_MIPMAP)
{
break;
}
- if (outwidth)
+ if (vid.support.arb_texture_non_power_of_two)
{
- if (vid.support.arb_texture_non_power_of_two)
- width2 = min(inwidth >> picmip, maxsize);
- else
- {
- for (width2 = 1;width2 < inwidth;width2 <<= 1);
- for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
- }
- *outwidth = max(1, width2);
+ width2 = min(inwidth >> picmip, maxsize);
+ height2 = min(inheight >> picmip, maxsize);
+ depth2 = min(indepth >> picmip, maxsize);
}
- if (outheight)
+ else
{
- if (vid.support.arb_texture_non_power_of_two)
- height2 = min(inheight >> picmip, maxsize);
- else
- {
- for (height2 = 1;height2 < inheight;height2 <<= 1);
- for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
- }
- *outheight = max(1, height2);
+ for (width2 = 1;width2 < inwidth;width2 <<= 1);
+ for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
+ for (height2 = 1;height2 < inheight;height2 <<= 1);
+ for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
+ for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
+ for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
}
- if (outdepth)
+
+ switch(vid.renderpath)
{
- if (vid.support.arb_texture_non_power_of_two)
- depth2 = min(indepth >> picmip, maxsize);
- else
+ case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_CGGL:
+ case RENDERPATH_D3D10:
+ case RENDERPATH_D3D11:
+ break;
+ case RENDERPATH_D3D9:
+#if 0
+ // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
+ if (texturetype == GLTEXTURETYPE_2D)
{
- for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
- for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
+ width2 = max(width2, 2);
+ height2 = max(height2, 2);
}
- *outdepth = max(1, depth2);
+#endif
+ break;
}
miplevels = 1;
while(extent >>= 1)
miplevels++;
}
+
+ if (outwidth)
+ *outwidth = max(1, width2);
+ if (outheight)
+ *outheight = max(1, height2);
+ if (outdepth)
+ *outdepth = max(1, depth2);
if (outmiplevels)
*outmiplevels = miplevels;
}
break;
case RENDERPATH_D3D9:
#ifdef SUPPORTD3D
- if (glt->tiledepth > 1)
+ if (glt->d3disdepthsurface)
+ IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
+ else if (glt->tiledepth > 1)
IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
else if (glt->sides == 6)
IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture);
#ifdef SUPPORTD3D
{
HRESULT d3dresult;
- if (glt->tiledepth > 1)
+ if (glt->d3disdepthsurface)
+ {
+ if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
+ Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
+ }
+ else if (glt->tiledepth > 1)
{
if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
Cvar_RegisterVariable (&gl_nopartialtextureupdates);
+ Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
+ Cvar_RegisterVariable (&r_texture_dds_swdecode);
R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
}
CHECKGLERROR
}
-static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
+static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
{
- int i, mip, width, height, depth;
- GLint oldbindtexnum = 0;
- const unsigned char *prevbuffer;
- prevbuffer = data;
+ if (data == NULL)
+ Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
+
+ if (glt->texturetype != GLTEXTURETYPE_2D)
+ Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
+
+ if (glt->textype->textype == TEXTYPE_PALETTE)
+ Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
+
+ if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
+ Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
+
+ if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
+ Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
+
+ // update a portion of the image
switch(vid.renderpath)
{
case RENDERPATH_GL13:
case RENDERPATH_GL20:
case RENDERPATH_CGGL:
- CHECKGLERROR
-
- // we need to restore the texture binding after finishing the upload
- GL_ActiveTexture(0);
- oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
- qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
+ {
+ int oldbindtexnum;
+ CHECKGLERROR
+ // we need to restore the texture binding after finishing the upload
+ GL_ActiveTexture(0);
+ oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
+ qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
+ qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
+ qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+ }
break;
case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+ {
+ RECT d3drect;
+ D3DLOCKED_RECT d3dlockedrect;
+ int y;
+ memset(&d3drect, 0, sizeof(d3drect));
+ d3drect.left = fragx;
+ d3drect.top = fragy;
+ d3drect.right = fragx+fragwidth;
+ d3drect.bottom = fragy+fragheight;
+ if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
+ {
+ for (y = 0;y < fragheight;y++)
+ memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
+ IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
+ }
+ }
+#endif
+ break;
case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
break;
}
+}
- // these are rounded up versions of the size to do better resampling
- if (vid.support.arb_texture_non_power_of_two || glt->texturetype == GLTEXTURETYPE_RECTANGLE)
- {
- width = glt->inputwidth;
- height = glt->inputheight;
- depth = glt->inputdepth;
- }
- else
- {
- for (width = 1;width < glt->inputwidth ;width <<= 1);
- for (height = 1;height < glt->inputheight;height <<= 1);
- for (depth = 1;depth < glt->inputdepth ;depth <<= 1);
- }
+static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
+{
+ int i, mip = 0, width, height, depth;
+ GLint oldbindtexnum = 0;
+ const unsigned char *prevbuffer;
+ prevbuffer = data;
+
+ // error out if a stretch is needed on special texture types
+ if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
+ Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
+ // when picmip or maxsize is applied, we scale up to a power of 2 multiple
+ // of the target size and then use the mipmap reduction function to get
+ // high quality supersampled results
+ for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
+ for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
+ for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
- R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->sides * glt->bytesperpixel);
if (prevbuffer == NULL)
{
- memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->bytesperpixel);
+ width = glt->tilewidth;
+ height = glt->tileheight;
+ depth = glt->tiledepth;
+ memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
prevbuffer = resizebuffer;
}
else if (glt->textype->textype == TEXTYPE_PALETTE)
{
// promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
- Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth * glt->sides, glt->palette);
+ Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
prevbuffer = colorconvertbuffer;
}
- // upload the image - preferring to do only complete uploads (drivers do not really like partial updates)
+ if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
+ {
+ // multiply RGB channels by A channel before uploading
+ int alpha;
+ for (i = 0;i < width*height*depth*4;i += 4)
+ {
+ alpha = prevbuffer[i+3];
+ colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
+ colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
+ colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
+ colorconvertbuffer[i+3] = alpha;
+ }
+ prevbuffer = colorconvertbuffer;
+ }
- if ((glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) == 0 && glt->inputwidth == glt->tilewidth && glt->inputheight == glt->tileheight && glt->inputdepth == glt->tiledepth && (fragx != 0 || fragy != 0 || fragwidth != glt->tilewidth || fragheight != glt->tileheight))
+ // scale up to a power of 2 size (if appropriate)
+ if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
{
- // update a portion of the image
- if (glt->texturetype != GLTEXTURETYPE_2D)
- Sys_Error("R_Upload: partial update of type other than 2D");
- switch(vid.renderpath)
+ Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
+ prevbuffer = resizebuffer;
+ }
+ // apply mipmap reduction algorithm to get down to picmip/max_size
+ while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
+ {
+ Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
+ prevbuffer = resizebuffer;
+ }
+
+ // do the appropriate upload type...
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL11:
+ case RENDERPATH_GL13:
+ case RENDERPATH_GL20:
+ case RENDERPATH_CGGL:
+ CHECKGLERROR
+
+ // we need to restore the texture binding after finishing the upload
+ GL_ActiveTexture(0);
+ oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
+ qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
+
+ if (qglGetCompressedTexImageARB)
{
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
- qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
- break;
- case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
+ if (gl_texturecompression.integer >= 2)
+ qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
+ else
+ qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
+ CHECKGLERROR
+ }
+ switch(glt->texturetype)
+ {
+ case GLTEXTURETYPE_2D:
+ qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ if (glt->flags & TEXF_MIPMAP)
{
- RECT d3drect;
- D3DLOCKED_RECT d3dlockedrect;
- int y;
- memset(&d3drect, 0, sizeof(d3drect));
- d3drect.left = fragx;
- d3drect.top = fragy;
- d3drect.right = fragx+fragwidth;
- d3drect.bottom = fragy+fragheight;
- if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits)
+ while (width > 1 || height > 1 || depth > 1)
{
- for (y = 0;y < fragheight;y++)
- memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, (unsigned char *)prevbuffer + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel);
- IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0);
+ Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
+ prevbuffer = resizebuffer;
+ qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
}
}
-#endif
break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- }
- }
- else
- {
- if (fragx || fragy || fragz || glt->inputwidth != fragwidth || glt->inputheight != fragheight || glt->inputdepth != fragdepth)
- Host_Error("R_Upload: partial update not allowed on initial upload or in combination with PICMIP or MIPMAP\n");
-
- // cubemaps contain multiple images and thus get processed a bit differently
- if (glt->texturetype != GLTEXTURETYPE_CUBEMAP)
- {
- if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
+ case GLTEXTURETYPE_3D:
+ qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ if (glt->flags & TEXF_MIPMAP)
{
- Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
- prevbuffer = resizebuffer;
+ while (width > 1 || height > 1 || depth > 1)
+ {
+ Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
+ prevbuffer = resizebuffer;
+ qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ }
}
- // picmip/max_size
- while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
+ break;
+ case GLTEXTURETYPE_CUBEMAP:
+ // convert and upload each side in turn,
+ // from a continuous block of input texels
+ texturebuffer = (unsigned char *)prevbuffer;
+ for (i = 0;i < 6;i++)
{
- Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
- prevbuffer = resizebuffer;
+ prevbuffer = texturebuffer;
+ texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
+ if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
+ {
+ Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
+ prevbuffer = resizebuffer;
+ }
+ // picmip/max_size
+ while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
+ {
+ Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
+ prevbuffer = resizebuffer;
+ }
+ mip = 0;
+ qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ if (glt->flags & TEXF_MIPMAP)
+ {
+ while (width > 1 || height > 1 || depth > 1)
+ {
+ Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
+ prevbuffer = resizebuffer;
+ qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ }
+ }
}
+ break;
}
- mip = 0;
- switch(vid.renderpath)
+ GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
+ qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
+ break;
+ case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+ if (!(glt->flags & TEXF_RENDERTARGET))
{
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GL20:
- case RENDERPATH_CGGL:
- if (qglGetCompressedTexImageARB)
- {
- if (gl_texturecompression.integer >= 2)
- qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
- else
- qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
- CHECKGLERROR
- }
+ D3DLOCKED_RECT d3dlockedrect;
+ D3DLOCKED_BOX d3dlockedbox;
switch(glt->texturetype)
{
case GLTEXTURETYPE_2D:
- qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- if (glt->flags & TEXF_MIPMAP)
+ if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
+ {
+ if (prevbuffer)
+ memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
+ else
+ memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
+ IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
+ }
+ mip++;
+ if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
{
while (width > 1 || height > 1 || depth > 1)
{
Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
prevbuffer = resizebuffer;
- qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
+ {
+ memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
+ IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
+ }
+ mip++;
}
}
break;
case GLTEXTURETYPE_3D:
- qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
+ {
+ // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
+ memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
+ IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
+ }
+ mip++;
if (glt->flags & TEXF_MIPMAP)
{
while (width > 1 || height > 1 || depth > 1)
{
Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
prevbuffer = resizebuffer;
- qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+ if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
+ {
+ // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
+ memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
+ IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
+ }
+ mip++;
}
}
break;
prevbuffer = resizebuffer;
}
mip = 0;
- qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- if (glt->flags & TEXF_MIPMAP)
- {
- while (width > 1 || height > 1 || depth > 1)
- {
- Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
- prevbuffer = resizebuffer;
- qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
- }
- }
- }
- break;
- case GLTEXTURETYPE_RECTANGLE:
- qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
- break;
- }
- GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
- qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
- break;
- case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
- if (!(glt->flags & TEXF_RENDERTARGET))
- {
- D3DLOCKED_RECT d3dlockedrect;
- D3DLOCKED_BOX d3dlockedbox;
- switch(glt->texturetype)
- {
- case GLTEXTURETYPE_2D:
- if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
- {
- if (prevbuffer)
- memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
- else
- memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel);
- IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
- }
- mip++;
- if ((glt->flags & TEXF_MIPMAP) && prevbuffer)
+ if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
{
- while (width > 1 || height > 1 || depth > 1)
- {
- Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
- prevbuffer = resizebuffer;
- if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
- {
- memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
- IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip);
- }
- mip++;
- }
- }
- break;
- case GLTEXTURETYPE_3D:
- if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
- {
- // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
- memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
- IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
+ memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
+ IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
}
mip++;
if (glt->flags & TEXF_MIPMAP)
{
Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
prevbuffer = resizebuffer;
- if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits)
+ if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
{
- // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes
- memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel);
- IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip);
+ memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
+ IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
}
mip++;
}
}
- break;
- case GLTEXTURETYPE_CUBEMAP:
- // convert and upload each side in turn,
- // from a continuous block of input texels
- texturebuffer = (unsigned char *)prevbuffer;
- for (i = 0;i < 6;i++)
- {
- prevbuffer = texturebuffer;
- texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel;
- if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
- {
- Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer);
- prevbuffer = resizebuffer;
- }
- // picmip/max_size
- while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
- {
- Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
- prevbuffer = resizebuffer;
- }
- mip = 0;
- if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
- {
- memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
- IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
- }
- mip++;
- if (glt->flags & TEXF_MIPMAP)
- {
- while (width > 1 || height > 1 || depth > 1)
- {
- Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
- prevbuffer = resizebuffer;
- if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits)
- {
- memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel);
- IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip);
- }
- mip++;
- }
- }
- }
- break;
- case GLTEXTURETYPE_RECTANGLE:
- Sys_Error("Direct3D does not have RECTANGLE textures\n");
- break;
}
+ break;
}
- glt->d3daddressw = 0;
- if (glt->flags & TEXF_CLAMP)
- {
- glt->d3daddressu = D3DTADDRESS_CLAMP;
- glt->d3daddressv = D3DTADDRESS_CLAMP;
- if (glt->tiledepth > 1)
- glt->d3daddressw = D3DTADDRESS_CLAMP;
- }
- else
- {
- glt->d3daddressu = D3DTADDRESS_WRAP;
- glt->d3daddressv = D3DTADDRESS_WRAP;
- if (glt->tiledepth > 1)
- glt->d3daddressw = D3DTADDRESS_WRAP;
- }
- glt->d3dmipmaplodbias = 0;
- glt->d3dmaxmiplevel = 0;
- glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
- if (glt->flags & TEXF_FORCELINEAR)
- {
- glt->d3dminfilter = D3DTEXF_LINEAR;
- glt->d3dmagfilter = D3DTEXF_LINEAR;
- glt->d3dmipfilter = D3DTEXF_POINT;
- }
- else if (glt->flags & TEXF_FORCENEAREST)
- {
- glt->d3dminfilter = D3DTEXF_POINT;
- glt->d3dmagfilter = D3DTEXF_POINT;
- glt->d3dmipfilter = D3DTEXF_POINT;
- }
- else if (glt->flags & TEXF_MIPMAP)
- {
- glt->d3dminfilter = d3d_filter_mipmin;
- glt->d3dmagfilter = d3d_filter_mipmag;
- glt->d3dmipfilter = d3d_filter_mipmix;
- }
- else
- {
- glt->d3dminfilter = d3d_filter_flatmin;
- glt->d3dmagfilter = d3d_filter_flatmag;
- glt->d3dmipfilter = d3d_filter_flatmix;
- }
-#endif
- break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
}
+ glt->d3daddressw = 0;
+ if (glt->flags & TEXF_CLAMP)
+ {
+ glt->d3daddressu = D3DTADDRESS_CLAMP;
+ glt->d3daddressv = D3DTADDRESS_CLAMP;
+ if (glt->tiledepth > 1)
+ glt->d3daddressw = D3DTADDRESS_CLAMP;
+ }
+ else
+ {
+ glt->d3daddressu = D3DTADDRESS_WRAP;
+ glt->d3daddressv = D3DTADDRESS_WRAP;
+ if (glt->tiledepth > 1)
+ glt->d3daddressw = D3DTADDRESS_WRAP;
+ }
+ glt->d3dmipmaplodbias = 0;
+ glt->d3dmaxmiplevel = 0;
+ glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel;
+ if (glt->flags & TEXF_FORCELINEAR)
+ {
+ glt->d3dminfilter = D3DTEXF_LINEAR;
+ glt->d3dmagfilter = D3DTEXF_LINEAR;
+ glt->d3dmipfilter = D3DTEXF_POINT;
+ }
+ else if (glt->flags & TEXF_FORCENEAREST)
+ {
+ glt->d3dminfilter = D3DTEXF_POINT;
+ glt->d3dmagfilter = D3DTEXF_POINT;
+ glt->d3dmipfilter = D3DTEXF_POINT;
+ }
+ else if (glt->flags & TEXF_MIPMAP)
+ {
+ glt->d3dminfilter = d3d_filter_mipmin;
+ glt->d3dmagfilter = d3d_filter_mipmag;
+ glt->d3dmipfilter = d3d_filter_mipmix;
+ }
+ else
+ {
+ glt->d3dminfilter = d3d_filter_flatmin;
+ glt->d3dmagfilter = d3d_filter_flatmag;
+ glt->d3dmipfilter = d3d_filter_flatmix;
+ }
+#endif
+ break;
+ case RENDERPATH_D3D10:
+ Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
+ case RENDERPATH_D3D11:
+ Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+ break;
}
}
if (cls.state == ca_dedicated)
return NULL;
- if (texturetype == GLTEXTURETYPE_RECTANGLE && !vid.support.arb_texture_rectangle)
- {
- Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
- return NULL;
- }
if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map)
{
Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
glt->d3dformat = d3dformat;
glt->d3dusage = d3dusage;
glt->d3dpool = d3dpool;
- if (glt->tiledepth > 1)
+ glt->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
+ if (glt->d3disdepthsurface)
+ {
+ if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
+ Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
+ }
+ else if (glt->tiledepth > 1)
{
if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL)))
Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!");
break;
}
- R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+ R_UploadFullTexture(glt, data);
if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer)
glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
}
-rtexture_t *R_LoadTextureRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
-{
- return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_RECTANGLE, data, palette);
-}
-
static int R_ShadowMapTextureFlags(int precision, qboolean filter)
{
int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
return flags;
}
-rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
-{
- return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
-}
-
rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
{
return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
}
-rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
-{
- return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
-}
-
-int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed)
+int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
{
gltexture_t *glt = (gltexture_t *)rt;
unsigned char *dds;
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 premultiplied alpha, say so in the DDS file
+ if(glt->flags & TEXF_RGBMULTIPLYBYALPHA)
+ {
+ switch(internalformat)
+ {
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
+ }
+ }
if (!bytesperblock && skipuncompressed)
return -3; // skipped
memset(mipinfo, 0, sizeof(mipinfo));
else
{
dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
- dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
+ dds_format_flags = 0x40; // DDPF_RGB
}
if (mipmaps)
{
dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
}
+ if(hasalpha)
+ dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
memcpy(dds, "DDS ", 4);
StoreLittleLong(dds+4, ddssize);
StoreLittleLong(dds+8, dds_flags);
gltexture_t *glt;
gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
textypeinfo_t *texinfo;
- int mip, mipwidth, mipheight, mipsize;
+ int mip, mipwidth, mipheight, mipsize, mipsize_total;
unsigned int c;
GLint oldbindtexnum = 0;
- const unsigned char *mippixels, *ddspixels;
+ const unsigned char *mippixels, *ddspixels, *mippixels_start;
unsigned char *dds;
fs_offset_t ddsfilesize;
unsigned int ddssize;
+ qboolean force_swdecode = (r_texture_dds_swdecode.integer > 1);
if (cls.state == ca_dedicated)
return NULL;
dds_height = BuffLittleLong(dds+12);
ddspixels = dds + 128;
+ if(r_texture_dds_load_alphamode.integer == 0)
+ if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
+ flags &= ~TEXF_ALPHA;
+
//flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
{
Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
return NULL;
}
- // check alpha
- for (i = 3;i < size;i += 4)
- if (ddspixels[i] < 255)
- break;
- if (i >= size)
- flags &= ~TEXF_ALPHA;
+ if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
+ {
+ // 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))
{
Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
return NULL;
}
- 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;
- else
- flags &= ~TEXF_ALPHA;
+ if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
+ {
+ if(r_texture_dds_load_alphamode.integer == 1)
+ {
+ // check alpha
+ for (i = 0;i < size;i += bytesperblock)
+ if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
+ {
+ // NOTE: this assumes sizeof(unsigned int) == 4
+ unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
+ // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
+ if(data & (data<<1) & 0xAAAAAAAA)//rgh
+ break;
+ }
+ if (i < size)
+ textype = TEXTYPE_DXT1A;
+ else
+ flags &= ~TEXF_ALPHA;
+ }
+ else
+ {
+ flags &= ~TEXF_ALPHA;
+ }
+ }
}
- else if (!memcmp(dds+84, "DXT3", 4))
+ else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
{
+ if(!memcmp(dds+84, "DXT2", 4))
+ {
+ if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
+ {
+ Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
+ }
+ }
+ else
+ {
+ if(flags & TEXF_RGBMULTIPLYBYALPHA)
+ {
+ Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
+ }
+ }
textype = TEXTYPE_DXT3;
bytesperblock = 16;
bytesperpixel = 0;
Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
return NULL;
}
+ // we currently always assume alpha
}
- else if (!memcmp(dds+84, "DXT5", 4))
+ else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
{
+ if(!memcmp(dds+84, "DXT4", 4))
+ {
+ if(!(flags & TEXF_RGBMULTIPLYBYALPHA))
+ {
+ Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
+ }
+ }
+ else
+ {
+ if(flags & TEXF_RGBMULTIPLYBYALPHA)
+ {
+ Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
+ }
+ }
textype = TEXTYPE_DXT5;
bytesperblock = 16;
bytesperpixel = 0;
Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
return NULL;
}
+ // we currently always assume alpha
}
else
{
return NULL;
}
+ force_swdecode = false;
+ if(bytesperblock)
+ {
+ if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc)
+ {
+ if(r_texture_dds_swdecode.integer > 1)
+ force_swdecode = true;
+ }
+ else
+ {
+ if(r_texture_dds_swdecode.integer < 1)
+ {
+ // unsupported
+ Mem_Free(dds);
+ return NULL;
+ }
+ force_swdecode = true;
+ }
+ }
+
// return whether this texture is transparent
if (hasalphaflag)
*hasalphaflag = (flags & TEXF_ALPHA) != 0;
+ // if we SW decode, choose 2 sizes bigger
+ if(force_swdecode)
+ {
+ // this is quarter res, so do not scale down more than we have to
+ miplevel -= 2;
+
+ if(miplevel < 0)
+ Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
+ }
+
+ // this is where we apply gl_picmip
+ mippixels_start = ddspixels;
+ mipwidth = dds_width;
+ mipheight = dds_height;
+ while(miplevel >= 1 && dds_miplevels >= 1)
+ {
+ if (mipwidth <= 1 && mipheight <= 1)
+ break;
+ mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
+ mippixels_start += mipsize; // just skip
+ --dds_miplevels;
+ --miplevel;
+ if (mipwidth > 1)
+ mipwidth >>= 1;
+ if (mipheight > 1)
+ mipheight >>= 1;
+ }
+ mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
+ mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
+
+ // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
+
+ // fake decode S3TC if needed
+ if(force_swdecode)
+ {
+ int mipsize_new = mipsize_total / bytesperblock * 4;
+ unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
+ unsigned char *p = mipnewpixels;
+ for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
+ {
+ c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3];
+ p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
+ p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
+ p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
+ if(textype == TEXTYPE_DXT5)
+ p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
+ else if(textype == TEXTYPE_DXT3)
+ p[3] = (
+ (mippixels_start[i-8] & 0x0F)
+ + (mippixels_start[i-8] >> 4)
+ + (mippixels_start[i-7] & 0x0F)
+ + (mippixels_start[i-7] >> 4)
+ + (mippixels_start[i-6] & 0x0F)
+ + (mippixels_start[i-6] >> 4)
+ + (mippixels_start[i-5] & 0x0F)
+ + (mippixels_start[i-5] >> 4)
+ ) * (0.125f / 15.0f * 255.0f);
+ else
+ p[3] = 255;
+ }
+
+ textype = TEXTYPE_BGRA;
+ bytesperblock = 0;
+ bytesperpixel = 4;
+
+ // as each block becomes a pixel, we must use pixel count for this
+ mipwidth = (mipwidth + 3) / 4;
+ mipheight = (mipheight + 3) / 4;
+ mipsize = bytesperpixel * mipwidth * mipheight;
+ mippixels_start = mipnewpixels;
+ mipsize_total = mipsize_new;
+ }
+
+ // start mip counting
+ mippixels = mippixels_start;
+
// calculate average color if requested
if (avgcolor)
{
Vector4Clear(avgcolor);
if (bytesperblock)
{
- for (i = bytesperblock == 16 ? 8 : 0;i < size;i += bytesperblock)
+ for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
{
- c = ddspixels[i] + 256*ddspixels[i+1] + 65536*ddspixels[i+2] + 16777216*ddspixels[i+3];
+ c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[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);
+ if(textype == TEXTYPE_DXT5)
+ avgcolor[3] += (0.5 * mippixels[i-8] + 0.5 * mippixels[i-7]);
+ else if(textype == TEXTYPE_DXT3)
+ avgcolor[3] += (
+ (mippixels_start[i-8] & 0x0F)
+ + (mippixels_start[i-8] >> 4)
+ + (mippixels_start[i-7] & 0x0F)
+ + (mippixels_start[i-7] >> 4)
+ + (mippixels_start[i-6] & 0x0F)
+ + (mippixels_start[i-6] >> 4)
+ + (mippixels_start[i-5] & 0x0F)
+ + (mippixels_start[i-5] >> 4)
+ ) * (0.125f / 15.0f * 255.0f);
+ else
+ avgcolor[3] += 255;
}
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
+ avgcolor[3] *= f;
}
else
{
- for (i = 0;i < size;i += 4)
+ for (i = 0;i < mipsize;i += 4)
{
- avgcolor[0] += ddspixels[i+2];
- avgcolor[1] += ddspixels[i+1];
- avgcolor[2] += ddspixels[i];
- avgcolor[3] += ddspixels[i+3];
+ avgcolor[0] += mippixels[i+2];
+ avgcolor[1] += mippixels[i+1];
+ avgcolor[2] += mippixels[i];
+ avgcolor[3] += mippixels[i+3];
}
f = (1.0f / 255.0f) * bytesperpixel / size;
avgcolor[0] *= f;
}
}
- // this is where we apply gl_picmip
- mippixels = ddspixels;
- mipwidth = dds_width;
- mipheight = dds_height;
- while(miplevel >= 1 && dds_miplevels >= 1)
- {
- if (mipwidth <= 1 && mipheight <= 1)
- break;
- mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
- mippixels += mipsize; // just skip
- --dds_miplevels;
- --miplevel;
- if (mipwidth > 1)
- mipwidth >>= 1;
- if (mipheight > 1)
- mipheight >>= 1;
- }
-
// when not requesting mipmaps, do not load them
if(!(flags & TEXF_MIPMAP))
dds_miplevels = 0;
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_ExpandableArray_AllocRecord(&texturearray);
for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
{
mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
- if (mippixels + mipsize > dds + ddssize)
+ if (mippixels + mipsize > mippixels_start + mipsize_total)
break;
switch(vid.renderpath)
{
}
Mem_Free(dds);
+ if(force_swdecode)
+ Mem_Free((unsigned char *) mippixels_start);
return (rtexture_t *)glt;
}
Host_Error("R_UpdateTexture: no texture supplied");
if (!glt->texnum && !glt->d3dtexture)
{
- Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", glt, glt->identifier, glt->pool);
+ Con_Printf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet", (void *)glt, glt->identifier, (void *)glt->pool);
return;
}
// update part of the texture
for (j = 0;j < height;j++, output += outputskip, input += inputskip)
memcpy(output, input, width*bpp);
}
+ else if (x || y || width != glt->inputwidth || height != glt->inputheight)
+ R_UploadPartialTexture(glt, data, x, y, 0, width, height, 1);
else
- R_Upload(glt, data, x, y, 0, width, height, 1);
+ R_UploadFullTexture(glt, data);
}
int R_RealGetTexture(rtexture_t *rt)
if (glt->buffermodified && glt->bufferpixels)
{
glt->buffermodified = false;
- R_Upload(glt, glt->bufferpixels, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth);
+ R_UploadFullTexture(glt, glt->bufferpixels);
}
glt->dirty = false;
return glt->texnum;
{
gltexture_t *glt = (gltexture_t *)rt;
- R_Upload( glt, NULL, 0, 0, 0, glt->tilewidth, glt->tileheight, glt->tiledepth );
+ R_UploadFullTexture(glt, NULL);
}
int R_PicmipForFlags(int flags)