+ int textype;
+ int inputbytesperpixel;
+ int internalbytesperpixel;
+ int glformat;
+ int glinternalformat;
+}
+textypeinfo_t;
+
+static textypeinfo_t textype_palette = {TEXTYPE_PALETTE, 1, 4, GL_RGBA, 3};
+static textypeinfo_t textype_rgb = {TEXTYPE_RGB , 3, 3, GL_RGB , 3};
+static textypeinfo_t textype_rgba = {TEXTYPE_RGBA , 4, 4, GL_RGBA, 3};
+static textypeinfo_t textype_palette_alpha = {TEXTYPE_PALETTE, 1, 4, GL_RGBA, 4};
+static textypeinfo_t textype_rgba_alpha = {TEXTYPE_RGBA , 4, 4, GL_RGBA, 4};
+
+// a tiling texture (most common type)
+#define GLIMAGETYPE_TILE 0
+// a fragments texture (contains one or more fragment textures)
+#define GLIMAGETYPE_FRAGMENTS 1
+
+#define GLTEXTURETYPE_1D 0
+#define GLTEXTURETYPE_2D 1
+#define GLTEXTURETYPE_3D 2
+#define GLTEXTURETYPE_CUBEMAP 3
+
+static int gltexturetypeenums[4] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
+static int gltexturetypedimensions[4] = {1, 2, 3, 2};
+static int cubemapside[6] =
+{
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
+};
+
+// a gltextureimage can have one (or more if fragments) gltextures inside
+typedef struct gltextureimage_s
+{
+ struct gltextureimage_s *imagechain;
+ int texturecount;
+ int type; // one of the GLIMAGETYPE_ values
+ int texturetype; // one of the GLTEXTURETYPE_ values
+ int sides; // 1 or 6 depending on texturetype
+ int texnum; // GL texture slot number
+ int width, height, depth; // 3D texture support
+ int bytesperpixel; // bytes per pixel
+ int glformat; // GL_RGB or GL_RGBA
+ int glinternalformat; // 3 or 4
+ int flags;
+ short *blockallocation; // fragment allocation (2D only)
+}
+gltextureimage_t;
+
+typedef struct gltexture_s
+{
+ // this field is exposed to the R_GetTexture macro, for speed reasons
+ // (must be identical in rtexture_t)
+ int texnum; // GL texture slot number
+
+ // pointer to texturepool (check this to see if the texture is allocated)
+ struct gltexturepool_s *pool;
+ // pointer to next texture in texturepool chain
+ struct gltexture_s *chain;
+ // pointer into gltextureimage array
+ gltextureimage_t *image;
+ // name of the texture (this might be removed someday), no duplicates
+ char *identifier;
+ // location in the image, and size
+ int x, y, z, width, height, depth;
+ // copy of the original texture(s) supplied to the upload function, for
+ // delayed uploads (non-precached)
+ qbyte *inputtexels;
+ // original data size in *inputtexels
+ int inputdatasize;
+ // flags supplied to the LoadTexture function
+ // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
+ int flags;
+ // pointer to one of the textype_ structs
+ textypeinfo_t *textype;
+ // one of the GLTEXTURETYPE_ values
+ int texturetype;
+ // palette if the texture is TEXTYPE_PALETTE
+ const unsigned int *palette;
+}
+gltexture_t;
+
+#define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
+
+typedef struct gltexturepool_s
+{
+ unsigned int sentinel;
+ struct gltextureimage_s *imagechain;
+ struct gltexture_s *gltchain;
+ struct gltexturepool_s *next;
+}
+gltexturepool_t;
+
+static gltexturepool_t *gltexturepoolchain = NULL;
+
+static qbyte *resizebuffer = NULL, *colorconvertbuffer;
+static int resizebuffersize = 0;
+static qbyte *texturebuffer;
+static int texturebuffersize = 0;
+
+static int realmaxsize = 0;
+
+static textypeinfo_t *R_GetTexTypeInfo(int textype, int flags)
+{
+ if (flags & TEXF_ALPHA)
+ {
+ switch(textype)
+ {
+ case TEXTYPE_PALETTE:
+ return &textype_palette_alpha;
+ case TEXTYPE_RGB:
+ Host_Error("R_GetTexTypeInfo: RGB format has no alpha, TEXF_ALPHA not allowed\n");
+ return NULL;
+ case TEXTYPE_RGBA:
+ return &textype_rgba_alpha;
+ default:
+ Host_Error("R_GetTexTypeInfo: unknown texture format\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ switch(textype)
+ {
+ case TEXTYPE_PALETTE:
+ return &textype_palette;
+ case TEXTYPE_RGB:
+ return &textype_rgb;
+ case TEXTYPE_RGBA:
+ return &textype_rgba;
+ default:
+ Host_Error("R_GetTexTypeInfo: unknown texture format\n");
+ return NULL;
+ }
+ }
+}
+
+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_UPLOAD)
+ R_UploadTexture(glt);
+ glt->texnum = glt->image->texnum;
+ return glt->image->texnum;
+ }
+ else
+ return 0;
+}
+
+void R_FreeTexture(rtexture_t *rt)
+{
+ gltexture_t *glt, **gltpointer;
+ gltextureimage_t *image, **gltimagepointer;
+
+ glt = (gltexture_t *)rt;
+ if (glt == NULL)
+ Host_Error("R_FreeTexture: texture == NULL\n");
+
+ for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
+ if (*gltpointer == glt)
+ *gltpointer = glt->chain;
+ else
+ Host_Error("R_FreeTexture: texture \"%s\" not linked in pool\n", glt->identifier);
+
+ // note: if freeing a fragment texture, this will not make the claimed
+ // space available for new textures unless all other fragments in the
+ // image are also freed
+ if (glt->image)
+ {
+ image = glt->image;
+ image->texturecount--;
+ if (image->texturecount < 1)
+ {
+ for (gltimagepointer = &glt->pool->imagechain;*gltimagepointer && *gltimagepointer != image;gltimagepointer = &(*gltimagepointer)->imagechain);
+ if (*gltimagepointer == image)
+ *gltimagepointer = image->imagechain;
+ else
+ Host_Error("R_FreeTexture: image not linked in pool\n");
+ if (image->texnum)
+ qglDeleteTextures(1, &image->texnum);
+ if (image->blockallocation)
+ Mem_Free(image->blockallocation);
+ Mem_Free(image);
+ }
+ }
+
+ if (glt->identifier)
+ Mem_Free(glt->identifier);
+ if (glt->inputtexels)
+ Mem_Free(glt->inputtexels);
+ Mem_Free(glt);
+}
+
+/*
+static gltexture_t *R_FindTexture (gltexturepool_t *pool, char *identifier)
+{
+ gltexture_t *glt;
+
+ if (!identifier)
+ return NULL;
+
+ for (glt = pool->gltchain;glt;glt = glt->chain)
+ if (glt->identifier && !strcmp (identifier, glt->identifier))
+ return glt;
+
+ return NULL;
+}
+*/
+
+rtexturepool_t *R_AllocTexturePool(void)
+{
+ gltexturepool_t *pool;
+ if (texturemempool == NULL)
+ return NULL;
+ pool = Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
+ if (pool == NULL)
+ return NULL;
+ pool->next = gltexturepoolchain;
+ gltexturepoolchain = pool;
+ pool->sentinel = TEXTUREPOOL_SENTINEL;
+ return (rtexturepool_t *)pool;
+}
+
+void R_FreeTexturePool(rtexturepool_t **rtexturepool)
+{
+ gltexturepool_t *pool, **poolpointer;
+ if (rtexturepool == NULL)
+ return;
+ if (*rtexturepool == NULL)
+ return;
+ pool = (gltexturepool_t *)(*rtexturepool);
+ *rtexturepool = NULL;
+ if (pool->sentinel != TEXTUREPOOL_SENTINEL)
+ Host_Error("R_FreeTexturePool: pool already freed\n");
+ for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
+ if (*poolpointer == pool)
+ *poolpointer = pool->next;
+ else
+ Host_Error("R_FreeTexturePool: pool not linked\n");
+ while (pool->gltchain)
+ R_FreeTexture((rtexture_t *)pool->gltchain);
+ if (pool->imagechain)
+ Sys_Error("R_FreeTexturePool: not all images freed\n");
+ Mem_Free(pool);
+}
+