WIP texture cache refactoring

git-svn-id: https://svn.eduke32.com/eduke32@3758 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
terminx 2013-05-15 02:17:17 +00:00
parent 80f645c65e
commit 08444cb825
19 changed files with 1125 additions and 1167 deletions

View file

@ -5,6 +5,7 @@ duke3d_h=\
$(EINC)/baselayer.h \
$(EINC)/polymer.h \
$(EINC)/polymost.h \
$(EINC)/texcache.h \
$(EINC)/cache1d.h \
$(SRC)/jmact/file_lib.h \
$(SRC)/jmact/keyboard.h \

View file

@ -64,6 +64,8 @@ ENGINEOBJS+= \
$(OBJ)/defs.$o \
$(OBJ)/engine.$o \
$(OBJ)/polymost.$o \
$(OBJ)/texcache.$o \
$(OBJ)/dxtfilter.$o \
$(OBJ)/hightile.$o \
$(OBJ)/textfont.$o \
$(OBJ)/smalltextfont.$o \

View file

@ -10,9 +10,11 @@ $(OBJ)/config.$o: $(SRC)/config.c $(INC)/compat.h $(INC)/osd.h $(INC)/editor.h
$(OBJ)/crc32.$o: $(SRC)/crc32.c $(INC)/crc32.h
$(OBJ)/defs.$o: $(SRC)/defs.c $(INC)/build.h $(INC)/baselayer.h $(INC)/scriptfile.h $(INC)/compat.h
$(OBJ)/engine.$o: $(SRC)/engine.c $(INC)/compat.h $(INC)/build.h $(INC)/pragmas.h $(INC)/cache1d.h $(INC)/a.h $(INC)/osd.h $(INC)/baselayer.h $(SRC)/engine_priv.h $(SRC)/engine_oldmap.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h $(INC)/polymer.h
$(OBJ)/polymost.$o: $(SRC)/polymost.c $(INC)/md4.h $(INC)/quicklz.h $(INC)/lzwnew.h $(INC)/compat.h $(INC)/build.h $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h
$(OBJ)/polymost.$o: $(SRC)/polymost.c $(INC)/md4.h $(INC)/quicklz.h $(INC)/lzwnew.h $(INC)/compat.h $(INC)/build.h $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h $(INC)/texcache.h
$(OBJ)/texcache.$o: $(SRC)/texcache.c $(INC)/texcache.h $(INC)/polymost.h $(INC)/dxtfilter.h
$(OBJ)/dxtfilter.$o: $(SRC)/dxtfilter.c $(INC)/dxtfilter.h
$(OBJ)/hightile.$o: $(SRC)/hightile.c $(INC)/kplib.h $(INC)/hightile.h
$(OBJ)/mdsprite.$o: $(SRC)/mdsprite.c $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h
$(OBJ)/mdsprite.$o: $(SRC)/mdsprite.c $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h $(INC)/texcache.h
$(OBJ)/textfont.$o: $(SRC)/textfont.c
$(OBJ)/smalltextfont.$o: $(SRC)/smalltextfont.c
$(OBJ)/glbuild.$o: $(SRC)/glbuild.c $(INC)/glbuild.h $(INC)/baselayer.h

View file

@ -67,6 +67,8 @@ ENGINEOBJS= \
$(OBJ)\defs.$o \
$(OBJ)\engine.$o \
$(OBJ)\polymost.$o \
$(OBJ)\texcache.$o \
$(OBJ)\dxtfilter.$o \
$(OBJ)\hightile.$o \
$(OBJ)\mdsprite.$o \
$(OBJ)\textfont.$o \

View file

@ -1229,7 +1229,7 @@ extern int32_t glmultisample, glnvmultisamplehint;
extern int32_t glwidescreen, glprojectionhacks;
extern int32_t gltexmaxsize;
void gltexapplyprops (void);
void invalidatecache(void);
void texcache_invalidate(void);
extern int32_t r_detailmapping;
extern int32_t r_glowmapping;

View file

@ -0,0 +1,2 @@
int32_t dxtfilter(int32_t fil, const texcachepicture *pict, const char *pic, void *midbuf, char *packbuf, uint32_t miplen);
int32_t dedxtfilter(int32_t fil, const texcachepicture *pict, char *pic, void *midbuf, char *packbuf, int32_t ispacked);

View file

@ -42,8 +42,8 @@ enum cvartype_t
CVAR_NOSAVE = 0x00000100,
CVAR_FUNCPTR = 0x00000200,
CVAR_RESTARTVID = 0x00000400,
CVAR_INVALIDATE = 0x00000800,
CVAR_INVALIDATE8 = 0x00001000,
CVAR_INVALIDATEALL = 0x00000800,
CVAR_INVALIDATEART = 0x00001000,
};
typedef struct

View file

@ -17,8 +17,6 @@ extern char cullmodel[MAXSPRITES];
extern int32_t cullcheckcnt;
#endif
extern char TEXCACHEFILE[BMAX_PATH];
typedef struct { char r, g, b, a; } coltype;
extern int32_t rendmode;
@ -49,33 +47,11 @@ void polymost_glinit(void);
void polymost_glreset(void);
void gltexinvalidate(int32_t dapicnum, int32_t dapalnum, int32_t dameth);
void gltexinvalidateall(void);
void gltexinvalidate8(void);
void gltexinvalidateall(int32_t artonly);
int32_t polymost_printext256(int32_t xpos, int32_t ypos, int16_t col, int16_t backcol, const char *name, char fontsize);
extern float curpolygonoffset;
extern int32_t cachepos;
struct cacheitem_t
{
char name[BMAX_PATH];
int32_t offset;
int32_t len;
struct cacheitem_t *next;
};
typedef struct cacheitem_t texcacheindex;
#define TEXCACHEMAGIC "QLZ1"
int32_t dxtfilter(int32_t fil, const texcachepicture *pict, const char *pic, void *midbuf, char *packbuf, uint32_t miplen);
int32_t dedxtfilter(int32_t fil, const texcachepicture *pict, char *pic, void *midbuf, char *packbuf, int32_t ispacked);
void writexcache(const char *fn, int32_t len, int32_t dameth, char effect, texcacheheader *head);
int32_t polymost_trytexcache(const char *fn, int32_t len, int32_t dameth, char effect,
texcacheheader *head, int32_t modelp);
extern float shadescale;
extern int32_t shadescale_unbounded;
extern float alphahackarray[MAXTILES];
@ -105,13 +81,18 @@ typedef struct pthtyp_t
struct pthtyp_t *ofb; // only fullbright
} pthtyp;
pthtyp *gltexcache(int32_t dapicnum, int32_t dapalnum, int32_t dameth);
extern int32_t gloadtile_art(int32_t,int32_t,int32_t,pthtyp *,int32_t);
extern int32_t gloadtile_hi(int32_t,int32_t,int32_t,hicreplctyp *,int32_t,pthtyp *,int32_t,char);
extern int32_t globalnoeffect;
extern int32_t drawingskybox;
extern int32_t hicprecaching;
extern double gyxscale, gxyaspect, ghalfx, grhalfxdown10;
extern char ptempbuf[MAXWALLSB<<1];
#include "texcache.h"
#endif
#endif

