Fix bugs with unloading of cachepic skinframes in QC menus - the reloading was broken...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 30 Apr 2018 06:38:44 +0000 (06:38 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 30 Apr 2018 06:38:44 +0000 (06:38 +0000)
Simplify Draw_CachePic behaviors with regards to NewPic and textureflags (mismatch now causes texture reload rather than having multiple with the same name in memory).

Improved reloading of unloaded pics by reusing the existing skinframe, so it can not produce duplicates.

Make Draw_NewPic clear the pic->autoload flag, this is a behavior change in VM_CL_ReadPicture.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12407 d7cf8633-e32d-0410-b094-e92efae38249

gl_draw.c
gl_rmain.c
render.h

index 47a90f9..b33200f 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -105,23 +105,19 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
                if (!strcmp(path, pic->name))
                {
                        // if it was created (or replaced) by Draw_NewPic, just return it
-                       if (pic->flags & CACHEPICFLAG_NEWPIC)
+                       if (!(pic->flags & CACHEPICFLAG_NEWPIC))
                        {
-                               if (pic->skinframe)
-                                       R_SkinFrame_MarkUsed(pic->skinframe);
-                               pic->lastusedframe = draw_frame;
-                               return pic;
-                       }
-                       if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that
-                       {
-                               if (!pic->skinframe || !pic->skinframe->base)
+                               // reload the pic if texflags changed in important ways
+                               // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that
+                               if (!pic->skinframe || !pic->skinframe->base || ((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP)))
                                        goto reload;
                                if (!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT))
                                        pic->autoload = false; // caller is making this pic persistent
-                               R_SkinFrame_MarkUsed(pic->skinframe);
-                               pic->lastusedframe = draw_frame;
-                               return pic;
                        }
+                       if (pic->skinframe)
+                               R_SkinFrame_MarkUsed(pic->skinframe);
+                       pic->lastusedframe = draw_frame;
+                       return pic;
                }
        }
 
@@ -147,8 +143,16 @@ reload:
        pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT) != 0;
        pic->lastusedframe = draw_frame;
 
-       // load high quality image (this falls back to low quality too)
-       pic->skinframe = R_SkinFrame_LoadExternal(pic->name, texflags | TEXF_FORCE_RELOAD, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0);
+       if (pic->skinframe)
+       {
+               // reload image after it was unloaded or texflags changed significantly
+               R_SkinFrame_LoadExternal_SkinFrame(pic->skinframe, pic->name, texflags | TEXF_FORCE_RELOAD, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0);
+       }
+       else
+       {
+               // load high quality image (this falls back to low quality too)
+               pic->skinframe = R_SkinFrame_LoadExternal(pic->name, texflags | TEXF_FORCE_RELOAD, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0);
+       }
 
        // get the dimensions of the image we loaded (if it was successful)
        if (pic->skinframe && pic->skinframe->base)
@@ -262,6 +266,7 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, unsigned cha
 
        R_SkinFrame_PurgeSkinFrame(pic->skinframe);
 
+       pic->autoload = false;
        pic->flags = CACHEPICFLAG_NEWPIC; // disable texflags checks in Draw_CachePic
        pic->flags |= (texflags & TEXF_CLAMP) ? 0 : CACHEPICFLAG_NOCLAMP;
        pic->flags |= (texflags & TEXF_FORCENEAREST) ? CACHEPICFLAG_NEAREST : 0;
@@ -759,6 +764,8 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo
        int e0, e1, e2, e3;
        if (!pic)
                pic = Draw_CachePic("white");
+       // make sure pic is loaded - we don't use the texture here, Mod_Mesh_GetTexture looks up the skinframe by name
+       Draw_GetPicTexture(pic);
        if (width == 0)
                width = pic->width;
        if (height == 0)
@@ -785,6 +792,8 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
        int e0, e1, e2, e3;
        if (!pic)
                pic = Draw_CachePic("white");
+       // make sure pic is loaded - we don't use the texture here, Mod_Mesh_GetTexture looks up the skinframe by name
+       Draw_GetPicTexture(pic);
        if (width == 0)
                width = pic->width;
        if (height == 0)
@@ -1379,6 +1388,8 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
        int e0, e1, e2, e3;
        if (!pic)
                pic = Draw_CachePic("white");
+       // make sure pic is loaded - we don't use the texture here, Mod_Mesh_GetTexture looks up the skinframe by name
+       Draw_GetPicTexture(pic);
        if (width == 0)
                width = pic->width;
        if (height == 0)
index 6fc7852..5efd843 100644 (file)
@@ -2278,16 +2278,32 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid
                skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
        }
 
-extern cvar_t gl_picmip;
 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
 {
+       skinframe_t *skinframe;
+
+       if (cls.state == ca_dedicated)
+               return NULL;
+
+       // return an existing skinframe if already loaded
+       // if loading of the first image fails, don't make a new skinframe as it
+       // would cause all future lookups of this to be missing
+       skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
+       if (skinframe && skinframe->base)
+               return skinframe;
+
+       return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
+}
+
+extern cvar_t gl_picmip;
+skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
+{
        int j;
        unsigned char *pixels;
        unsigned char *bumppixels;
        unsigned char *basepixels = NULL;
        int basepixels_width = 0;
        int basepixels_height = 0;
-       skinframe_t *skinframe;
        rtexture_t *ddsbase = NULL;
        qboolean ddshasalpha = false;
        float ddsavgcolor[4];
@@ -2300,13 +2316,6 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        if (cls.state == ca_dedicated)
                return NULL;
 
-       // return an existing skinframe if already loaded
-       // if loading of the first image fails, don't make a new skinframe as it
-       // would cause all future lookups of this to be missing
-       skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
-       if (skinframe && skinframe->base)
-               return skinframe;
-
        Image_StripImageExtension(name, basename, sizeof(basename));
 
        // check for DDS texture file first
@@ -2512,7 +2521,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
                return NULL;
 
        // if already loaded just return it, otherwise make a new skinframe
-       skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : skindata ? CRC_Block(skindata, width*height*4) : 0, true);
+       skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
        if (skinframe->base)
                return skinframe;
        textureflags &= ~TEXF_FORCE_RELOAD;
@@ -2582,7 +2591,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i
                return NULL;
 
        // if already loaded just return it, otherwise make a new skinframe
-       skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
+       skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
        if (skinframe->base)
                return skinframe;
        //textureflags &= ~TEXF_FORCE_RELOAD;
index ce95a4b..dcacb63 100644 (file)
--- a/render.h
+++ b/render.h
@@ -280,6 +280,7 @@ void R_SkinFrame_Purge(void);
 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name );
 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add);
 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture);
+skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture);
 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB);
 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height);
 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette);