]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_textures.c
make csqc render entities persistent (except the temp ones created by a
[xonotic/darkplaces.git] / gl_textures.c
index 1051a7a75490bfcb27b10a826d8bc356e0bf8957..bc6494e8735c57cfb4563d19fa0544cb5bc227a9 100644 (file)
@@ -60,8 +60,8 @@ static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA   , 4, 4, 4.
 static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
 static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA   , 4, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
 static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA   , 4, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
-static textypeinfo_t textype_shadowmap              = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_ARB, GL_UNSIGNED_INT};
-static textypeinfo_t textype_projection             = {TEXTYPE_PROJECTION,4,4,4.0f, GL_LUMINANCE_ALPHA, GL_LUMINANCE16_ALPHA16, GL_UNSIGNED_SHORT};
+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};
 
 typedef enum gltexturetype_e
 {
@@ -218,9 +218,7 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
                        case TEXTYPE_BGRA:
                                return &textype_bgra;
                        case TEXTYPE_SHADOWMAP:
-                               return &textype_shadowmap;
-                       case TEXTYPE_PROJECTION:
-                               return &textype_projection;
+                               return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
                        default:
                                Host_Error("R_GetTexTypeInfo: unknown texture format");
                                return NULL;
@@ -267,41 +265,6 @@ static void R_UpdateDynamicTexture(gltexture_t *glt) {
        }
 }
 
-static void R_UploadTexture(gltexture_t *t);
-
-static void R_PrecacheTexture(gltexture_t *glt)
-{
-       int precache;
-       precache = false;
-       if (glt->flags & TEXF_ALWAYSPRECACHE)
-               precache = true;
-       else if (r_precachetextures.integer >= 2)
-               precache = true;
-       else if (r_precachetextures.integer >= 1)
-               if (glt->flags & TEXF_PRECACHE)
-                       precache = true;
-
-       if (precache)
-               R_UploadTexture(glt);
-}
-
-int R_RealGetTexture(rtexture_t *rt)
-{
-       if (rt)
-       {
-               gltexture_t *glt;
-               glt = (gltexture_t *)rt;
-               if (glt->flags & GLTEXF_DYNAMIC)
-                       R_UpdateDynamicTexture(glt);
-               if (glt->flags & GLTEXF_UPLOAD)
-                       R_UploadTexture(glt);
-
-               return glt->texnum;
-       }
-       else
-               return 0;
-}
-
 void R_PurgeTexture(rtexture_t *rt)
 {
        if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
@@ -785,17 +748,19 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
 
        if (textype == TEXTYPE_SHADOWMAP)
        {
-               if (flags & TEXF_COMPARE)
+               if (gl_support_arb_shadow)
                {
-                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
+                       if (flags & TEXF_COMPARE)
+                       {
+                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
+                       }
+                       else
+                       {
+                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
+                       }
                        qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
                }
-               else
-               {
-                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
-                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_ALWAYS);CHECKGLERROR
-               }
-               qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
        }
 
        CHECKGLERROR
@@ -973,22 +938,33 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
        qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
 }
 
-static void R_UploadTexture (gltexture_t *glt)
+int R_RealGetTexture(rtexture_t *rt)
 {
-       if (!(glt->flags & GLTEXF_UPLOAD))
-               return;
-
-       CHECKGLERROR
-       qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
-       R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
-       if (glt->inputtexels)
+       if (rt)
        {
-               Mem_Free(glt->inputtexels);
-               glt->inputtexels = NULL;
-               glt->flags |= GLTEXF_DESTROYED;
+               gltexture_t *glt;
+               glt = (gltexture_t *)rt;
+               if (glt->flags & GLTEXF_DYNAMIC)
+                       R_UpdateDynamicTexture(glt);
+               if (glt->flags & GLTEXF_UPLOAD)
+               {
+                       CHECKGLERROR
+                       qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+                       R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+                       if (glt->inputtexels)
+                       {
+                               Mem_Free(glt->inputtexels);
+                               glt->inputtexels = NULL;
+                               glt->flags |= GLTEXF_DESTROYED;
+                       }
+                       else if (glt->flags & GLTEXF_DESTROYED)
+                               Con_Printf("R_GetTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
+               }
+
+               return glt->texnum;
        }
-       else if (glt->flags & GLTEXF_DESTROYED)
-               Con_Printf("R_UploadTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
+       else
+               return 0;
 }
 
 static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
@@ -997,6 +973,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        gltexture_t *glt;
        gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
        textypeinfo_t *texinfo;
+       int precache;
 
        if (cls.state == ca_dedicated)
                return NULL;
@@ -1064,7 +1041,6 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                }
                break;
        case TEXTYPE_SHADOWMAP:
-       case TEXTYPE_PROJECTION:
                break;
        default:
                Host_Error("R_LoadTexture: unknown texture type");
@@ -1095,16 +1071,45 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        glt->updatecallback = NULL;
        glt->updatacallback_data = NULL;
 
-       if (data)
+       GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
+
+       precache = false;
+       if (glt->flags & TEXF_ALWAYSPRECACHE)
+               precache = true;
+       else if (r_precachetextures.integer >= 2)
+               precache = true;
+       else if (r_precachetextures.integer >= 1)
+               if (glt->flags & TEXF_PRECACHE)
+                       precache = true;
+
+       if (precache)
        {
-               glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, size);
-               memcpy(glt->inputtexels, data, size);
+               // immediate upload (most common case)
+               // data may be NULL (blank texture for dynamic rendering)
+               CHECKGLERROR
+               qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
+               R_Upload(glt, data, 0, 0, 0, glt->inputwidth, glt->inputheight, glt->inputdepth);
+       }
+       else if (data)
+       {
+               // deferred texture upload (menu graphics)
+               // optimize first if possible
+               if ((textype == TEXTYPE_BGRA || textype == TEXTYPE_RGBA) && glt->inputwidth * glt->inputheight * glt->inputdepth > glt->tilewidth * glt->tileheight * glt->tiledepth)
+               {
+                       glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
+                       Image_Resample32(data, glt->inputwidth, glt->inputheight, glt->inputdepth, glt->inputtexels, glt->tilewidth, glt->tileheight, glt->tiledepth, r_lerpimages.integer);
+                       // change texture size accordingly
+                       glt->inputwidth = glt->tilewidth;
+                       glt->inputheight = glt->tileheight;
+                       glt->inputdepth = glt->tiledepth;
+                       GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
+               }
+               else
+               {
+                       glt->inputtexels = (unsigned char *)Mem_Alloc(texturemempool, size);
+                       memcpy(glt->inputtexels, data, size);
+               }
        }
