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