]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
added TEXF_CLAMP flag for textures
[xonotic/darkplaces.git] / gl_textures.c
1
2 #include "quakedef.h"
3
4 cvar_t  r_max_size = {CVAR_SAVE, "r_max_size", "2048"};
5 cvar_t  r_max_scrapsize = {CVAR_SAVE, "r_max_scrapsize", "256"};
6 cvar_t  r_picmip = {CVAR_SAVE, "r_picmip", "0"};
7 cvar_t  r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1"};
8 cvar_t  r_precachetextures = {CVAR_SAVE, "r_precachetextures", "1"};
9
10 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
11 int             gl_filter_mag = GL_LINEAR;
12
13
14 static mempool_t *texturemempool;
15 static mempool_t *texturedatamempool;
16 static mempool_t *textureprocessingmempool;
17
18 // note: this must not conflict with TEXF_ flags in r_textures.h
19 // cleared when a texture is uploaded
20 #define GLTEXF_UPLOAD 0x00010000
21 // bitmask for mismatch checking
22 #define GLTEXF_IMPORTANTBITS (0)
23 // set when image is uploaded and freed
24 #define GLTEXF_DESTROYED 0x00040000
25
26 // size of images which hold fragment textures, ignores picmip and max_size
27 static int block_size;
28
29 typedef struct
30 {
31         int textype;
32         int inputbytesperpixel;
33         int internalbytesperpixel;
34         int glformat;
35         int glinternalformat;
36 }
37 textypeinfo_t;
38
39 static textypeinfo_t textype_qpalette       = {TEXTYPE_QPALETTE, 1, 4, GL_RGBA, 3};
40 static textypeinfo_t textype_rgb            = {TEXTYPE_RGB     , 3, 3, GL_RGB , 3};
41 static textypeinfo_t textype_rgba           = {TEXTYPE_RGBA    , 4, 4, GL_RGBA, 3};
42 static textypeinfo_t textype_qpalette_alpha = {TEXTYPE_QPALETTE, 1, 4, GL_RGBA, 4};
43 static textypeinfo_t textype_rgba_alpha     = {TEXTYPE_RGBA    , 4, 4, GL_RGBA, 4};
44
45 // a tiling texture (most common type)
46 #define GLIMAGETYPE_TILE 0
47 // a fragments texture (contains one or more fragment textures)
48 #define GLIMAGETYPE_FRAGMENTS 1
49
50 #define GLTEXTURETYPE_1D 0
51 #define GLTEXTURETYPE_2D 1
52 #define GLTEXTURETYPE_3D 2
53 #define GLTEXTURETYPE_CUBEMAP 3
54
55 static int gltexturetypeenums[4] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
56 static int gltexturetypedimensions[4] = {1, 2, 3, 2};
57 static int cubemapside[6] =
58 {
59         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
60         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
61         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
62         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
63         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
64         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
65 };
66
67 // a gltextureimage can have one (or more if fragments) gltextures inside
68 typedef struct gltextureimage_s
69 {
70         struct gltextureimage_s *imagechain;
71         int texturecount;
72         int type; // one of the GLIMAGETYPE_ values
73         int texturetype; // one of the GLTEXTURETYPE_ values
74         int sides; // 1 or 6 depending on texturetype
75         int texnum; // GL texture slot number
76         int width, height, depth; // 3D texture support
77         int bytesperpixel; // bytes per pixel
78         int glformat; // GL_RGB or GL_RGBA
79         int glinternalformat; // 3 or 4
80         int flags;
81         short *blockallocation; // fragment allocation (2D only)
82 }
83 gltextureimage_t;
84
85 typedef struct gltexture_s
86 {
87         // this field is exposed to the R_GetTexture macro, for speed reasons
88         // (must be identical in rtexture_t)
89         int texnum; // GL texture slot number
90
91         // pointer to texturepool (check this to see if the texture is allocated)
92         struct gltexturepool_s *pool;
93         // pointer to next texture in texturepool chain
94         struct gltexture_s *chain;
95         // pointer into gltextureimage array
96         gltextureimage_t *image;
97         // name of the texture (this might be removed someday), no duplicates
98         char *identifier;
99         // location in the image, and size
100         int x, y, z, width, height, depth;
101         // copy of the original texture(s) supplied to the upload function, for
102         // delayed uploads (non-precached)
103         qbyte *inputtexels;
104         // original data size in *inputtexels
105         int inputdatasize;
106         // flags supplied to the LoadTexture function
107         // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
108         int flags;
109         // pointer to one of the textype_ structs
110         textypeinfo_t *textype;
111         // one of the GLTEXTURETYPE_ values
112         int texturetype;
113 }
114 gltexture_t;
115
116 #define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
117
118 typedef struct gltexturepool_s
119 {
120         int sentinel;
121         struct gltextureimage_s *imagechain;
122         struct gltexture_s *gltchain;
123         struct gltexturepool_s *next;
124 }
125 gltexturepool_t;
126
127 static gltexturepool_t *gltexturepoolchain = NULL;
128
129 static qbyte *resizebuffer = NULL, *colorconvertbuffer;
130 static int resizebuffersize = 0;
131 static qbyte *texturebuffer;
132 static int texturebuffersize = 0;
133
134 static int realmaxsize = 0;
135
136 static textypeinfo_t *R_GetTexTypeInfo(int textype, int flags)
137 {
138         if (flags & TEXF_ALPHA)
139         {
140                 switch(textype)
141                 {
142                 case TEXTYPE_QPALETTE:
143                         return &textype_qpalette_alpha;
144                 case TEXTYPE_RGB:
145                         Host_Error("R_GetTexTypeInfo: RGB format has no alpha, TEXF_ALPHA not allowed\n");
146                         return NULL;
147                 case TEXTYPE_RGBA:
148                         return &textype_rgba_alpha;
149                 default:
150                         Host_Error("R_GetTexTypeInfo: unknown texture format\n");
151                         return NULL;
152                 }
153         }
154         else
155         {
156                 switch(textype)
157                 {
158                 case TEXTYPE_QPALETTE:
159                         return &textype_qpalette;
160                 case TEXTYPE_RGB:
161                         return &textype_rgb;
162                 case TEXTYPE_RGBA:
163                         return &textype_rgba;
164                 default:
165                         Host_Error("R_GetTexTypeInfo: unknown texture format\n");
166                         return NULL;
167                 }
168         }
169 }
170
171 static void R_UploadTexture(gltexture_t *t);
172
173 static void R_PrecacheTexture(gltexture_t *glt)
174 {
175         int precache;
176         precache = false;
177         if (glt->flags & TEXF_ALWAYSPRECACHE)
178                 precache = true;
179         else if (r_precachetextures.integer >= 2)
180                 precache = true;
181         else if (r_precachetextures.integer >= 1)
182                 if (glt->flags & TEXF_PRECACHE)
183                         precache = true;
184
185         if (precache)
186                 R_UploadTexture(glt);
187 }
188
189 int R_RealGetTexture(rtexture_t *rt)
190 {
191         if (rt)
192         {
193                 gltexture_t *glt;
194                 glt = (gltexture_t *)rt;
195                 if (glt->flags & GLTEXF_UPLOAD)
196                         R_UploadTexture(glt);
197                 glt->texnum = glt->image->texnum;
198                 return glt->image->texnum;
199         }
200         else
201                 return 0;
202 }
203
204 void R_FreeTexture(rtexture_t *rt)
205 {
206         gltexture_t *glt, **gltpointer;
207         gltextureimage_t *image, **gltimagepointer;
208
209         glt = (gltexture_t *)rt;
210         if (glt == NULL)
211                 Host_Error("R_FreeTexture: texture == NULL\n");
212
213         for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
214         if (*gltpointer == glt)
215                 *gltpointer = glt->chain;
216         else
217                 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool\n", glt->identifier);
218
219         // note: if freeing a fragment texture, this will not make the claimed
220         // space available for new textures unless all other fragments in the
221         // image are also freed
222         image = glt->image;
223         image->texturecount--;
224         if (image->texturecount < 1)
225         {
226                 for (gltimagepointer = &glt->pool->imagechain;*gltimagepointer && *gltimagepointer != image;gltimagepointer = &(*gltimagepointer)->imagechain);
227                 if (*gltimagepointer == image)
228                         *gltimagepointer = image->imagechain;
229                 else
230                         Host_Error("R_FreeTexture: image not linked in pool\n");
231                 if (image->texnum)
232                         qglDeleteTextures(1, &image->texnum);
233                 if (image->blockallocation)
234                         Mem_Free(image->blockallocation);
235                 Mem_Free(image);
236         }
237
238         if (glt->identifier)
239                 Mem_Free(glt->identifier);
240         if (glt->inputtexels)
241                 Mem_Free(glt->inputtexels);
242         Mem_Free(glt);
243 }
244
245 /*
246 static gltexture_t *R_FindTexture (gltexturepool_t *pool, char *identifier)
247 {
248         gltexture_t     *glt;
249
250         if (!identifier)
251                 return NULL;
252
253         for (glt = pool->gltchain;glt;glt = glt->chain)
254                 if (glt->identifier && !strcmp (identifier, glt->identifier))
255                         return glt;
256
257         return NULL;
258 }
259 */
260
261 rtexturepool_t *R_AllocTexturePool(void)
262 {
263         gltexturepool_t *pool;
264         if (texturemempool == NULL)
265                 return NULL;
266         pool = Mem_Alloc(texturemempool, sizeof(gltexturepool_t));
267         if (pool == NULL)
268                 return NULL;
269         pool->next = gltexturepoolchain;
270         gltexturepoolchain = pool;
271         pool->sentinel = TEXTUREPOOL_SENTINEL;
272         return (rtexturepool_t *)pool;
273 }
274
275 void R_FreeTexturePool(rtexturepool_t **rtexturepool)
276 {
277         gltexturepool_t *pool, **poolpointer;
278         if (rtexturepool == NULL)
279                 return;
280         if (*rtexturepool == NULL)
281                 return;
282         pool = (gltexturepool_t *)(*rtexturepool);
283         *rtexturepool = NULL;
284         if (pool->sentinel != TEXTUREPOOL_SENTINEL)
285                 Host_Error("R_FreeTexturePool: pool already freed\n");
286         for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
287         if (*poolpointer == pool)
288                 *poolpointer = pool->next;
289         else
290                 Host_Error("R_FreeTexturePool: pool not linked\n");
291         while (pool->gltchain)
292                 R_FreeTexture((rtexture_t *)pool->gltchain);
293         if (pool->imagechain)
294                 Sys_Error("R_FreeTexturePool: not all images freed\n");
295         Mem_Free(pool);
296 }
297
298
299 typedef struct
300 {
301         char *name;
302         int minification, magnification;
303 }
304 glmode_t;
305
306 static glmode_t modes[] =
307 {
308         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
309         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
310         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
311         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
312         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
313         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
314 };
315
316 extern int gl_backend_rebindtextures;
317
318 static void GL_TextureMode_f (void)
319 {
320         int i;
321         gltextureimage_t *image;
322         gltexturepool_t *pool;
323
324         if (Cmd_Argc() == 1)
325         {
326                 for (i = 0;i < 6;i++)
327                 {
328                         if (gl_filter_min == modes[i].minification)
329                         {
330                                 Con_Printf ("%s\n", modes[i].name);
331                                 return;
332                         }
333                 }
334                 Con_Printf ("current filter is unknown???\n");
335                 return;
336         }
337
338         for (i = 0;i < 6;i++)
339                 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
340                         break;
341         if (i == 6)
342         {
343                 Con_Printf ("bad filter name\n");
344                 return;
345         }
346
347         gl_filter_min = modes[i].minification;
348         gl_filter_mag = modes[i].magnification;
349
350         // change all the existing mipmap texture objects
351         // FIXME: force renderer(/client/something?) restart instead?
352         for (pool = gltexturepoolchain;pool;pool = pool->next)
353         {
354                 for (image = pool->imagechain;image;image = image->imagechain)
355                 {
356                         // only update already uploaded images
357                         if (!(image->flags & GLTEXF_UPLOAD))
358                         {
359                                 qglBindTexture(GL_TEXTURE_2D, image->texnum);
360                                 if (image->flags & TEXF_MIPMAP)
361                                         qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
362                                 else
363                                         qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_mag);
364                                 qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
365                         }
366                 }
367         }
368         gl_backend_rebindtextures = true;
369 }
370
371 static int R_CalcTexelDataSize (gltexture_t *glt)
372 {
373         int width2, height2, depth2, size;
374         if (glt->flags & TEXF_FRAGMENT)
375                 size = glt->width * glt->height * glt->depth;
376         else
377         {
378                 if (r_max_size.integer > realmaxsize)
379                         Cvar_SetValue("r_max_size", realmaxsize);
380                 // calculate final size
381                 for (width2 = 1;width2 < glt->width;width2 <<= 1);
382                 for (height2 = 1;height2 < glt->height;height2 <<= 1);
383                 for (depth2 = 1;depth2 < glt->depth;depth2 <<= 1);
384                 for (width2 >>= r_picmip.integer;width2 > r_max_size.integer;width2 >>= 1);
385                 for (height2 >>= r_picmip.integer;height2 > r_max_size.integer;height2 >>= 1);
386                 for (depth2 >>= r_picmip.integer;depth2 > r_max_size.integer;depth2 >>= 1);
387                 if (width2 < 1) width2 = 1;
388                 if (height2 < 1) height2 = 1;
389                 if (depth2 < 1) depth2 = 1;
390
391                 size = 0;
392                 if (glt->flags & TEXF_MIPMAP)
393                 {
394                         while (width2 > 1 || height2 > 1 || depth2 > 1)
395                         {
396                                 size += width2 * height2 * depth2;
397                                 if (width2 > 1)
398                                         width2 >>= 1;
399                                 if (height2 > 1)
400                                         height2 >>= 1;
401                                 if (depth2 > 1)
402                                         depth2 >>= 1;
403                         }
404                         size++; // count the last 1x1 mipmap
405                 }
406                 else
407                         size = width2 * height2 * depth2;
408         }
409         size *= glt->textype->internalbytesperpixel * glt->image->sides;
410
411         return size;
412 }
413
414 void R_TextureStats_PrintTotal(void)
415 {
416         int glsize, total = 0, totalt = 0, totalp = 0, loaded = 0, loadedt = 0, loadedp = 0;
417         gltexture_t *glt;
418         gltexturepool_t *pool;
419         for (pool = gltexturepoolchain;pool;pool = pool->next)
420         {
421                 for (glt = pool->gltchain;glt;glt = glt->chain)
422                 {
423                         glsize = R_CalcTexelDataSize(glt);
424                         total++;
425                         totalt += glsize;
426                         totalp += glt->inputdatasize;
427                         if (!(glt->flags & GLTEXF_UPLOAD))
428                         {
429                                 loaded++;
430                                 loadedt += glsize;
431                                 loadedp += glt->inputdatasize;
432                         }
433                 }
434         }
435         Con_Printf("total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", total, totalt / 1048576.0, totalp / 1048576.0, loaded, loadedt / 1048576.0, loadedp / 1048576.0, total - loaded, (totalt - loadedt) / 1048576.0, (totalp - loadedp) / 1048576.0);
436 }
437
438 static void R_TextureStats_f(void)
439 {
440         int loaded;
441         gltexture_t *glt;
442         gltexturepool_t *pool;
443         Con_Printf("glsize input loaded mip alpha name\n");
444         for (pool = gltexturepoolchain;pool;pool = pool->next)
445         {
446                 for (glt = pool->gltchain;glt;glt = glt->chain)
447                 {
448                         loaded = !(glt->flags & GLTEXF_UPLOAD);
449                         Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", loaded ? '[' : ' ', (R_CalcTexelDataSize(glt) + 1023) / 1024, loaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', loaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier ? glt->identifier : "<unnamed>");
450                 }
451                 Con_Printf("pool %10p\n", pool);
452         }
453         R_TextureStats_PrintTotal();
454 }
455
456 char engineversion[40];
457
458 static void r_textures_start(void)
459 {
460         // deal with size limits of various drivers (3dfx in particular)
461         qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &realmaxsize);
462         CHECKGLERROR
463         // LordHavoc: allow any alignment
464         qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
465         CHECKGLERROR
466
467         // use the largest scrap texture size we can (not sure if this is really a good idea)
468         for (block_size = 1;block_size < realmaxsize && block_size < r_max_scrapsize.integer;block_size <<= 1);
469
470         texturemempool = Mem_AllocPool("Texture Info");
471         texturedatamempool = Mem_AllocPool("Texture Storage (not yet uploaded)");
472         textureprocessingmempool = Mem_AllocPool("Texture Processing Buffers");
473 }
474
475 static void r_textures_shutdown(void)
476 {
477         rtexturepool_t *temp;
478         while(gltexturepoolchain)
479         {
480                 temp = (rtexturepool_t *) gltexturepoolchain;
481                 R_FreeTexturePool(&temp);
482         }
483
484         resizebuffersize = 0;
485         texturebuffersize = 0;
486         resizebuffer = NULL;
487         colorconvertbuffer = NULL;
488         texturebuffer = NULL;
489         Mem_FreePool(&texturemempool);
490         Mem_FreePool(&texturedatamempool);
491         Mem_FreePool(&textureprocessingmempool);
492 }
493
494 static void r_textures_newmap(void)
495 {
496 }
497
498 void R_Textures_Init (void)
499 {
500         Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f);
501         Cmd_AddCommand("r_texturestats", R_TextureStats_f);
502         Cvar_RegisterVariable (&r_max_scrapsize);
503         Cvar_RegisterVariable (&r_max_size);
504         Cvar_RegisterVariable (&r_picmip);
505         Cvar_RegisterVariable (&r_lerpimages);
506         Cvar_RegisterVariable (&r_precachetextures);
507
508         R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap);
509 }
510
511 void R_Textures_Frame (void)
512 {
513         // could do procedural texture animation here, if we keep track of which
514         // textures were accessed this frame...
515
516         // free the resize buffers
517         resizebuffersize = 0;
518         if (resizebuffer)
519         {
520                 Mem_Free(resizebuffer);
521                 resizebuffer = NULL;
522         }
523         if (colorconvertbuffer)
524         {
525                 Mem_Free(colorconvertbuffer);
526                 colorconvertbuffer = NULL;
527         }
528 }
529
530 void R_MakeResizeBufferBigger(int size)
531 {
532         if (resizebuffersize < size)
533         {
534                 resizebuffersize = size;
535                 if (resizebuffer)
536                         Mem_Free(resizebuffer);
537                 if (colorconvertbuffer)
538                         Mem_Free(colorconvertbuffer);
539                 resizebuffer = Mem_Alloc(textureprocessingmempool, resizebuffersize);
540                 colorconvertbuffer = Mem_Alloc(textureprocessingmempool, resizebuffersize);
541                 if (!resizebuffer || !colorconvertbuffer)
542                         Host_Error("R_Upload: out of memory\n");
543         }
544 }
545
546 static void GL_SetupTextureParameters(int flags, int texturetype)
547 {
548         int textureenum = gltexturetypeenums[texturetype];
549         int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP : GL_REPEAT;
550
551         CHECKGLERROR
552
553         qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);
554         if (gltexturetypedimensions[texturetype] >= 2)
555                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);
556         if (gltexturetypedimensions[texturetype] >= 3)
557                 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);
558
559         if (flags & TEXF_MIPMAP)
560                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);
561         else
562                 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);
563         qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);
564
565         CHECKGLERROR
566 }
567
568 static void R_Upload(gltexture_t *glt, qbyte *data)
569 {
570         int i, mip, width, height, depth, internalformat;
571         qbyte *prevbuffer;
572         prevbuffer = data;
573
574         CHECKGLERROR
575
576         glt->texnum = glt->image->texnum;
577         qglBindTexture(gltexturetypeenums[glt->image->texturetype], glt->image->texnum);
578         CHECKGLERROR
579         glt->flags &= ~GLTEXF_UPLOAD;
580         gl_backend_rebindtextures = true;
581
582         if (glt->flags & TEXF_FRAGMENT)
583         {
584                 if (glt->image->flags & GLTEXF_UPLOAD)
585                 {
586                         glt->image->flags &= ~GLTEXF_UPLOAD;
587                         Con_DPrintf("uploaded new fragments image\n");
588                         R_MakeResizeBufferBigger(glt->image->width * glt->image->height * glt->image->depth * glt->image->bytesperpixel);
589                         memset(resizebuffer, 255, glt->image->width * glt->image->height * glt->image->depth * glt->image->bytesperpixel);
590                         switch(glt->image->texturetype)
591                         {
592                         case GLTEXTURETYPE_1D:
593                                 qglTexImage1D(GL_TEXTURE_1D, 0, glt->image->glinternalformat, glt->image->width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, resizebuffer);
594                                 CHECKGLERROR
595                                 break;
596                         case GLTEXTURETYPE_2D:
597                                 qglTexImage2D(GL_TEXTURE_2D, 0, glt->image->glinternalformat, glt->image->width, glt->image->height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, resizebuffer);
598                                 CHECKGLERROR
599                                 break;
600                         case GLTEXTURETYPE_3D:
601                                 qglTexImage3D(GL_TEXTURE_3D, 0, glt->image->glinternalformat, glt->image->width, glt->image->height, glt->image->depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, resizebuffer);
602                                 CHECKGLERROR
603                                 break;
604                         default:
605                                 Host_Error("R_Upload: fragment texture of type other than 1D, 2D, or 3D\n");
606                                 break;
607                         }
608                         GL_SetupTextureParameters(glt->image->flags, glt->image->texturetype);
609                 }
610
611                 if (prevbuffer == NULL)
612                 {
613                         R_MakeResizeBufferBigger(glt->image->width * glt->image->height * glt->image->depth * glt->image->bytesperpixel);
614                         memset(resizebuffer, 255, glt->width * glt->height * glt->image->depth * glt->image->bytesperpixel);
615                         prevbuffer = resizebuffer;
616                 }
617                 else if (glt->textype->textype == TEXTYPE_QPALETTE)
618                 {
619                         // promote paletted to RGBA, so we only have to worry about RGB and
620                         // RGBA in the rest of this code
621                         R_MakeResizeBufferBigger(glt->image->width * glt->image->height * glt->image->depth * glt->image->bytesperpixel);
622                         Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height * glt->depth, d_8to24table);
623                         prevbuffer = colorconvertbuffer;
624                 }
625
626                 switch(glt->image->texturetype)
627                 {
628                 case GLTEXTURETYPE_1D:
629                         qglTexSubImage1D(GL_TEXTURE_1D, 0, glt->x, glt->width, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
630                         CHECKGLERROR
631                         break;
632                 case GLTEXTURETYPE_2D:
633                         qglTexSubImage2D(GL_TEXTURE_2D, 0, glt->x, glt->y, glt->width, glt->height, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
634                         CHECKGLERROR
635                         break;
636                 case GLTEXTURETYPE_3D:
637                         qglTexSubImage3D(GL_TEXTURE_3D, 0, glt->x, glt->y, glt->z, glt->width, glt->height, glt->depth, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
638                         CHECKGLERROR
639                         break;
640                 default:
641                         Host_Error("R_Upload: fragment texture of type other than 1D, 2D, or 3D\n");
642                         break;
643                 }
644                 glt->texnum = glt->image->texnum;
645                 return;
646         }
647
648         glt->image->flags &= ~GLTEXF_UPLOAD;
649
650         // these are rounded up versions of the size to do better resampling
651         for (width  = 1;width  < glt->width ;width  <<= 1);
652         for (height = 1;height < glt->height;height <<= 1);
653         for (depth  = 1;depth  < glt->depth ;depth  <<= 1);
654
655         R_MakeResizeBufferBigger(width * height * depth * glt->image->bytesperpixel);
656
657         if (prevbuffer == NULL)
658         {
659                 width = glt->image->width;
660                 height = glt->image->height;
661                 depth = glt->image->depth;
662                 memset(resizebuffer, 255, width * height * depth * glt->image->bytesperpixel);
663                 prevbuffer = resizebuffer;
664         }
665         else
666         {
667                 if (glt->textype->textype == TEXTYPE_QPALETTE)
668                 {
669                         // promote paletted to RGBA, so we only have to worry about RGB and
670                         // RGBA in the rest of this code
671                         Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height * glt->depth, d_8to24table);
672                         prevbuffer = colorconvertbuffer;
673                 }
674
675                 if (glt->width != width || glt->height != height || glt->depth != depth)
676                 {
677                         Image_Resample(prevbuffer, glt->width, glt->height, glt->depth, resizebuffer, width, height, depth, glt->image->bytesperpixel, r_lerpimages.integer);
678                         prevbuffer = resizebuffer;
679                 }
680
681                 // apply picmip/max_size limitations
682                 while (width > glt->image->width || height > glt->image->height || depth > glt->image->depth)
683                 {
684                         Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, glt->image->width, glt->image->height, glt->image->depth, glt->image->bytesperpixel);
685                         prevbuffer = resizebuffer;
686                 }
687         }
688
689         // 3 and 4 are converted by the driver to it's preferred format for the current display mode
690         internalformat = 3;
691         if (glt->flags & TEXF_ALPHA)
692                 internalformat = 4;
693
694         mip = 0;
695         switch(glt->image->texturetype)
696         {
697         case GLTEXTURETYPE_1D:
698                 qglTexImage1D(GL_TEXTURE_1D, mip++, internalformat, width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
699                 CHECKGLERROR
700                 if (glt->flags & TEXF_MIPMAP)
701                 {
702                         while (width > 1 || height > 1 || depth > 1)
703                         {
704                                 Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
705                                 prevbuffer = resizebuffer;
706                                 qglTexImage1D(GL_TEXTURE_1D, mip++, internalformat, width, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
707                                 CHECKGLERROR
708                         }
709                 }
710                 break;
711         case GLTEXTURETYPE_2D:
712                 qglTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
713                 CHECKGLERROR
714                 if (glt->flags & TEXF_MIPMAP)
715                 {
716                         while (width > 1 || height > 1 || depth > 1)
717                         {
718                                 Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
719                                 prevbuffer = resizebuffer;
720                                 qglTexImage2D(GL_TEXTURE_2D, mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
721                                 CHECKGLERROR
722                         }
723                 }
724                 break;
725         case GLTEXTURETYPE_3D:
726                 qglTexImage3D(GL_TEXTURE_3D, mip++, internalformat, width, height, depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
727                 CHECKGLERROR
728                 if (glt->flags & TEXF_MIPMAP)
729                 {
730                         while (width > 1 || height > 1 || depth > 1)
731                         {
732                                 Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
733                                 prevbuffer = resizebuffer;
734                                 qglTexImage3D(GL_TEXTURE_3D, mip++, internalformat, width, height, depth, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
735                                 CHECKGLERROR
736                         }
737                 }
738                 break;
739         case GLTEXTURETYPE_CUBEMAP:
740                 // convert and upload each side in turn,
741                 // from a continuous block of input texels
742                 texturebuffer = prevbuffer;
743                 for (i = 0;i < 6;i++)
744                 {
745                         prevbuffer = texturebuffer;
746                         texturebuffer += width * height * depth * glt->textype->inputbytesperpixel;
747                         qglTexImage2D(cubemapside[i], mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
748                         CHECKGLERROR
749                         if (glt->flags & TEXF_MIPMAP)
750                         {
751                                 while (width > 1 || height > 1 || depth > 1)
752                                 {
753                                         Image_MipReduce(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1, glt->image->bytesperpixel);
754                                         prevbuffer = resizebuffer;
755                                         qglTexImage2D(cubemapside[i], mip++, internalformat, width, height, 0, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer);
756                                         CHECKGLERROR
757                                 }
758                         }
759                 }
760                 break;
761         }
762         GL_SetupTextureParameters(glt->image->flags, glt->image->texturetype);
763 }
764
765 static void R_FindImageForTexture(gltexture_t *glt)
766 {
767         int i, j, best, best2, x, y, z, w, h, d;
768         textypeinfo_t *texinfo;
769         gltexturepool_t *pool;
770         gltextureimage_t *image, **imagechainpointer;
771         texinfo = glt->textype;
772         pool = glt->pool;
773
774         // remains -1 until uploaded
775         glt->texnum = -1;
776
777         x = 0;
778         y = 0;
779         z = 0;
780         w = glt->width;
781         h = glt->height;
782         d = glt->depth;
783         if (glt->flags & TEXF_FRAGMENT)
784         {
785                 for (imagechainpointer = &pool->imagechain;*imagechainpointer;imagechainpointer = &(*imagechainpointer)->imagechain)
786                 {
787                         image = *imagechainpointer;
788                         if (image->type != GLIMAGETYPE_FRAGMENTS)
789                                 continue;
790                         if (image->texturetype != glt->texturetype)
791                                 continue;
792                         if ((image->flags ^ glt->flags) & (TEXF_MIPMAP | TEXF_ALPHA | TEXF_CLAMP))
793                                 continue;
794                         if (image->glformat != texinfo->glformat || image->glinternalformat != texinfo->glinternalformat)
795                                 continue;
796                         if (glt->width > image->width || glt->height > image->height || glt->depth > image->depth)
797                                 continue;
798
799                         // got a fragments texture, find a place in it if we can
800                         for (best = image->width, i = 0;i < image->width - w;i++)
801                         {
802                                 for (best2 = 0, j = 0;j < w;j++)
803                                 {
804                                         if (image->blockallocation[i+j] >= best)
805                                                 break;
806                                         if (best2 < image->blockallocation[i+j])
807                                                 best2 = image->blockallocation[i+j];
808                                 }
809                                 if (j == w)
810                                 {
811                                         // this is a valid spot
812                                         x = i;
813                                         y = best = best2;
814                                 }
815                         }
816
817                         if (best + h > image->height)
818                                 continue;
819
820                         for (i = 0;i < w;i++)
821                                 image->blockallocation[x + i] = best + h;
822
823                         glt->x = x;
824                         glt->y = y;
825                         glt->z = 0;
826                         glt->image = image;
827                         image->texturecount++;
828                         return;
829                 }
830
831                 image = Mem_Alloc(texturemempool, sizeof(gltextureimage_t));
832                 if (image == NULL)
833                         Sys_Error("R_FindImageForTexture: ran out of memory\n");
834                 image->type = GLIMAGETYPE_FRAGMENTS;
835                 // make sure the created image is big enough for the fragment
836                 for (image->width = block_size;image->width < glt->width;image->width <<= 1);
837                 image->height = 1;
838                 if (gltexturetypedimensions[glt->texturetype] >= 2)
839                         for (image->height = block_size;image->height < glt->height;image->height <<= 1);
840                 image->depth = 1;
841                 if (gltexturetypedimensions[glt->texturetype] >= 3)
842                         for (image->depth = block_size;image->depth < glt->depth;image->depth <<= 1);
843                 image->blockallocation = Mem_Alloc(texturemempool, image->width * sizeof(short));
844                 memset(image->blockallocation, 0, image->width * sizeof(short));
845
846                 x = 0;
847                 y = 0;
848                 z = 0;
849                 for (i = 0;i < w;i++)
850                         image->blockallocation[x + i] = y + h;
851         }
852         else
853         {
854                 for (imagechainpointer = &pool->imagechain;*imagechainpointer;imagechainpointer = &(*imagechainpointer)->imagechain);
855
856                 image = Mem_Alloc(texturemempool, sizeof(gltextureimage_t));
857                 if (image == NULL)
858                         Sys_Error("R_FindImageForTexture: ran out of memory\n");
859                 image->type = GLIMAGETYPE_TILE;
860                 image->blockallocation = NULL;
861
862                 // calculate final size
863                 if (r_max_size.integer > realmaxsize)
864                         Cvar_SetValue("r_max_size", realmaxsize);
865                 for (image->width = 1;image->width < glt->width;image->width <<= 1);
866                 for (image->height = 1;image->height < glt->height;image->height <<= 1);
867                 for (image->depth = 1;image->depth < glt->depth;image->depth <<= 1);
868                 for (image->width >>= r_picmip.integer;image->width > r_max_size.integer;image->width >>= 1);
869                 for (image->height >>= r_picmip.integer;image->height > r_max_size.integer;image->height >>= 1);
870                 for (image->depth >>= r_picmip.integer;image->depth > r_max_size.integer;image->depth >>= 1);
871                 if (image->width < 1) image->width = 1;
872                 if (image->height < 1) image->height = 1;
873                 if (image->depth < 1) image->depth = 1;
874         }
875         image->texturetype = glt->texturetype;
876         image->glinternalformat = texinfo->glinternalformat;
877         image->glformat = texinfo->glformat;
878         image->flags = (glt->flags & (TEXF_MIPMAP | TEXF_ALPHA | TEXF_CLAMP)) | GLTEXF_UPLOAD;
879         image->bytesperpixel = texinfo->internalbytesperpixel;
880         image->sides = image->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
881         // get a texture number to use
882         qglGenTextures(1, &image->texnum);
883         *imagechainpointer = image;
884         image->texturecount++;
885
886         glt->x = x;
887         glt->y = y;
888         glt->y = z;
889         glt->image = image;
890 }
891
892 // note: R_FindImageForTexture must be called before this
893 static void R_UploadTexture (gltexture_t *glt)
894 {
895         if (!(glt->flags & GLTEXF_UPLOAD))
896                 return;
897
898         R_Upload(glt, glt->inputtexels);
899         if (glt->inputtexels)
900         {
901                 Mem_Free(glt->inputtexels);
902                 glt->inputtexels = NULL;
903                 glt->flags |= GLTEXF_DESTROYED;
904         }
905         else if (glt->flags & GLTEXF_DESTROYED)
906                 Con_Printf("R_UploadTexture: Texture %s already uploaded and destroyed.  Can not upload original image again.  Uploaded blank texture.\n", glt->identifier);
907 }
908
909 static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, char *identifier, int width, int height, int depth, int sides, int flags, int textype, int texturetype, qbyte *data)
910 {
911         int i, size;
912         gltexture_t *glt;
913         gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
914         textypeinfo_t *texinfo;
915
916         if (cls.state == ca_dedicated)
917                 return NULL;
918
919         if (flags & TEXF_FRAGMENT && texturetype != GLTEXTURETYPE_2D)
920                 Sys_Error("R_LoadTexture: only 2D fragment textures implemented\n");
921         if (texturetype == GLTEXTURETYPE_CUBEMAP && !gl_texturecubemap)
922                 Sys_Error("R_LoadTexture: cubemap texture not supported by driver\n");
923         if (texturetype == GLTEXTURETYPE_3D && !gl_texture3d)
924                 Sys_Error("R_LoadTexture: 3d texture not supported by driver\n");
925
926         /*
927         glt = R_FindTexture (pool, identifier);
928         if (glt)
929         {
930                 Con_Printf("R_LoadTexture: replacing existing texture %s\n", identifier);
931                 R_FreeTexture((rtexture_t *)glt);
932         }
933         */
934
935         texinfo = R_GetTexTypeInfo(textype, flags);
936         size = width * height * depth * sides * texinfo->inputbytesperpixel;
937
938         // clear the alpha flag if the texture has no transparent pixels
939         switch(textype)
940         {
941         case TEXTYPE_QPALETTE:
942                 if (flags & TEXF_ALPHA)
943                 {
944                         flags &= ~TEXF_ALPHA;
945                         if (data)
946                         {
947                                 for (i = 0;i < size;i++)
948                                 {
949                                         if (data[i] == 255)
950                                         {
951                                                 flags |= TEXF_ALPHA;
952                                                 break;
953                                         }
954                                 }
955                         }
956                 }
957                 break;
958         case TEXTYPE_RGB:
959                 if (flags & TEXF_ALPHA)
960                         Host_Error("R_LoadTexture: RGB has no alpha, don't specify TEXF_ALPHA\n");
961                 break;
962         case TEXTYPE_RGBA:
963                 if (flags & TEXF_ALPHA)
964                 {
965                         flags &= ~TEXF_ALPHA;
966                         if (data)
967                         {
968                                 for (i = 3;i < size;i += 4)
969                                 {
970                                         if (data[i] < 255)
971                                         {
972                                                 flags |= TEXF_ALPHA;
973                                                 break;
974                                         }
975                                 }
976                         }
977                 }
978                 break;
979         default:
980                 Host_Error("R_LoadTexture: unknown texture type\n");
981         }
982
983         glt = Mem_Alloc(texturemempool, sizeof(gltexture_t));
984         if (identifier)
985         {
986                 glt->identifier = Mem_Alloc(texturemempool, strlen(identifier)+1);
987                 strcpy (glt->identifier, identifier);
988         }
989         else
990                 glt->identifier = NULL;
991         glt->pool = pool;
992         glt->chain = pool->gltchain;
993         pool->gltchain = glt;
994         glt->width = width;
995         glt->height = height;
996         glt->depth = depth;
997         glt->flags = flags | GLTEXF_UPLOAD;
998         glt->textype = texinfo;
999         glt->texturetype = texturetype;
1000         glt->inputdatasize = size;
1001
1002         if (data)
1003         {
1004                 glt->inputtexels = Mem_Alloc(texturedatamempool, size);
1005                 if (glt->inputtexels == NULL)
1006                         Sys_Error("R_SetupTexture: out of memory\n");
1007                 memcpy(glt->inputtexels, data, size);
1008         }
1009         else
1010                 glt->inputtexels = NULL;
1011
1012         R_FindImageForTexture(glt);
1013         R_PrecacheTexture(glt);
1014
1015         return (rtexture_t *)glt;
1016 }
1017
1018 rtexture_t *R_LoadTexture(rtexturepool_t *rtexturepool, char *identifier, int width, int height, qbyte *data, int textype, int flags)
1019 {
1020         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_2D, data);
1021 }
1022
1023 rtexture_t *R_LoadTexture1D(rtexturepool_t *rtexturepool, char *identifier, int width, qbyte *data, int textype, int flags)
1024 {
1025         return R_SetupTexture(rtexturepool, identifier, width, 1, 1, 1, flags, textype, GLTEXTURETYPE_1D, data);
1026 }
1027
1028 rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, char *identifier, int width, int height, qbyte *data, int textype, int flags)
1029 {
1030         return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, textype, GLTEXTURETYPE_2D, data);
1031 }
1032
1033 rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, char *identifier, int width, int height, int depth, qbyte *data, int textype, int flags)
1034 {
1035         return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, textype, GLTEXTURETYPE_3D, data);
1036 }
1037
1038 rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, char *identifier, int width, qbyte *data, int textype, int flags)
1039 {
1040         return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data);
1041 }
1042
1043 int R_TextureHasAlpha(rtexture_t *rt)
1044 {
1045         return rt ? (((gltexture_t *)rt)->flags & TEXF_ALPHA) != 0 : false;
1046 }
1047
1048 int R_TextureWidth(rtexture_t *rt)
1049 {
1050         return rt ? ((gltexture_t *)rt)->width : 0;
1051 }
1052
1053 int R_TextureHeight(rtexture_t *rt)
1054 {
1055         return rt ? ((gltexture_t *)rt)->height : 0;
1056 }
1057
1058 void R_FragmentLocation3D(rtexture_t *rt, int *x, int *y, int *z, float *fx1, float *fy1, float *fz1, float *fx2, float *fy2, float *fz2)
1059 {
1060         gltexture_t *glt;
1061         float iwidth, iheight, idepth;
1062         if (cls.state == ca_dedicated)
1063         {
1064                 if (x)
1065                         *x = 0;
1066                 if (y)
1067                         *y = 0;
1068                 if (z)
1069                         *z = 0;
1070                 if (fx1 || fy1 || fx2 || fy2)
1071                 {
1072                         if (fx1)
1073                                 *fx1 = 0;
1074                         if (fy1)
1075                                 *fy1 = 0;
1076                         if (fz1)
1077                                 *fz1 = 0;
1078                         if (fx2)
1079                                 *fx2 = 1;
1080                         if (fy2)
1081                                 *fy2 = 1;
1082                         if (fz2)
1083                                 *fz2 = 1;
1084                 }
1085                 return;
1086         }
1087         if (!rt)
1088                 Host_Error("R_FragmentLocation: no texture supplied\n");
1089         glt = (gltexture_t *)rt;
1090         if (glt->flags & TEXF_FRAGMENT)
1091         {
1092                 if (x)
1093                         *x = glt->x;
1094                 if (y)
1095                         *y = glt->y;
1096                 if (fx1 || fy1 || fx2 || fy2)
1097                 {
1098                         iwidth = 1.0f / glt->image->width;
1099                         iheight = 1.0f / glt->image->height;
1100                         idepth = 1.0f / glt->image->depth;
1101                         if (fx1)
1102                                 *fx1 = glt->x * iwidth;
1103                         if (fy1)
1104                                 *fy1 = glt->y * iheight;
1105                         if (fz1)
1106                                 *fz1 = glt->z * idepth;
1107                         if (fx2)
1108                                 *fx2 = (glt->x + glt->width) * iwidth;
1109                         if (fy2)
1110                                 *fy2 = (glt->y + glt->height) * iheight;
1111                         if (fz2)
1112                                 *fz2 = (glt->z + glt->depth) * idepth;
1113                 }
1114         }
1115         else
1116         {
1117                 if (x)
1118                         *x = 0;
1119                 if (y)
1120                         *y = 0;
1121                 if (z)
1122                         *z = 0;
1123                 if (fx1 || fy1 || fx2 || fy2)
1124                 {
1125                         if (fx1)
1126                                 *fx1 = 0;
1127                         if (fy1)
1128                                 *fy1 = 0;
1129                         if (fz1)
1130                                 *fz1 = 0;
1131                         if (fx2)
1132                                 *fx2 = 1;
1133                         if (fy2)
1134                                 *fy2 = 1;
1135                         if (fz2)
1136                                 *fz2 = 1;
1137                 }
1138         }
1139 }
1140
1141 void R_FragmentLocation(rtexture_t *rt, int *x, int *y, float *fx1, float *fy1, float *fx2, float *fy2)
1142 {
1143         R_FragmentLocation3D(rt, x, y, NULL, fx1, fy1, NULL, fx2, fy2, NULL);
1144 }
1145
1146 int R_CompatibleFragmentWidth(int width, int textype, int flags)
1147 {
1148         return width;
1149 }
1150
1151 void R_UpdateTexture(rtexture_t *rt, qbyte *data)
1152 {
1153         gltexture_t *glt;
1154         if (rt == NULL)
1155                 Host_Error("R_UpdateTexture: no texture supplied\n");
1156         if (data == NULL)
1157                 Host_Error("R_UpdateTexture: no data supplied\n");
1158         glt = (gltexture_t *)rt;
1159
1160         // if it has not been uploaded yet, update the data that will be used when it is
1161         if (glt->inputtexels)
1162                 memcpy(glt->inputtexels, data, glt->inputdatasize);
1163         else
1164                 R_Upload(glt, data);
1165 }
1166