View file

@ -0,0 +1,43 @@
#ifndef _texcache_h_
# define _texcache_h_
#ifdef USE_OPENGL
#define TEXCACHEMAGIC "QLZ1"
#define GLTEXCACHEADSIZ 8192
struct texcacheitem_t
{
char name[BMAX_PATH];
int32_t offset;
int32_t len;
struct texcacheitem_t *next;
};
typedef struct texcacheitem_t texcacheindex;
extern char TEXCACHEFILE[BMAX_PATH];
extern pthtyp *texcache_head[GLTEXCACHEADSIZ];
extern FILE *texcache_indexptr;
extern int32_t texcache_noalloc;
extern int32_t texcache_memsize;
extern uint8_t *texcache_memptr;
extern int32_t texcache_filehandle;
extern int32_t texcache_offset;
extern texcacheindex *texcache_firstindex;
extern texcacheindex *texcache_currentindex;
extern void texcache_freeptrs(void);
extern void texcache_sync(void);
extern void texcache_init(void);
extern void texcache_clearmem(void);
extern int32_t texcache_loadoffsets(void);
extern int32_t texcache_readdata(void *dest, int32_t len);
extern pthtyp *texcache_fetch(int32_t dapicnum, int32_t dapalnum, int32_t dameth);
extern int32_t texcache_loadskin(const texcacheheader *head, int32_t *doalloc, GLuint *glpic, int32_t *xsiz, int32_t *ysiz);
extern int32_t texcache_loadtile(const texcacheheader *head, int32_t *doalloc, pthtyp *pth);
extern void texcache_writetex(const char *fn, int32_t len, int32_t dameth, char effect, texcacheheader *head);
extern int32_t texcache_readtexheader(const char *fn, int32_t len, int32_t dameth, char effect, texcacheheader *head, int32_t modelp);
#endif
#endif

View file

