]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_textures.c
if a skyboxskinframe is missing, don't draw that sky surface (fixes crash if some...
[xonotic/darkplaces.git] / gl_textures.c
index 0d8c0feb5898d1b1e10bb714228bed65b5efe1d6..b5affacbe2b678218fcea8a18aa32ba1ab39e86e 100644 (file)
@@ -95,13 +95,12 @@ typedef enum gltexturetype_e
        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,
@@ -122,6 +121,7 @@ typedef struct gltexture_s
        // d3d stuff the backend needs
        void *d3dtexture;
 #ifdef SUPPORTD3D
+       qboolean d3disdepthsurface; // for depth/stencil surfaces
        int d3dformat;
        int d3dusage;
        int d3dpool;
@@ -292,10 +292,37 @@ void R_FreeTexture(rtexture_t *rt)
        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)
@@ -459,7 +486,7 @@ static void GL_TextureMode_f (void)
                        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)
                                        {
@@ -493,25 +520,6 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i
 {
        int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
 
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_CGGL:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-               break;
-       case RENDERPATH_D3D9:
-               // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures...
-               if (indepth == 1)
-               {
-                       width2 = max(width2, 2);
-                       height2 = max(height2, 2);
-               }
-               break;
-       }
-
        switch (texturetype)
        {
        default:
@@ -531,38 +539,41 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i
                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;
@@ -572,6 +583,13 @@ static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, i
                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;
 }
@@ -730,7 +748,9 @@ static void r_textures_devicelost(void)
                        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);
@@ -770,7 +790,12 @@ static void r_textures_devicerestored(void)
 #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!");
@@ -1094,6 +1119,21 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                prevbuffer = colorconvertbuffer;
        }
 
+       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;
+       }
+
        // scale up to a power of 2 size (if appropriate)
        if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
        {
@@ -1187,9 +1227,6 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                }
                        }
                        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
@@ -1293,9 +1330,6 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        }
                                }
                                break;
-                       case GLTEXTURETYPE_RECTANGLE:
-                               Sys_Error("Direct3D does not have RECTANGLE textures\n");
-                               break;
                        }
                }
                glt->d3daddressw = 0;
@@ -1362,11 +1396,6 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        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");
@@ -1527,7 +1556,13 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        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!");
@@ -1583,11 +1618,6 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident
        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;
@@ -1600,21 +1630,11 @@ static int R_ShadowMapTextureFlags(int precision, qboolean filter)
        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, qboolean hasalpha)
 {
        gltexture_t *glt = (gltexture_t *)rt;
@@ -1651,6 +1671,15 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        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));
@@ -1853,8 +1882,22 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        }
                }
        }
-       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);
+                       }
+               }
                if(!vid.support.ext_texture_compression_s3tc)
                {
                        Mem_Free(dds);
@@ -1872,8 +1915,22 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                }
                // 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);
+                       }
+               }
                if(!vid.support.ext_texture_compression_s3tc)
                {
                        Mem_Free(dds);