#include "quakedef.h"
-cvar_t gl_max_size = {"gl_max_size", "1024"};
+cvar_t gl_max_size = {"gl_max_size", "2048"};
cvar_t gl_picmip = {"gl_picmip", "0"};
cvar_t gl_lerpimages = {"gl_lerpimages", "1"};
cvar_t r_upload = {"r_upload", "1"};
int texels;
-// 4096x4096
-#define MAXMIPS 12
+// 65536x65536
+#define MAXMIPS 16
typedef struct
{
+ char identifier[64];
int texnum;
- int totaltexels;
+ int texeldatasize;
byte *texels[MAXMIPS];
unsigned short texelsize[MAXMIPS][2];
- char identifier[64];
- short width, height;
+ unsigned short width, height;
// LordHavoc: CRC to identify cache mismatchs
unsigned short crc;
char mipmap;
char alpha;
char bytesperpixel;
char lerped; // whether this texture was uploaded with or without interpolation
+ char inuse; // cleared during texture purge when loading new level
+ char pad; // unused
} gltexture_t;
#define MAX_GLTEXTURES 4096
-gltexture_t gltextures[MAX_GLTEXTURES];
+gltexture_t *gltextures;
int numgltextures;
typedef struct
name = "<unnamed>";
while (name[c] && c < 28)
n[c++] = name[c];
- while (c < 28)
- n[c++] = ' ';
+ // no need to pad since the name was moved to last
+// while (c < 28)
+// n[c++] = ' ';
n[c] = 0;
- Con_Printf("%s %5i %04X %s %s\n", n, total, crc, mip ? "yes" : "no ", alpha ? "yes " : "no ");
+ Con_Printf("%5i %04X %s %s %s\n", total, crc, mip ? "yes" : "no ", alpha ? "yes " : "no ", n);
}
void GL_TextureStats_f(void)
{
- int i, t = 0;
+ int i, s = 0, sc = 0, t = 0;
gltexture_t *glt;
- Con_Printf("name kbytes crc mip alpha\n");
+ Con_Printf("kbytes crc mip alpha name\n");
for (i = 0, glt = gltextures;i < numgltextures;i++, glt++)
{
- GL_TextureStats_Print(glt->identifier, ((glt->totaltexels * 4) + 512) >> 10, glt->crc, glt->mipmap, glt->alpha);
- t += glt->totaltexels;
+ GL_TextureStats_Print(glt->identifier, (glt->texeldatasize + 512) >> 10, glt->crc, glt->mipmap, glt->alpha);
+ t += glt->texeldatasize;
+ if (glt->identifier[0] == '&')
+ {
+ sc++;
+ s += glt->texeldatasize;
+ }
}
- Con_Printf("%i textures, totalling %.3f mbytes\n", numgltextures, t / 1024.0 / 1024.0);
+ Con_Printf("%i textures, totalling %.3fMB, %i are (usually) unnecessary model skins totalling %.3fMB\n", numgltextures, t / 1048576.0, sc, s / 1048576.0);
}
-extern int buildnumber;
+void GL_TextureStats_PrintTotal(void)
+{
+ int i, s = 0, sc = 0, t = 0;
+ gltexture_t *glt;
+ for (i = 0, glt = gltextures;i < numgltextures;i++, glt++)
+ {
+ t += glt->texeldatasize;
+ if (glt->identifier[0] == '&')
+ {
+ sc++;
+ s += glt->texeldatasize;
+ }
+ }
+ Con_Printf("%i textures, totalling %.3fMB, %i are (usually) unnecessary model skins totalling %.3fMB\n", numgltextures, t / 1048576.0, sc, s / 1048576.0);
+}
char engineversion[40];
-void GL_UploadTexture (gltexture_t *glt);
+//void GL_UploadTexture (gltexture_t *glt);
void gl_textures_start()
{
- int i;
- gltexture_t *glt;
- for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
- GL_UploadTexture(glt);
+// int i;
+// gltexture_t *glt;
+// for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
+// GL_UploadTexture(glt);
}
void gl_textures_shutdown()
if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || strstr((char *)gl_renderer, "Glide"))
Cvar_Set ("gl_max_size", "256");
+ gltextures = qmalloc(sizeof(gltexture_t) * MAX_GLTEXTURES);
+ memset(gltextures, 0, sizeof(gltexture_t) * MAX_GLTEXTURES);
Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
R_RegisterModule("GL_Textures", gl_textures_start, gl_textures_shutdown);
out = outdata;
fstep = (int) (inheight*65536.0f/outheight);
- row1 = malloc(outwidth*4);
- row2 = malloc(outwidth*4);
+ row1 = qmalloc(outwidth*4);
+ row2 = qmalloc(outwidth*4);
inrow = indata;
oldy = 0;
GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
row1 -= outwidth*4;
}
}
- free(row1);
- free(row2);
+ qfree(row1);
+ qfree(row2);
}
else
{
void GL_FreeTexels(gltexture_t *glt)
{
if (glt->texels[0])
- free(glt->texels[0]);
+ qfree(glt->texels[0]);
glt->texels[0] = 0;
}
void GL_AllocTexels(gltexture_t *glt, int width, int height, int mipmapped)
{
- int i, w, h, size, done;
+ int i, w, h, size;
if (glt->texels[0])
GL_FreeTexels(glt);
glt->texelsize[0][0] = width;
size = 0;
w = width;h = height;
i = 0;
- done = false;
- for (i = 0;i < MAXMIPS;i++)
+ while (i < MAXMIPS)
{
glt->texelsize[i][0] = w;
glt->texelsize[i][1] = h;
- glt->texels[i] = (void *)size;
+ glt->texels[i++] = (void *)size;
size += w*h*4;
if (w > 1)
{
else if (h > 1)
h >>= 1;
else
- {
- i++;
break;
- }
}
- glt->totaltexels = size;
+ glt->texeldatasize = size;
while (i < MAXMIPS)
glt->texels[i++] = NULL;
- glt->texels[0] = malloc(size);
+ glt->texels[0] = qmalloc(size);
for (i = 1;i < MAXMIPS && glt->texels[i];i++)
glt->texels[i] += (int) glt->texels[0];
}
else
{
size = width*height*4;
- glt->totaltexels = size;
- glt->texels[0] = malloc(size);
+ glt->texeldatasize = size;
+ glt->texels[0] = qmalloc(size);
for (i = 1;i < MAXMIPS;i++)
glt->texels[i] = NULL;
}
{
unsigned short crc;
int i, width2, height2, width3, height3, w, h, mip;
- gltexture_t *glt;
+ gltexture_t *glt, *freeglt;
+ // LordHavoc: texture caching, turned out to be a waste of time (and immense waste of diskspace)
+ //char cachefilename[1024], *cachefile;
if (isDedicated)
return 1;
+ freeglt = NULL;
+
// LordHavoc: do a CRC to confirm the data really is the same as previous occurances.
crc = CRC_Block(data, width*height*bytesperpixel);
// see if the texture is already present
{
for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
{
- if (!strcmp (identifier, glt->identifier))
+ if (glt->inuse)
{
- // LordHavoc: everyone hates cache mismatchs, so I fixed it
- if (crc != glt->crc || width != glt->width || height != glt->height)
+ if (!strcmp (identifier, glt->identifier))
{
- Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
- goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
- //Sys_Error ("GL_LoadTexture: cache mismatch");
+ // LordHavoc: everyone hates cache mismatchs, so I fixed it
+ if (crc != glt->crc || width != glt->width || height != glt->height)
+ {
+ Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
+ goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
+ }
+ if ((gl_lerpimages.value != 0) != glt->lerped)
+ goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
+ return glt->texnum;
}
- if ((gl_lerpimages.value != 0) != glt->lerped)
- goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
- return glt->texnum;
}
+ else
+ freeglt = glt;
}
}
+ else
+ i = 0;
// LordHavoc: although this could be an else condition as it was in the original id code,
// it is more clear this way
- // LordHavoc: check if there are still slots available
- if (numgltextures >= MAX_GLTEXTURES)
- Sys_Error ("GL_LoadTexture: ran out of texture slots (%d)\n", MAX_GLTEXTURES);
- glt = &gltextures[numgltextures++];
-
- strcpy (glt->identifier, identifier);
- glt->texnum = texture_extension_number;
- texture_extension_number++;
+ if (freeglt)
+ {
+ glt = freeglt;
+ strcpy (glt->identifier, identifier);
+ }
+ else
+ {
+ // LordHavoc: check if there are still slots available
+ if (numgltextures >= MAX_GLTEXTURES)
+ Sys_Error ("GL_LoadTexture: ran out of texture slots (%d)\n", MAX_GLTEXTURES);
+ glt = &gltextures[numgltextures++];
+ glt->texnum = texture_extension_number;
+ texture_extension_number++;
+ strcpy (glt->identifier, identifier);
+ }
+
// LordHavoc: label to drop out of the loop into the setup code
GL_LoadTexture_setup:
// calculate power of 2 size
glt->bytesperpixel = bytesperpixel;
glt->lerped = gl_lerpimages.value != 0;
glt->alpha = false; // updated later
+ glt->inuse = true;
+ /*
+ // LordHavoc: texture caching, turned out to be a waste of time (and immense waste of diskspace)
+ sprintf(cachefilename, "%s%x%x%x.texels", identifier, width3, height3, crc);
+ for (i = 0;cachefilename[i];i++)
+ {
+ if (cachefilename[i] <= ' ' || cachefilename[i] >= 127 || cachefilename[i] == '/' || cachefilename[i] == '\\' || cachefilename[i] == ':' || cachefilename[i] == '*' || cachefilename[i] == '?')
+ cachefilename[i] = '@';
+ if (cachefilename[i] >= 'A' && cachefilename[i] <= 'Z')
+ cachefilename[i] += 'a' - 'A';
+ }
+ cachefile = COM_LoadMallocFile(cachefilename, true);
+ if (cachefile)
+ {
+ if (cachefile[0] == 'D' && cachefile[1] == 'P' && cachefile[2] == 'C' && cachefile[3] == 'T')
+ {
+ memcpy(glt->texels[0], cachefile + 4, width3*height3*4);
+ qfree(cachefile);
+// Con_Printf("loaded cache texture %s\n", cachefilename);
+ goto cacheloaded;
+ }
+ else
+ qfree(cachefile);
+ }
+ */
if (width == width3 && height == height3) // perfect match
{
if (bytesperpixel == 1) // 8bit
else if (width == width2 && height == height2) // perfect match for top level, but needs to be reduced
{
byte *temptexels2;
- temptexels2 = malloc(width2*height2*4); // scaleup buffer
+ temptexels2 = qmalloc(width2*height2*4); // scaleup buffer
if (bytesperpixel == 1) // 8bit
Image_Copy8bitRGBA(data, temptexels2, width*height, d_8to24table);
else
else
GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
}
- free(temptexels2);
+ qfree(temptexels2);
}
else // scaling...
{
byte *temptexels;
// pre-scaleup buffer
- temptexels = malloc(width*height*4);
+ temptexels = qmalloc(width*height*4);
if (bytesperpixel == 1) // 8bit
Image_Copy8bitRGBA(data, temptexels, width*height, d_8to24table);
else
if (width2 != width3 || height2 != height3) // reduced by gl_pic_mip or gl_max_size
{
byte *temptexels2;
- temptexels2 = malloc(width2*height2*4); // scaleup buffer
+ temptexels2 = qmalloc(width2*height2*4); // scaleup buffer
GL_ResampleTexture(temptexels, width, height, temptexels2, width2, height2);
while (width2 > width3 || height2 > height3)
{
else
GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
}
- free(temptexels2);
+ qfree(temptexels2);
}
else // copy directly
GL_ResampleTexture(temptexels, width, height, glt->texels[0], width2, height2);
- free(temptexels);
+ qfree(temptexels);
}
+ /*
+ // LordHavoc: texture caching, turned out to be a waste of time (and immense waste of diskspace)
+ Con_Printf("writing cache texture %s\n", cachefilename);
+ cachefile = qmalloc(width3*height3*4 + 4);
+ cachefile[0] = 'D';
+ cachefile[1] = 'P';
+ cachefile[2] = 'C';
+ cachefile[3] = 'T';
+ memcpy(cachefile + 4, glt->texels[0], width3*height3*4);
+ COM_WriteFile(cachefilename, cachefile, width3*height3*4 + 4);
+ qfree(cachefile);
+cacheloaded:
+ */
if (alpha)
{
byte *in = glt->texels[0] + 3;
return glt->texnum;
}
-
-/*
-================
-GL_LoadPicTexture
-================
-*/
-int GL_LoadPicTexture (qpic_t *pic)
-{
- return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true, 1);
-}
-
-int GL_GetTextureSlots (int count)
-{
- gltexture_t *glt, *first;
-
- first = glt = &gltextures[numgltextures];
- while (count--)
- {
- glt->identifier[0] = 0;
- glt->texnum = texture_extension_number++;
- glt->crc = 0;
- glt->width = 0;
- glt->height = 0;
- glt->bytesperpixel = 0;
- glt++;
- numgltextures++;
- }
- return first->texnum;
-}