@ -0,0 +1,238 @@
#ifdef USE_OPENGL
/*
Description of Ken's filter to improve LZW compression of DXT1 format by ~15%: (as tested with the HRP)
To increase LZW patterns, I store each field of the DXT block structure separately.
Here are the 3 DXT fields:
1. __int64 alpha_4x4; //DXT3 only (16 byte structure size when included)
2. short rgb0, rgb1;
3. int32_t index_4x4;
Each field is then stored with its own specialized algorithm.
1. I haven't done much testing with this field - I just copy it raw without any transform for now.
2. For rgb0 and rgb1, I use a "green" filter like this:
g = g;
r = r-g;
b = b-g;
For grayscale, this makes the stream: x,0,0,x,0,0,x,0,0,... instead of x,x,x,x,x,x,x,x,...
Q:what was the significance of choosing green? A:largest/most dominant component
Believe it or not, this gave 1% better compression :P
I tried subtracting each componenet with the previous pixel, but strangely it hurt compression.
Oh, the joy of trial & error. :)
3. For index_4x4, I transform the ordering of 2-bit indices in the DXT blocks from this:
0123 0123 0123 ---- ---- ----
4567 4567 4567 ---- ---- ----
89ab 89ab 89ab ---- ---- ----
cdef cdef cdef ---- ---- ----
To this: (I swap x & y axes)
048c 048c 048c |||| |||| ||||
159d 159d 159d |||| |||| ||||
26ae 26ae 26ae |||| |||| ||||
37bf 37bf 37bf |||| |||| ||||
The trick is: going from the bottom of the 4th line to the top of the 5th line
is the exact same jump (geometrically) as from 5th to 6th, etc.. This is not true in the top case.
These silly tricks will increase patterns and therefore make LZW compress better.
I think this improved compression by a few % :)
*/
#include "compat.h"
#include "build.h"
#include "texcache.h"
#include "quicklz.h"
static uint16_t dxt_hicosub(uint16_t c)
{
int32_t r, g, b;
g = ((c>> 5)&63);
r = ((c>>11)-(g>>1))&31;
b = ((c>> 0)-(g>>1))&31;
return((r<<11)+(g<<5)+b);
}
static uint16_t dedxt_hicoadd(uint16_t c)
{
int32_t r, g, b;
g = ((c>> 5)&63);
r = ((c>>11)+(g>>1))&31;
b = ((c>> 0)+(g>>1))&31;
return((r<<11)+(g<<5)+b);
}
static void dxt_handle_io(int32_t fil, int32_t len, void *midbuf, char *packbuf)
{
void *writebuf;
int32_t j, cleng;
if (glusetexcache == 2)
{
cleng = qlz_compress(midbuf, packbuf, len, state_compress);
if (cleng == 0 || cleng > len-1)
{
cleng = len;
writebuf = midbuf;
}
else writebuf = packbuf;
}
else
{
cleng = len;
writebuf = midbuf;
}
// native -> external (little endian)
j = B_LITTLE32(cleng);
Bwrite(fil, &j, sizeof(j));
Bwrite(fil, writebuf, cleng);
}
static int32_t dedxt_handle_io(int32_t fil, int32_t j /* TODO: better name */,
void *midbuf, char *packbuf, int32_t ispacked)
{
void *inbuf;
int32_t cleng;
if (texcache_readdata(&cleng, sizeof(int32_t)))
return -1;
// external (little endian) -> native
cleng = B_LITTLE32(cleng);
inbuf = (ispacked && cleng < j) ? packbuf : midbuf;
if (texcache_memptr && texcache_memsize >= texcache_offset + cleng)
{
if (ispacked && cleng < j)
{
if (qlz_decompress((const char *)texcache_memptr + texcache_offset, midbuf, state_decompress) == 0)
{
texcache_offset += cleng;
return -1;
}
}
else Bmemcpy(inbuf, texcache_memptr + texcache_offset, cleng);
texcache_offset += cleng;
}
else
{
Blseek(fil, texcache_offset, BSEEK_SET);
texcache_offset += cleng;
if (Bread(fil, inbuf, cleng) < cleng)
return -1;
if (ispacked && cleng < j)
if (qlz_decompress(packbuf, midbuf, state_decompress) == 0)
return -1;
}
return 0;
}
// NOTE: <pict> members are in external (little) endianness.
int32_t dxtfilter(int32_t fil, const texcachepicture *pict, const char *pic, void *midbuf, char *packbuf, uint32_t miplen)
{
uint32_t j, k, offs, stride;
char *cptr;
if ((pict->format == (signed) B_LITTLE32(GL_COMPRESSED_RGB_S3TC_DXT1_EXT)) ||
(pict->format == (signed) B_LITTLE32(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT))) { offs = 0; stride = 8; }
else if ((pict->format == (signed) B_LITTLE32(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT)) ||
(pict->format == (signed) B_LITTLE32(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT))) { offs = 8; stride = 16; }
else { offs = 0; stride = 8; }
if (stride == 16) //If DXT3...
{
//alpha_4x4
cptr = (char *)midbuf;
for (k=0; k<8; k++) *cptr++ = pic[k];
for (j=stride; (unsigned)j<miplen; j+=stride)
for (k=0; k<8; k++) *cptr++ = pic[j+k];
dxt_handle_io(fil, (miplen/stride)<<3, midbuf, packbuf);
}
//rgb0,rgb1
cptr = (char *)midbuf;
for (k=0; k<=2; k+=2)
for (j=0; (unsigned)j<miplen; j+=stride)
{ *(int16_t *)cptr = dxt_hicosub(*(int16_t *)(&pic[offs+j+k])); cptr += 2; }
dxt_handle_io(fil, (miplen/stride)<<2, midbuf, packbuf);
//index_4x4
cptr = (char *)midbuf;
for (j=0; (unsigned)j<miplen; j+=stride)
{
const char *c2 = &pic[j+offs+4];
cptr[0] = ((c2[0]>>0)&3) + (((c2[1]>>0)&3)<<2) + (((c2[2]>>0)&3)<<4) + (((c2[3]>>0)&3)<<6);
cptr[1] = ((c2[0]>>2)&3) + (((c2[1]>>2)&3)<<2) + (((c2[2]>>2)&3)<<4) + (((c2[3]>>2)&3)<<6);
cptr[2] = ((c2[0]>>4)&3) + (((c2[1]>>4)&3)<<2) + (((c2[2]>>4)&3)<<4) + (((c2[3]>>4)&3)<<6);
cptr[3] = ((c2[0]>>6)&3) + (((c2[1]>>6)&3)<<2) + (((c2[2]>>6)&3)<<4) + (((c2[3]>>6)&3)<<6);
cptr += 4;
}
dxt_handle_io(fil, (miplen/stride)<<2, midbuf, packbuf);
return 0;
}
// NOTE: <pict> members are in native endianness.
int32_t dedxtfilter(int32_t fil, const texcachepicture *pict, char *pic, void *midbuf, char *packbuf, int32_t ispacked)
{
int32_t j, k, offs, stride;
char *cptr;
if ((pict->format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ||
(pict->format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)) { offs = 0; stride = 8; }
else if ((pict->format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) ||
(pict->format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)) { offs = 8; stride = 16; }
else { offs = 0; stride = 8; }
if (stride == 16) //If DXT3...
{
//alpha_4x4
if (dedxt_handle_io(fil, (pict->size/stride)*8, midbuf, packbuf, ispacked))
return -1;
cptr = (char *)midbuf;
for (k=0; k<8; k++) pic[k] = *cptr++;
for (j=stride; j<pict->size; j+=stride)
for (k=0; k<8; k++) pic[j+k] = (*cptr++);
}
//rgb0,rgb1
if (dedxt_handle_io(fil, (pict->size/stride)*4, midbuf, packbuf, ispacked))
return -1;
cptr = (char *)midbuf;
for (k=0; k<=2; k+=2)
{
for (j=0; j<pict->size; j+=stride)
{
*(int16_t *)(&pic[offs+j+k]) = dedxt_hicoadd(*(int16_t *)cptr);
cptr += 2;
}
}
//index_4x4:
if (dedxt_handle_io(fil, (pict->size/stride)*4, midbuf, packbuf, ispacked))
return -1;
cptr = (char *)midbuf;
for (j=0; j<pict->size; j+=stride)
{
pic[j+offs+4] = ((cptr[0]>>0)&3) + (((cptr[1]>>0)&3)<<2) + (((cptr[2]>>0)&3)<<4) + (((cptr[3]>>0)&3)<<6);
pic[j+offs+5] = ((cptr[0]>>2)&3) + (((cptr[1]>>2)&3)<<2) + (((cptr[2]>>2)&3)<<4) + (((cptr[3]>>2)&3)<<6);
pic[j+offs+6] = ((cptr[0]>>4)&3) + (((cptr[1]>>4)&3)<<2) + (((cptr[2]>>4)&3)<<4) + (((cptr[3]>>4)&3)<<6);
pic[j+offs+7] = ((cptr[0]>>6)&3) + (((cptr[1]>>6)&3)<<2) + (((cptr[2]>>6)&3)<<4) + (((cptr[3]>>6)&3)<<6);
cptr += 4;
}
return 0;
}
#endif

View file

@ -14333,9 +14333,9 @@ void setbrightness(char dabrightness, uint8_t dapalid, uint8_t flags)
const int32_t doinvalidate = (paldidchange || (palsumdidchange && nohwgamma));
if (!(flags&2) && doinvalidate)
gltexinvalidateall();
gltexinvalidateall(0);
if (!(flags&8) && doinvalidate)
gltexinvalidate8();
gltexinvalidateall(1);
#ifdef POLYMER
if ((rendmode == 4) && doinvalidate)
polymer_texinvalidate();

View file

@ -10,10 +10,10 @@
#include "engine_priv.h"
#include "hightile.h"
#include "polymost.h"
#include "texcache.h"
#include "mdsprite.h"
#include "cache1d.h"
#include "kplib.h"
#include "md4.h"
#include <math.h>
@ -668,78 +668,6 @@ static int32_t daskinloader(int32_t filh, intptr_t *fptr, int32_t *bpl, int32_t
return 0;
}
// JONOF'S COMPRESSED TEXTURE CACHE STUFF ---------------------------------------------------
static int32_t mdloadskin_cached(int32_t fil, const texcacheheader *head, int32_t *doalloc, GLuint *glpic, int32_t *xsiz, int32_t *ysiz, int32_t pal)
{
int32_t level, r;
texcachepicture pict;
void *pic = NULL, *packbuf = NULL;
void *midbuf = NULL;
int32_t alloclen=0;
UNREFERENCED_PARAMETER(pal);
if (*doalloc&1)
{
bglGenTextures(1,glpic); //# of textures (make OpenGL allocate structure)
*doalloc |= 2; // prevents bglGenTextures being called again if we fail in here
}
bglBindTexture(GL_TEXTURE_2D,*glpic);
while (bglGetError() != GL_NO_ERROR)
{
/* no-op*/
}
// load the mipmaps
for (level = 0; level==0 || (pict.xdim > 1 || pict.ydim > 1); level++)
{
Blseek(fil, cachepos, BSEEK_SET);
r = Bread(fil, &pict, sizeof(texcachepicture));
cachepos += sizeof(texcachepicture);
if (r < (int32_t)sizeof(texcachepicture)) goto failure;
pict.size = B_LITTLE32(pict.size);
pict.format = B_LITTLE32(pict.format);
pict.xdim = B_LITTLE32(pict.xdim);
pict.ydim = B_LITTLE32(pict.ydim);
pict.border = B_LITTLE32(pict.border);
pict.depth = B_LITTLE32(pict.depth);
if (level == 0) { *xsiz = pict.xdim; *ysiz = pict.ydim; }
if (alloclen < pict.size)
{
void *picc = Brealloc(pic, pict.size);
if (!picc) goto failure; else pic = picc;
alloclen = pict.size;
picc = Brealloc(packbuf, alloclen+16);
if (!picc) goto failure; else packbuf = picc;
picc = Brealloc(midbuf, pict.size);
if (!picc) goto failure; else midbuf = picc;
}
if (dedxtfilter(fil, &pict, (char *)pic, (char *)midbuf, (char *)packbuf, (head->flags&4)==4)) goto failure;
bglCompressedTexImage2DARB(GL_TEXTURE_2D,level,pict.format,pict.xdim,pict.ydim,pict.border,
pict.size,pic);
if (bglGetError() != GL_NO_ERROR) goto failure;
}
if (midbuf) Bfree(midbuf);
if (pic) Bfree(pic);
if (packbuf) Bfree(packbuf);
return 0;
failure:
if (midbuf) Bfree(midbuf);
if (pic) Bfree(pic);
if (packbuf) Bfree(packbuf);
return -1;
}
// --------------------------------------------------- JONOF'S COMPRESSED TEXTURE CACHE STUFF
static inline int32_t hicfxmask(int32_t pal)
{
return (globalnoeffect)?0:(hictinting[pal].f&HICEFFECTMASK);
@ -753,7 +681,7 @@ int32_t mdloadskin(md2model_t *m, int32_t number, int32_t pal, int32_t surf)
GLuint *texidx = NULL;
mdskinmap_t *sk, *skzero = NULL;
int32_t doalloc = 1, filh;
int32_t cachefil = -1, picfillen;
int32_t gotcache, picfillen;
texcacheheader cachead;
int32_t startticks, willprint=0;
@ -848,26 +776,23 @@ int32_t mdloadskin(md2model_t *m, int32_t number, int32_t pal, int32_t surf)
startticks = getticks();
cachefil = polymost_trytexcache(fn, picfillen, pal<<8, hicfxmask(pal), &cachead, 1);
gotcache = texcache_readtexheader(fn, picfillen, pal<<8, hicfxmask(pal), &cachead, 1);
if (cachefil >= 0 && !mdloadskin_cached(cachefil, &cachead, &doalloc, texidx, &xsiz, &ysiz, pal))
if (gotcache && !texcache_loadskin(&cachead, &doalloc, texidx, &xsiz, &ysiz))
{
osizx = cachead.xdim;
osizy = cachead.ydim;
hasalpha = (cachead.flags & 2) ? 1 : 0;
if (pal < (MAXPALOOKUPS - RESERVEDPALS))
m->usesalpha = hasalpha;
// kclose(cachefil);
//kclose(filh); // FIXME: uncomment when cache1d.c is fixed
// cachefil >= 0, so it won't be rewritten
}
else
{
int32_t ret;
intptr_t fptr=0;
// if (cachefil >= 0) kclose(cachefil);
cachefil = -1; // the compressed version will be saved to disk
gotcache = 0; // the compressed version will be saved to disk
if ((filh = kopen4load(fn, 0)) < 0)
return -1;
@ -952,7 +877,7 @@ int32_t mdloadskin(md2model_t *m, int32_t number, int32_t pal, int32_t surf)
bglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
if (glinfo.texcompr && glusetexcompr && glusetexcache)
if (cachefil < 0)
if (!gotcache)
{
// save off the compressed version
cachead.quality = r_downsize;
@ -967,7 +892,7 @@ int32_t mdloadskin(md2model_t *m, int32_t number, int32_t pal, int32_t surf)
}
cachead.flags = (i!=3) | (hasalpha ? 2 : 0);
/// OSD_Printf("Caching \"%s\"\n",fn);
writexcache(fn, picfillen, pal<<8, hicfxmask(pal), &cachead);
texcache_writetex(fn, picfillen, pal<<8, hicfxmask(pal), &cachead);
if (willprint)
{

View file

@ -2104,15 +2104,15 @@ int32_t osdcmd_cvar_set(const osdfuncparm_t *parm)
#ifdef USE_OPENGL
if (!OSD_ParsingScript())
{
switch (cvars[i].c.type&(CVAR_RESTARTVID|CVAR_INVALIDATE|CVAR_INVALIDATE8))
switch (cvars[i].c.type&(CVAR_RESTARTVID|CVAR_INVALIDATEALL|CVAR_INVALIDATEART))
{
case CVAR_RESTARTVID:
osdcmd_restartvid(NULL);
break;
case CVAR_INVALIDATE:
gltexinvalidateall();
case CVAR_INVALIDATE8:
gltexinvalidate8();
case CVAR_INVALIDATEALL:
gltexinvalidateall(0);
case CVAR_INVALIDATEART:
gltexinvalidateall(1);
#ifdef POLYMER
if (getrendermode() == REND_POLYMER)
polymer_texinvalidate();

View file

@ -8,6 +8,7 @@
#include "polymer.h"
#include "engine_priv.h"
#include "crc32.h"
#include "texcache.h"
// CVARS
int32_t pr_lighting = 1;
@ -1018,7 +1019,7 @@ void polymer_drawrooms(int32_t daposx, int32_t daposy, int32_t da
skyhoriz += 360.0f;
drawingskybox = 1;
pth = gltexcache(cursky,0,0);
pth = texcache_fetch(cursky,0,0);
drawingskybox = 0;
// if it's not a skybox, make the sky parallax
@ -1546,7 +1547,7 @@ int16_t polymer_addlight(_prlight* light)
loadtile(picnum);
pth = NULL;
pth = gltexcache(picnum, 0, 0);
pth = texcache_fetch(picnum, 0, 0);
if (pth)
light->lightmap = pth->glpic;
@ -3826,7 +3827,7 @@ static void polymer_drawsky(int16_t tilenum, char palnum, int8_t shade)
bglScalef(1000.0f, 1000.0f, 1000.0f);
drawingskybox = 1;
pth = gltexcache(tilenum,0,0);
pth = texcache_fetch(tilenum,0,0);
drawingskybox = 0;
if (pth && (pth->flags & 4))
@ -3867,7 +3868,7 @@ static void polymer_drawartsky(int16_t tilenum, char palnum, int8_t shad
DO_TILE_ANIM(picnum, 0);
if (!waloff[picnum])
loadtile(picnum);
pth = gltexcache(picnum, palnum, 0);
pth = texcache_fetch(picnum, palnum, 0);
glpics[i] = pth ? pth->glpic : 0;
glcolors[i][0] = glcolors[i][1] = glcolors[i][2] = getshadefactor(shade);
@ -3957,7 +3958,7 @@ static void polymer_drawskybox(int16_t tilenum, char palnum, int8_t shad
while (i < 6)
{
drawingskybox = i + 1;
pth = gltexcache(tilenum, palnum, 4);
pth = texcache_fetch(tilenum, palnum, 4);
color[0] = color[1] = color[2] = getshadefactor(shade);
@ -4557,7 +4558,7 @@ static void polymer_getbuildmaterial(_prmaterial* material, int16_t tile
loadtile(tilenum);
// PR_BIT_DIFFUSE_MAP
pth = gltexcache(tilenum, pal, cmeth);
pth = texcache_fetch(tilenum, pal, cmeth);
if (pth)
material->diffusemap = pth->glpic;
@ -4718,7 +4719,7 @@ static void polymer_getbuildmaterial(_prmaterial* material, int16_t tile
}
// PR_BIT_DIFFUSE_DETAIL_MAP
if (hicfindsubst(tilenum, DETAILPAL, 0) && (pth = gltexcache(tilenum, DETAILPAL, 0)) &&
if (hicfindsubst(tilenum, DETAILPAL, 0) && (pth = texcache_fetch(tilenum, DETAILPAL, 0)) &&
pth->hicr && (pth->hicr->palnum == DETAILPAL))
{
material->detailmap = pth->glpic;
@ -4727,17 +4728,17 @@ static void polymer_getbuildmaterial(_prmaterial* material, int16_t tile
}
// PR_BIT_GLOW_MAP
if (hicfindsubst(tilenum, GLOWPAL, 0) && (pth = gltexcache(tilenum, GLOWPAL, 0)) &&
if (hicfindsubst(tilenum, GLOWPAL, 0) && (pth = texcache_fetch(tilenum, GLOWPAL, 0)) &&
pth->hicr && (pth->hicr->palnum == GLOWPAL))
material->glowmap = pth->glpic;
// PR_BIT_SPECULAR_MAP
if (hicfindsubst(tilenum, SPECULARPAL, 0) && (pth = gltexcache(tilenum, SPECULARPAL, 0)) &&
if (hicfindsubst(tilenum, SPECULARPAL, 0) && (pth = texcache_fetch(tilenum, SPECULARPAL, 0)) &&
pth->hicr && (pth->hicr->palnum == SPECULARPAL))
material->specmap = pth->glpic;
// PR_BIT_NORMAL_MAP
if (hicfindsubst(tilenum, NORMALPAL, 0) && (pth = gltexcache(tilenum, NORMALPAL, 0)) &&
if (hicfindsubst(tilenum, NORMALPAL, 0) && (pth = texcache_fetch(tilenum, NORMALPAL, 0)) &&
pth->hicr && (pth->hicr->palnum == NORMALPAL))
{
material->normalmap = pth->glpic;
@ -5436,7 +5437,7 @@ static void polymer_updatelights(void)
loadtile(picnum);
pth = NULL;
pth = gltexcache(picnum, 0, 0);
pth = texcache_fetch(picnum, 0, 0);
if (pth)
light->lightmap = pth->glpic;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,713 @@
#include "build.h"
#include "quicklz.h"
#include "hightile.h"
#include "polymost.h"
#include "texcache.h"
#include "dxtfilter.h"
#include "scriptfile.h"
#include "crc32.h"
#define CLEAR_GL_ERRORS() while(bglGetError() != GL_NO_ERROR) { }
#define REALLOC_OR_FAIL(ptr, size, type) { ptr = (type *)Brealloc(ptr, size); if (!ptr) goto failure; }
#define TEXCACHE_FREEBUFS() { Bfree(pic), Bfree(packbuf), Bfree(midbuf); }
int32_t texcache_filehandle = -1; // texture cache file handle
FILE *texcache_indexptr = NULL;
uint8_t *texcache_memptr = NULL;
int32_t texcache_memsize = -1;
int32_t texcache_offset = 0;
// Set to 1 when we failed (re)allocating space for the memcache or failing to
// read into it (which would presumably generate followup errors spamming the
// log otherwise):
int32_t texcache_noalloc = 0;
static hashtable_t h_texcache = { 1024, NULL };
char TEXCACHEFILE[BMAX_PATH] = "textures";
pthtyp *texcache_head[GLTEXCACHEADSIZ];
texcacheindex *texcache_firstindex = NULL;
texcacheindex *texcache_currentindex = NULL;
static texcacheindex *texcache_ptrs[MAXTILES<<1];
static int32_t texcache_numentries = 0;
enum texcacherr_t
{
TEXCACHERR_NOERROR,
TEXCACHERR_OUTOFMEMORY,
TEXCACHERR_BUFFERUNDERRUN,
TEXCACHERR_DEDXT,
TEXCACHERR_COMPTEX,
TEXCACHERR_GETTEXLEVEL
};
static const char *texcache_loaderrs[5] = {
"out of memory!",
"read too few bytes from cache file",
"dedxtfilter failed",
"bglCompressedTexImage2DARB failed",
"bglGetTexLevelParameteriv failed",
};
pthtyp *texcache_fetch(int32_t dapicnum, int32_t dapalnum, int32_t dameth)
{
int32_t i, j;
hicreplctyp *si;
pthtyp *pth, *pth2;
j = (dapicnum&(GLTEXCACHEADSIZ-1));
si = usehightile ? hicfindsubst(dapicnum,dapalnum,drawingskybox) : NULL;
if (!si)
{
if (drawingskybox || dapalnum >= (MAXPALOOKUPS - RESERVEDPALS)) return NULL;
goto tryart;
}
/* if palette > 0 && replacement found
* no effects are applied to the texture
* else if palette > 0 && no replacement found
* effects are applied to the palette 0 texture if it exists
*/
// load a replacement
for (pth=texcache_head[j]; pth; pth=pth->next)
{
if (pth->picnum == dapicnum && pth->palnum == si->palnum &&
(si->palnum>0 ? 1 : (pth->effects == hictinting[dapalnum].f)) &&
(pth->flags & (1+2+4)) == (((dameth&4)>>2)+2+((drawingskybox>0)<<2)) &&
(drawingskybox>0 ? (pth->skyface == drawingskybox) : 1)
)
{
if (pth->flags & 128)
{
pth->flags &= ~128;
if (gloadtile_hi(dapicnum,dapalnum,drawingskybox,si,dameth,pth,0,
(si->palnum>0) ? 0 : hictinting[dapalnum].f)) // reload tile
{
if (drawingskybox) return NULL;
goto tryart; // failed, so try for ART
}
}
return(pth);
}
}
pth = (pthtyp *)Bcalloc(1,sizeof(pthtyp));
if (!pth) return NULL;
// possibly fetch an already loaded multitexture :_)
if (dapalnum >= (MAXPALOOKUPS - RESERVEDPALS))
for (i = (GLTEXCACHEADSIZ - 1); i >= 0; i--)
for (pth2=texcache_head[i]; pth2; pth2=pth2->next)
{
if ((pth2->hicr) && (pth2->hicr->filename) && (Bstrcasecmp(pth2->hicr->filename, si->filename) == 0))
{
Bmemcpy(pth, pth2, sizeof(pthtyp));
pth->picnum = dapicnum;
pth->flags = ((dameth&4)>>2) + 2 + ((drawingskybox>0)<<2);
if (pth2->flags & 8) pth->flags |= 8; //hasalpha
pth->hicr = si;
pth->next = texcache_head[j];
texcache_head[j] = pth;
return(pth);
}
}
if (gloadtile_hi(dapicnum,dapalnum,drawingskybox,si,dameth,pth,1, (si->palnum>0) ? 0 : hictinting[dapalnum].f))
{
Bfree(pth);
if (drawingskybox) return NULL;
goto tryart; // failed, so try for ART
}
pth->palnum = si->palnum;
pth->next = texcache_head[j];
texcache_head[j] = pth;
return(pth);
tryart:
if (hicprecaching) return NULL;
// load from art
for (pth=texcache_head[j]; pth; pth=pth->next)
if (pth->picnum == dapicnum && pth->palnum == dapalnum &&
(pth->flags & (1+2)) == ((dameth&4)>>2)
)
{
if (pth->flags & 128)
{
pth->flags &= ~128;
if (gloadtile_art(dapicnum,dapalnum,dameth,pth,0))
return NULL; //reload tile (for animations)
}
return(pth);
}
pth = (pthtyp *)Bcalloc(1,sizeof(pthtyp));
if (!pth) return NULL;
if (gloadtile_art(dapicnum,dapalnum,dameth,pth,1))
{
Bfree(pth);
return NULL;
}
pth->next = texcache_head[j];
texcache_head[j] = pth;
return(pth);
}
static void texcache_closefiles(void)
{
if (texcache_filehandle != -1)
{
Bclose(texcache_filehandle);
texcache_filehandle = -1;
}
if (texcache_indexptr)
{
Bfclose(texcache_indexptr);
texcache_indexptr = NULL;
}
}
void texcache_freeptrs(void)
{
int32_t i;
for (i = texcache_numentries-1; i >= 0; i--)
if (texcache_ptrs[i])
{
int32_t ii;
for (ii = texcache_numentries-1; ii >= 0; ii--)
if (i != ii && texcache_ptrs[ii] == texcache_ptrs[i])
{
/*OSD_Printf("removing duplicate cacheptr %d\n",ii);*/
texcache_ptrs[ii] = NULL;
}
Bfree(texcache_ptrs[i]);
texcache_ptrs[i] = NULL;
}
}
void texcache_clearmem(void)
{
Bfree(texcache_memptr);
texcache_memptr = NULL;
texcache_memsize = -1;
}
void texcache_sync(void)
{
if (texcache_memptr && texcache_filehandle != -1 && filelength(texcache_filehandle) > texcache_memsize)
{
size_t len = filelength(texcache_filehandle);
texcache_memptr = (uint8_t *)Brealloc(texcache_memptr, len);
if (!texcache_memptr)
{
texcache_clearmem();
initprintf("Failed syncing memcache to texcache, disabling memcache.\n");
texcache_noalloc = 1;
}
else
{
initprintf("Syncing memcache to texcache\n");
Blseek(texcache_filehandle, texcache_memsize, BSEEK_SET);
if (Bread(texcache_filehandle, texcache_memptr + texcache_memsize, len - texcache_memsize) != (bssize_t)(len-texcache_memsize))
{
initprintf("polymost_cachesync: Failed reading texcache into memcache!\n");
texcache_clearmem();
texcache_noalloc = 1;
}
else
{
texcache_memsize = len;
}
}
}
}
void texcache_init(void)
{
texcache_closefiles();
texcache_clearmem();
texcache_freeptrs();
texcache_currentindex = texcache_firstindex = (texcacheindex *)Bcalloc(1, sizeof(texcacheindex));
texcache_numentries = 0;
// Bmemset(&firstcacheindex, 0, sizeof(texcacheindex));
// Bmemset(&cacheptrs[0], 0, sizeof(cacheptrs));
hash_init(&h_texcache);
}
void texcache_invalidate(void)
{
#ifdef DEBUGGINGAIDS
OSD_Printf("texcache_invalidate()\n");
#endif
r_downsizevar = r_downsize; // update the cvar representation when the menu changes r_downsize
polymost_glreset();
texcache_init();
// LoadCacheOffsets();
Bstrcpy(ptempbuf, TEXCACHEFILE);
unlink(ptempbuf);
Bstrcat(ptempbuf, ".cache");
unlink(ptempbuf);
texcache_indexptr = Bfopen(ptempbuf, "at+");
texcache_filehandle = Bopen(TEXCACHEFILE,BO_BINARY|BO_CREAT|BO_TRUNC|BO_APPEND|BO_RDWR,BS_IREAD|BS_IWRITE);
if (!texcache_indexptr || texcache_filehandle < 0)
{
initprintf("Unable to open cache file \"%s\" or \"%s\": %s\n", TEXCACHEFILE, ptempbuf, strerror(errno));
texcache_closefiles();
glusetexcache = 0;
return;
}
else
initprintf("Deleted and reopened \"%s\" as cache file\n", TEXCACHEFILE);
Bfprintf(texcache_indexptr,"// automatically generated by EDuke32, DO NOT MODIFY!\n");
}
int32_t texcache_loadoffsets(void)
{
int32_t foffset, fsize, i;
char *fname;
scriptfile *script;
Bstrcpy(ptempbuf,TEXCACHEFILE);
Bstrcat(ptempbuf,".cache");
script = scriptfile_fromfile(ptempbuf);
if (!script) return -1;
while (!scriptfile_eof(script))
{
if (scriptfile_getstring(script, &fname)) break; // hashed filename
if (scriptfile_getnumber(script, &foffset)) break; // offset in cache
if (scriptfile_getnumber(script, &fsize)) break; // size
i = hash_find(&h_texcache,fname);
if (i > -1)
{
// update an existing entry
texcacheindex *t = texcache_ptrs[i];
t->offset = foffset;
t->len = fsize;
/*initprintf("%s %d got a match for %s offset %d\n",__FILE__, __LINE__, fname,foffset);*/
}
else
{
Bstrncpyz(texcache_currentindex->name, fname, BMAX_PATH);
texcache_currentindex->offset = foffset;
texcache_currentindex->len = fsize;
texcache_currentindex->next = (texcacheindex *)Bcalloc(1, sizeof(texcacheindex));
hash_add(&h_texcache, fname, texcache_numentries, 1);
texcache_ptrs[texcache_numentries++] = texcache_currentindex;
texcache_currentindex = texcache_currentindex->next;
}
}
scriptfile_close(script);
return 0;
}
// Read from on-disk texcache or its in-memory cache.
int32_t texcache_readdata(void *dest, int32_t len)
{
const int32_t ocachepos = texcache_offset;
texcache_offset += len;
if (texcache_memptr && texcache_memsize >= ocachepos+len)
{
// initprintf("using memcache!\n");
Bmemcpy(dest, texcache_memptr+ocachepos, len);
}
else
{
Blseek(texcache_filehandle, ocachepos, BSEEK_SET);
if (Bread(texcache_filehandle, dest, len) < len)
return 1;
}
return 0;
}
static int32_t texcache_enabled(void)
{
if (!glusetexcompr || !glusetexcache) return 0;
if (!glinfo.texcompr || !bglCompressedTexImage2DARB || !bglGetCompressedTexImageARB)
{
// lacking the necessary extensions to do this
OSD_Printf("Warning: the GL driver lacks necessary functions to use caching\n");
glusetexcache = 0;
return 0;
}
if (!texcache_indexptr || texcache_filehandle < 0)
{
OSD_Printf("Warning: no active cache!\n");
return 0;
}
return 1;
}
typedef struct { int32_t len, method; char effect, name[BMAX_PATH]; } texcacheid_t;
static const char * texcache_calcid(char *cachefn, const char *fn, const int32_t len, const int32_t dameth, const char effect)
{
int32_t fp;
char *cp;
texcacheid_t id = { len, dameth, effect };
Bstrcpy(id.name, fn);
while (Bstrlen(id.name) < BMAX_PATH - Bstrlen(fn))
Bstrcat(id.name, fn);
Bsprintf(cachefn, "%x%x%x",
crc32once((uint8_t *)fn, Bstrlen(fn)),
crc32once((uint8_t *)id.name, Bstrlen(id.name)),
crc32once((uint8_t *)&id, sizeof(texcacheid_t)));
return cachefn;
}
#define READTEXHEADER_FAILURE(x) { err = x; goto failure; }
// returns 1 on success
int32_t texcache_readtexheader(const char *fn, int32_t len, int32_t dameth, char effect,
texcacheheader *head, int32_t modelp)
{
int32_t i, err = 0;
char cachefn[BMAX_PATH];
if (!texcache_enabled()) return 0;
i = hash_find(&h_texcache, texcache_calcid(cachefn, fn, len, dameth, effect));
if (i < 0 || !texcache_ptrs[i])
return 0; // didn't find it
texcache_offset = texcache_ptrs[i]->offset;
// initprintf("%s %d got a match for %s offset %d\n",__FILE__, __LINE__, cachefn,offset);
if (texcache_readdata(head, sizeof(texcacheheader))) READTEXHEADER_FAILURE(0);
if (Bmemcmp(head->magic, TEXCACHEMAGIC, 4)) READTEXHEADER_FAILURE(1);
// native (little-endian) -> internal
head->xdim = B_LITTLE32(head->xdim);
head->ydim = B_LITTLE32(head->ydim);
head->flags = B_LITTLE32(head->flags);
head->quality = B_LITTLE32(head->quality);
if (modelp && head->quality != r_downsize) READTEXHEADER_FAILURE(2);
if ((head->flags & 4) && glusetexcache != 2) READTEXHEADER_FAILURE(3);
if (!(head->flags & 4) && glusetexcache == 2) READTEXHEADER_FAILURE(4);
// handle nocompress
if (!modelp && !(head->flags & 8) && head->quality != r_downsize)
return 0;
if (gltexmaxsize && (head->xdim > (1<<gltexmaxsize) || head->ydim > (1<<gltexmaxsize))) READTEXHEADER_FAILURE(5);
if (!glinfo.texnpot && (head->flags & 1)) READTEXHEADER_FAILURE(6);
return 1;
failure:
{
static const char *error_msgs[] = {
"failed reading texture cache header", // 0
"header magic string doesn't match", // 1
"r_downsize doesn't match", // 2 (skins only)
"compression doesn't match: cache contains compressed tex", // 3
"compression doesn't match: cache contains uncompressed tex", // 4
"texture in cache exceeds maximum supported size", // 5
"texture in cache has non-power-of-two size, unsupported", // 6
};
initprintf("%s cache miss: %s\n", modelp?"Skin":"Texture", error_msgs[err]);
}
return 0;
}
#undef READTEXHEADER_FAILURE(x)
#define WRITEX_FAIL_ON_ERROR() if (bglGetError() != GL_NO_ERROR) goto failure
void texcache_writetex(const char *fn, int32_t len, int32_t dameth, char effect, texcacheheader *head)
{
char cachefn[BMAX_PATH];
char *pic = NULL, *packbuf = NULL;
void *midbuf = NULL;
uint32_t alloclen=0, level;
uint32_t padx=0, pady=0;
GLint gi;
int32_t offset = 0;
if (!texcache_enabled()) return;
gi = GL_FALSE;
bglGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &gi);
if (gi != GL_TRUE)
{
OSD_Printf("Error: glGetTexLevelParameteriv returned GL_FALSE!\n");
return;
}
Blseek(texcache_filehandle, 0, BSEEK_END);
offset = Blseek(texcache_filehandle, 0, BSEEK_CUR);
// OSD_Printf("Caching %s, offset 0x%x\n", cachefn, offset);
Bmemcpy(head->magic, TEXCACHEMAGIC, 4); // sizes are set by caller
if (glusetexcache == 2) head->flags |= 4;
// native -> external (little-endian)
head->xdim = B_LITTLE32(head->xdim);
head->ydim = B_LITTLE32(head->ydim);
head->flags = B_LITTLE32(head->flags);
head->quality = B_LITTLE32(head->quality);
if (Bwrite(texcache_filehandle, head, sizeof(texcacheheader)) != sizeof(texcacheheader)) goto failure;
CLEAR_GL_ERRORS();
for (level = 0; level==0 || (padx > 1 || pady > 1); level++)
{
uint32_t miplen;
texcachepicture pict;
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_COMPRESSED_ARB, &gi); WRITEX_FAIL_ON_ERROR();
if (gi != GL_TRUE) goto failure; // an uncompressed mipmap
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_INTERNAL_FORMAT, &gi); WRITEX_FAIL_ON_ERROR();
#ifdef __APPLE__
if (pr_ati_textureformat_one && gi == 1) gi = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
#endif
// native -> external (little endian)
pict.format = B_LITTLE32(gi);
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &gi); WRITEX_FAIL_ON_ERROR();
padx = gi; pict.xdim = B_LITTLE32(gi);
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_HEIGHT, &gi); WRITEX_FAIL_ON_ERROR();
pady = gi; pict.ydim = B_LITTLE32(gi);
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_BORDER, &gi); WRITEX_FAIL_ON_ERROR();
pict.border = B_LITTLE32(gi);
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_DEPTH, &gi); WRITEX_FAIL_ON_ERROR();
pict.depth = B_LITTLE32(gi);
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &gi); WRITEX_FAIL_ON_ERROR();
miplen = gi; pict.size = B_LITTLE32(gi);
if (alloclen < miplen)
{
REALLOC_OR_FAIL(pic, miplen, char);
alloclen = miplen;
REALLOC_OR_FAIL(packbuf, alloclen+400, char);
REALLOC_OR_FAIL(midbuf, miplen, void);
}
bglGetCompressedTexImageARB(GL_TEXTURE_2D, level, pic); WRITEX_FAIL_ON_ERROR();
if (Bwrite(texcache_filehandle, &pict, sizeof(texcachepicture)) != sizeof(texcachepicture)) goto failure;
if (dxtfilter(texcache_filehandle, &pict, pic, midbuf, packbuf, miplen)) goto failure;
}
{
texcacheindex *t;
int32_t i = hash_find(&h_texcache, texcache_calcid(cachefn, fn, len, dameth, effect));
if (i > -1)
{
// update an existing entry
t = texcache_ptrs[i];
t->offset = offset;
t->len = Blseek(texcache_filehandle, 0, BSEEK_CUR) - t->offset;
/*initprintf("%s %d got a match for %s offset %d\n",__FILE__, __LINE__, cachefn,offset);*/
}
else
{
t = texcache_currentindex;
Bstrcpy(t->name, cachefn);
t->offset = offset;
t->len = Blseek(texcache_filehandle, 0, BSEEK_CUR) - t->offset;
t->next = (texcacheindex *)Bcalloc(1, sizeof(texcacheindex));
hash_add(&h_texcache, cachefn, texcache_numentries, 0);
texcache_ptrs[texcache_numentries++] = t;
texcache_currentindex = t->next;
}
if (texcache_indexptr)
{
fseek(texcache_indexptr, 0, BSEEK_END);
Bfprintf(texcache_indexptr, "%s %d %d\n", t->name, t->offset, t->len);
}
else OSD_Printf("wtf?\n");
}
goto success;
failure:
initprintf("ERROR: cache failure!\n");
texcache_currentindex->offset = 0;
Bmemset(texcache_currentindex->name,0,sizeof(texcache_currentindex->name));
success:
TEXCACHE_FREEBUFS();
}
#undef WRITEX_FAIL_ON_ERROR()
static void texcache_setuptexture(int32_t *doalloc, GLuint *glpic)
{
if (*doalloc&1)
{
bglGenTextures(1,glpic); //# of textures (make OpenGL allocate structure)
*doalloc |= 2; // prevents bglGenTextures being called again if we fail in here
}
bglBindTexture(GL_TEXTURE_2D,*glpic);
}
static int32_t texcache_loadmips(const texcacheheader *head, GLenum *glerr, int32_t *xsiz, int32_t *ysiz)
{
int32_t level;
texcachepicture pict;
char *pic = NULL, *packbuf = NULL;
void *midbuf = NULL;
int32_t alloclen=0;
for (level = 0; level==0 || (pict.xdim > 1 || pict.ydim > 1); level++)
{
GLint format;
if (texcache_readdata(&pict, sizeof(texcachepicture)))
{
TEXCACHE_FREEBUFS();
return TEXCACHERR_BUFFERUNDERRUN;
}
// external (little endian) -> native
pict.size = B_LITTLE32(pict.size);
pict.format = B_LITTLE32(pict.format);
pict.xdim = B_LITTLE32(pict.xdim);
pict.ydim = B_LITTLE32(pict.ydim);
pict.border = B_LITTLE32(pict.border);
pict.depth = B_LITTLE32(pict.depth);
if (level == 0)
{
if (xsiz) *xsiz = pict.xdim;
if (ysiz) *ysiz = pict.ydim;
}
if (alloclen < pict.size)
{
REALLOC_OR_FAIL(pic, pict.size, char);
alloclen = pict.size;
REALLOC_OR_FAIL(packbuf, alloclen+16, char);
REALLOC_OR_FAIL(midbuf, pict.size, void);
}
if (dedxtfilter(texcache_filehandle, &pict, pic, midbuf, packbuf, (head->flags&4)==4))
{
TEXCACHE_FREEBUFS();
return TEXCACHERR_DEDXT;
}
bglCompressedTexImage2DARB(GL_TEXTURE_2D,level,pict.format,pict.xdim,pict.ydim,pict.border,pict.size,pic);
if ((*glerr=bglGetError()) != GL_NO_ERROR)
{
TEXCACHE_FREEBUFS();
return TEXCACHERR_COMPTEX;
}
bglGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_INTERNAL_FORMAT, &format);
if ((*glerr = bglGetError()) != GL_NO_ERROR)
{
TEXCACHE_FREEBUFS();
return TEXCACHERR_GETTEXLEVEL;
}
if (pict.format != format)
{
OSD_Printf("gloadtile_cached: invalid texture cache file format %d %d\n", pict.format, format);
TEXCACHE_FREEBUFS();
return -1;
}
}
TEXCACHE_FREEBUFS();
return 0;
failure:
TEXCACHE_FREEBUFS();
return TEXCACHERR_OUTOFMEMORY;
}
int32_t texcache_loadskin(const texcacheheader *head, int32_t *doalloc, GLuint *glpic, int32_t *xsiz, int32_t *ysiz)
{
int32_t err=0;
GLenum glerr=GL_NO_ERROR;
texcache_setuptexture(doalloc, glpic);
CLEAR_GL_ERRORS();
if ((err = texcache_loadmips(head, &glerr, xsiz, ysiz)))
{
if (err > 0)
initprintf("texcache_loadskin: %s (glerr=%x)\n", texcache_loaderrs[err-1], glerr);
return -1;
}
return 0;
}
int32_t texcache_loadtile(const texcacheheader *head, int32_t *doalloc, pthtyp *pth)
{
int32_t err=0;
GLenum glerr=GL_NO_ERROR;
texcache_setuptexture(doalloc, &pth->glpic);
pth->sizx = head->xdim;
pth->sizy = head->ydim;
CLEAR_GL_ERRORS();
if ((err = texcache_loadmips(head, &glerr, NULL, NULL)))
{
if (err > 0)
initprintf("texcache_loadtile: %s (glerr=%x)\n", texcache_loaderrs[err-1], glerr);
return -1;
}
return 0;
}

View file

@ -80,6 +80,7 @@
<ClInclude Include="build\include\common.h" />
<ClInclude Include="build\include\crc32.h" />
<ClInclude Include="build\include\dxdidf.h" />
<ClInclude Include="build\include\dxtfilter.h" />
<ClInclude Include="build\include\dynamicgtk.h" />
<ClInclude Include="build\include\editor.h" />
<ClInclude Include="build\include\enet_mmulti.h" />
@ -106,6 +107,7 @@
<ClInclude Include="build\include\scriptfile.h" />
<ClInclude Include="build\include\sdlayer.h" />
<ClInclude Include="build\include\startwin.editor.h" />
<ClInclude Include="build\include\texcache.h" />
<ClInclude Include="build\include\tracker.hpp" />
<ClInclude Include="build\include\tracker_operator.hpp" />
<ClInclude Include="build\include\tracker_operators.hpp" />
@ -196,6 +198,7 @@
<ClCompile Include="build\src\config.c" />
<ClCompile Include="build\src\crc32.c" />
<ClCompile Include="build\src\defs.c" />
<ClCompile Include="build\src\dxtfilter.c" />
<ClCompile Include="build\src\dynamicgtk.c" />
<ClCompile Include="build\src\engine.c" />
<ClCompile Include="build\src\glbuild.c" />
@ -217,6 +220,7 @@
<ClCompile Include="build\src\smalltextfont.c" />
<ClCompile Include="build\src\startgtk.editor.c" />
<ClCompile Include="build\src\startwin.editor.c" />
<ClCompile Include="build\src\texcache.c" />
<ClCompile Include="build\src\textfont.c" />
<ClCompile Include="build\src\winbits.c" />
<ClCompile Include="build\src\winlayer.c" />

View file

@ -399,6 +399,12 @@
<ClInclude Include="build\include\common.h">
<Filter>build\headers</Filter>
</ClInclude>
<ClInclude Include="build\include\texcache.h">
<Filter>build\headers</Filter>
</ClInclude>
<ClInclude Include="build\include\dxtfilter.h">
<Filter>build\headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="build\src\a-c.c">
@ -704,6 +710,12 @@
<ClCompile Include="build\src\winbits.c">
<Filter>build\source</Filter>
</ClCompile>
<ClCompile Include="build\src\texcache.c">
<Filter>build\source</Filter>
</ClCompile>
<ClCompile Include="build\src\dxtfilter.c">
<Filter>build\source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Makefile.msvc">

View file

@ -2763,7 +2763,7 @@ cheat_for_port_credits2:
sliderbar(1,d+8,yy+7, &r_downsize,-1,enabled && x==io,MENUHIGHLIGHT(io),!enabled,0,2);
if (r_downsize != i)
{
invalidatecache();
texcache_invalidate();
resetvideomode();
if (setgamemode(fullscreen,xdim,ydim,bpp))
OSD_Printf("restartvid: Reset failed...\n");