-       else
-               glt->inputtexels = NULL;
-
-       GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth);
-       R_PrecacheTexture(glt);
 
        // texture converting and uploading can take a while, so make sure we're sending keepalives
        CL_KeepaliveMessage(false);
@@ -1132,53 +1137,31 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident
        return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
 }
 
-rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, qboolean filter)
+static int R_ShadowMapTextureFlags(int precision, qboolean filter)
 {
-       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_ALWAYSPRECACHE | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR | TEXF_COMPARE : TEXF_FORCENEAREST), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
+       int flags = TEXF_ALWAYSPRECACHE | TEXF_CLAMP;
+       if (filter)
+               flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
+       else
+               flags |= TEXF_FORCENEAREST;
+       if (precision <= 16)
+               flags |= TEXF_LOWPRECISION;
+       return flags;
 }
 
-rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, qboolean filter)
+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, TEXF_ALWAYSPRECACHE | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR | TEXF_COMPARE : TEXF_FORCENEAREST), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
 }
 
-rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, qboolean filter)
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
 {
-    return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, TEXF_ALWAYSPRECACHE | TEXF_CLAMP | TEXF_COMPARE | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
 }
 
-rtexture_t *R_LoadTextureCubeProjection(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int size, int border)
+rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width, int precision, qboolean filter)
 {
-    // maps to a 2x3 texture rectangle with normalized coordinates (must be scaled by size after lookup)
-    // +-
-    // XX
-    // YY
-    // ZZ
-    rtexture_t *projection;
-       unsigned short *data, *texel;
-       unsigned int sizebits = 0, stepbits = 0, res, i, j, k;
-       while ((1 << sizebits) < size) sizebits++;
-       while ((1 << stepbits) <= border) stepbits++;
-    stepbits = min(stepbits, sizebits);
-       res = size>>stepbits;
-       stepbits += 16 - sizebits - 1;
-       data = (unsigned short *)Mem_Alloc(texturemempool, 2*sizeof(unsigned short)*res*res*6);
-       texel = data;
-       for (i = 0;i < 6;i++) 
-       {
-               unsigned int x = (i%2)<<16, y = (i/2)<<16;
-               for (j = 0;j < res;j++)
-               {
-                       for (k = 0;k < res;k++)
-                       {
-                               *texel++ = (x + ((2*k + 1)<<stepbits))/width;
-                               *texel++ = (y + ((2*j + 1)<<stepbits))/height;
-                       }
-               }
-       }
-       projection = R_SetupTexture(rtexturepool, identifier, res, res, 1, 6, TEXF_ALWAYSPRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, TEXTYPE_PROJECTION, GLTEXTURETYPE_CUBEMAP, (unsigned char *)data, NULL);
-       Mem_Free(data);
-    return projection;
+    return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
 }
 
 int R_TextureHasAlpha(rtexture_t *rt)
@@ -1203,13 +1186,12 @@ void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, in
                Host_Error("R_UpdateTexture: no texture supplied");
        if (data == NULL)
                Host_Error("R_UpdateTexture: no data supplied");
-       glt = (gltexture_t *)rt;
 
        // we need it to be uploaded before we can update a part of it
-       if (glt->flags & GLTEXF_UPLOAD)
-               R_UploadTexture(glt);
+       R_RealGetTexture(rt);
 
        // update part of the texture
+       glt = (gltexture_t *)rt;
        R_Upload(glt, data, x, y, 0, width, height, 1);
 }