DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
gl_textures.c
Go to the documentation of this file.
1/*
2Copyright (C) 2000-2020 DarkPlaces contributors
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21
22#include "quakedef.h"
23#include "image.h"
24#include "jpeg.h"
25#include "image_png.h"
26
27cvar_t gl_max_size = {CF_CLIENT | CF_ARCHIVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"};
28cvar_t gl_max_lightmapsize = {CF_CLIENT | CF_ARCHIVE, "gl_max_lightmapsize", "512", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"};
29cvar_t gl_picmip = {CF_CLIENT | CF_ARCHIVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"};
30cvar_t gl_picmip_world = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"};
31cvar_t r_picmipworld = {CF_CLIENT | CF_ARCHIVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"};
32cvar_t gl_picmip_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"};
33cvar_t r_picmipsprites = {CF_CLIENT | CF_ARCHIVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"};
34cvar_t gl_picmip_other = {CF_CLIENT | CF_ARCHIVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"};
35cvar_t r_lerpimages = {CF_CLIENT | CF_ARCHIVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"};
36cvar_t gl_texture_anisotropy = {CF_CLIENT | CF_ARCHIVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"};
37cvar_t gl_texturecompression = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"};
38cvar_t gl_texturecompression_color = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"};
39cvar_t gl_texturecompression_normal = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"};
40cvar_t gl_texturecompression_gloss = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"};
41cvar_t gl_texturecompression_glow = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"};
42cvar_t gl_texturecompression_2d = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"};
43cvar_t gl_texturecompression_q3bsplightmaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"};
44cvar_t gl_texturecompression_q3bspdeluxemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"};
45cvar_t gl_texturecompression_sky = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
46cvar_t gl_texturecompression_lightcubemaps = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
47cvar_t gl_texturecompression_reflectmask = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
48cvar_t gl_texturecompression_sprites = {CF_CLIENT | CF_ARCHIVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
49cvar_t r_texture_dds_load_alphamode = {CF_CLIENT, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
50cvar_t r_texture_dds_load_logfailure = {CF_CLIENT, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"};
51cvar_t r_texture_dds_swdecode = {CF_CLIENT, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
52
56
57
60
61// note: this must not conflict with TEXF_ flags in r_textures.h
62// bitmask for mismatch checking
63#define GLTEXF_IMPORTANTBITS (0)
64// dynamic texture (treat texnum == 0 differently)
65#define GLTEXF_DYNAMIC 0x00080000
66
79
80#ifdef USE_GLES2
81
82// we use these internally even if we never deliver such data to the driver
83#define GL_BGR 0x80E0
84#define GL_BGRA 0x80E1
85
86// framebuffer texture formats
87// GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
95static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB565 , GL_RGBA , GL_UNSIGNED_SHORT_5_6_5};
97static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGBA32F , GL_RGBA , GL_FLOAT};
98
99// image formats:
100static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE };
101static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
102static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
103static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
104static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE };
105static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
106static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE };
107#ifdef __ANDROID__
108static textypeinfo_t textype_etc1 = {"etc1", TEXTYPE_ETC1 , 1, 3, 0.5f, GL_ETC1_RGB8_OES , 0 , 0 };
109#endif
110#else
111// framebuffer texture formats
122
123// image formats:
153#endif
154
163
165#ifdef GL_TEXTURE_WRAP_R
167#endif
177
178typedef struct gltexture_s
179{
180 // this portion of the struct is exposed to the R_GetTexture macro for
181 // speed reasons, must be identical in rtexture_t!
182 int texnum; // GL texture slot number
183 int renderbuffernum; // GL renderbuffer slot number
184 qbool dirty; // indicates that R_RealGetTexture should be called
185 qbool glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT
186 int gltexturetypeenum; // used by R_Mesh_TexBind
187
188 // dynamic texture stuff [11/22/2007 Black]
191 // --- [11/22/2007 Black]
192
193 // stores backup copy of texture for deferred texture updates (R_UpdateTexture when combine = true)
194 unsigned char *bufferpixels;
195 int modified_mins[3], modified_maxs[3];
197
198 // pointer to texturepool (check this to see if the texture is allocated)
199 struct gltexturepool_s *pool;
200 // pointer to next texture in texturepool chain
201 struct gltexture_s *chain;
202 // name of the texture (this might be removed someday), no duplicates
203 char identifier[MAX_QPATH + 32];
204 // original data size in *inputtexels
205 int inputwidth, inputheight, inputdepth;
206 // copy of the original texture(s) supplied to the upload function, for
207 // delayed uploads (non-precached)
208 unsigned char *inputtexels;
209 // original data size in *inputtexels
211 // flags supplied to the LoadTexture function
212 // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags
213 int flags;
214 // picmip level
216 // pointer to one of the textype_ structs
218 // one of the GLTEXTURETYPE_ values
220 // palette if the texture is TEXTYPE_PALETTE
221 const unsigned int *palette;
222 // actual stored texture size after gl_picmip and gl_max_size are applied
223 int tilewidth, tileheight, tiledepth;
224 // 1 or 6 depending on texturetype
225 int sides;
226 // how many mipmap levels in this texture
228 // bytes per pixel
230 // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
232 // 3 or 4
234 // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
236}
238
239#define TEXTUREPOOL_SENTINEL 0xC0DEDBAD
240
241typedef struct gltexturepool_s
242{
243 unsigned int sentinel;
244 struct gltexture_s *gltchain;
245 struct gltexturepool_s *next;
246}
248
250
251static unsigned char *resizebuffer = NULL, *colorconvertbuffer;
252static int resizebuffersize = 0;
253static const unsigned char *texturebuffer;
254
256{
257 switch(textype)
258 {
259#ifdef USE_GLES2
263#ifdef __ANDROID__
264 case TEXTYPE_ETC1: return &textype_etc1;
265#endif
266 case TEXTYPE_ALPHA: return &textype_alpha;
277#else
278 case TEXTYPE_DXT1: return &textype_dxt1;
279 case TEXTYPE_DXT1A: return &textype_dxt1a;
280 case TEXTYPE_DXT3: return &textype_dxt3;
281 case TEXTYPE_DXT5: return &textype_dxt5;
285 case TEXTYPE_ALPHA: return &textype_alpha;
303#endif
304 default:
305 Host_Error("R_GetTexTypeInfo: unknown texture format %i with flags %x", (int)textype, flags);
306 break;
307 }
308 return NULL;
309}
310
311// dynamic texture code [11/22/2007 Black]
313 gltexture_t *glt = (gltexture_t*) rt;
314 if( !glt ) {
315 return;
316 }
317
318 // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!)
319 if (glt->flags & GLTEXF_DYNAMIC)
320 {
321 // mark it as dirty, so R_RealGetTexture gets called
322 glt->dirty = true;
323 }
324}
325
326void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) {
327 gltexture_t *glt = (gltexture_t*) rt;
328 if( !glt ) {
329 return;
330 }
331
332 glt->flags |= GLTEXF_DYNAMIC;
333 glt->updatecallback = updatecallback;
335}
336
338 glt->dirty = false;
339 if( glt->updatecallback ) {
340 glt->updatecallback( (rtexture_t*) glt, glt->updatecallback_data );
341 }
342}
343
345{
346 if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) {
347 R_FreeTexture(rt);
348 }
349}
350
352{
353 gltexture_t *glt, **gltpointer;
354
355 glt = (gltexture_t *)rt;
356 if (glt == NULL)
357 Host_Error("R_FreeTexture: texture == NULL");
358
359 for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain);
360 if (*gltpointer == glt)
361 *gltpointer = glt->chain;
362 else
363 Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier);
364
366
367 switch(vid.renderpath)
368 {
369 case RENDERPATH_GL32:
370 case RENDERPATH_GLES2:
371 if (glt->texnum)
372 {
374 qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
375 }
376 if (glt->renderbuffernum)
377 {
379 qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
380 }
381 break;
382 }
383
384 if (glt->inputtexels)
385 Mem_Free(glt->inputtexels);
387}
388
390{
391 gltexturepool_t *pool;
392 if (texturemempool == NULL)
393 return NULL;
395 if (pool == NULL)
396 return NULL;
397 pool->next = gltexturepoolchain;
398 gltexturepoolchain = pool;
400 return (rtexturepool_t *)pool;
401}
402
404{
405 gltexturepool_t *pool, **poolpointer;
406 if (rtexturepool == NULL)
407 return;
408 if (*rtexturepool == NULL)
409 return;
410 pool = (gltexturepool_t *)(*rtexturepool);
411 *rtexturepool = NULL;
412 if (pool->sentinel != TEXTUREPOOL_SENTINEL)
413 Host_Error("R_FreeTexturePool: pool already freed");
414 for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next);
415 if (*poolpointer == pool)
416 *poolpointer = pool->next;
417 else
418 Host_Error("R_FreeTexturePool: pool not linked");
419 while (pool->gltchain)
421 Mem_Free(pool);
422}
423
424
425typedef struct glmode_s
426{
427 const char *name;
428 int minification, magnification;
429}
431
432static glmode_t modes[6] =
433{
434 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
435 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
436 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
437 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
438 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
439 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
440};
441
443{
444 int i;
445 GLint oldbindtexnum;
446 gltexture_t *glt;
447 gltexturepool_t *pool;
448
449 if (Cmd_Argc(cmd) == 1)
450 {
451 Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not ");
452 for (i = 0;i < 6;i++)
453 {
454 if (gl_filter_min == modes[i].minification)
455 {
456 Con_Printf("%s\n", modes[i].name);
457 return;
458 }
459 }
460 Con_Print("current filter is unknown???\n");
461 return;
462 }
463
464 for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++)
465 if (!strcasecmp (modes[i].name, Cmd_Argv(cmd, 1) ) )
466 break;
467 if (i == 6)
468 {
469 Con_Print("bad filter name\n");
470 return;
471 }
472
475 gl_filter_force = ((Cmd_Argc(cmd) > 2) && !strcasecmp(Cmd_Argv(cmd, 2), "force"));
476
477 switch(vid.renderpath)
478 {
479 case RENDERPATH_GL32:
480 case RENDERPATH_GLES2:
481 // change all the existing mipmap texture objects
482 // FIXME: force renderer(/client/something?) restart instead?
485 for (pool = gltexturepoolchain;pool;pool = pool->next)
486 {
487 for (glt = pool->gltchain;glt;glt = glt->chain)
488 {
489 // only update already uploaded images
490 if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
491 {
492 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
493 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
494 if (glt->flags & TEXF_MIPMAP)
495 {
497 }
498 else
499 {
501 }
503 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
504 }
505 }
506 }
507 break;
508 }
509}
510
511static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels)
512{
513 int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1;
514
515 switch (texturetype)
516 {
517 default:
518 case GLTEXTURETYPE_2D:
519 maxsize = vid.maxtexturesize_2d;
520 if (flags & TEXF_PICMIP)
521 {
522 maxsize = bound(1, gl_max_size.integer, maxsize);
523 picmip = miplevel;
524 }
525 break;
526 case GLTEXTURETYPE_3D:
527 maxsize = vid.maxtexturesize_3d;
528 break;
530 maxsize = vid.maxtexturesize_cubemap;
531 break;
532 }
533
534 width2 = min(inwidth >> picmip, maxsize);
535 height2 = min(inheight >> picmip, maxsize);
536 depth2 = min(indepth >> picmip, maxsize);
537
538 miplevels = 1;
539 if (flags & TEXF_MIPMAP)
540 {
541 int extent = max(width2, max(height2, depth2));
542 while(extent >>= 1)
543 miplevels++;
544 }
545
546 if (outwidth)
547 *outwidth = max(1, width2);
548 if (outheight)
549 *outheight = max(1, height2);
550 if (outdepth)
551 *outdepth = max(1, depth2);
552 if (outmiplevels)
553 *outmiplevels = miplevels;
554}
555
556
558{
559 int width2, height2, depth2, size;
560
561 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL);
562
563 size = width2 * height2 * depth2;
564
565 if (glt->flags & TEXF_MIPMAP)
566 {
567 while (width2 > 1 || height2 > 1 || depth2 > 1)
568 {
569 if (width2 > 1)
570 width2 >>= 1;
571 if (height2 > 1)
572 height2 >>= 1;
573 if (depth2 > 1)
574 depth2 >>= 1;
575 size += width2 * height2 * depth2;
576 }
577 }
578
579 return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides;
580}
581
582void R_TextureStats_Print(qbool printeach, qbool printpool, qbool printtotal)
583{
584 int glsize;
585 int isloaded;
586 int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0;
587 int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0;
588 gltexture_t *glt;
589 gltexturepool_t *pool;
590 if (printeach)
591 Con_Print("glsize input loaded mip alpha name\n");
592 for (pool = gltexturepoolchain;pool;pool = pool->next)
593 {
594 pooltotal = 0;
595 pooltotalt = 0;
596 pooltotalp = 0;
597 poolloaded = 0;
598 poolloadedt = 0;
599 poolloadedp = 0;
600 for (glt = pool->gltchain;glt;glt = glt->chain)
601 {
602 glsize = R_CalcTexelDataSize(glt);
603 isloaded = glt->texnum != 0 || glt->renderbuffernum != 0;
604 pooltotal++;
605 pooltotalt += glsize;
606 pooltotalp += glt->inputdatasize;
607 if (isloaded)
608 {
609 poolloaded++;
610 poolloadedt += glsize;
611 poolloadedp += glt->inputdatasize;
612 }
613 if (printeach)
614 Con_Printf("%c%4i%c%c%4i%c %-24s %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->textype->name, isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier);
615 }
616 if (printpool)
617 Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", (void *)pool, pooltotal, pooltotalt / 1048576.0, pooltotalp / 1048576.0, poolloaded, poolloadedt / 1048576.0, poolloadedp / 1048576.0, pooltotal - poolloaded, (pooltotalt - poolloadedt) / 1048576.0, (pooltotalp - poolloadedp) / 1048576.0);
618 sumtotal += pooltotal;
619 sumtotalt += pooltotalt;
620 sumtotalp += pooltotalp;
621 sumloaded += poolloaded;
622 sumloadedt += poolloadedt;
623 sumloadedp += poolloadedp;
624 }
625 if (printtotal)
626 Con_Printf("textures total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", sumtotal, sumtotalt / 1048576.0, sumtotalp / 1048576.0, sumloaded, sumloadedt / 1048576.0, sumloadedp / 1048576.0, sumtotal - sumloaded, (sumtotalt - sumloadedt) / 1048576.0, (sumtotalp - sumloadedp) / 1048576.0);
627}
628
630{
631 R_TextureStats_Print(true, true, true);
632}
633
634static void r_textures_start(void)
635{
636 switch(vid.renderpath)
637 {
638 case RENDERPATH_GL32:
639 case RENDERPATH_GLES2:
640 // LadyHavoc: allow any alignment
642 qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR
643 qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR
644 break;
645 }
646
647 texturemempool = Mem_AllocPool("texture management", 0, NULL);
649
650 // Disable JPEG screenshots if the DLL isn't loaded
651 if (! JPEG_OpenLibrary ())
653 if (! PNG_OpenLibrary ())
655}
656
676
677static void r_textures_newmap(void)
678{
679}
680
681static void r_textures_devicelost(void)
682{
683 int i, endindex;
684 gltexture_t *glt;
686 for (i = 0;i < endindex;i++)
687 {
689 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
690 continue;
691 switch(vid.renderpath)
692 {
693 case RENDERPATH_GL32:
694 case RENDERPATH_GLES2:
695 break;
696 }
697 }
698}
699
701{
702 int i, endindex;
703 gltexture_t *glt;
705 for (i = 0;i < endindex;i++)
706 {
708 if (!glt || !(glt->flags & TEXF_RENDERTARGET))
709 continue;
710 switch(vid.renderpath)
711 {
712 case RENDERPATH_GL32:
713 case RENDERPATH_GLES2:
714 break;
715 }
716 }
717}
718
719
721{
722 Cmd_AddCommand(CF_CLIENT, "gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate");
723 Cmd_AddCommand(CF_CLIENT, "r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics");
749
751}
752
754{
755#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
756 static int old_aniso = 0;
757 static qbool first_time_aniso = true;
758#endif
759
760 // could do procedural texture animation here, if we keep track of which
761 // textures were accessed this frame...
762
763 // free the resize buffers
765 if (resizebuffer)
766 {
769 }
771 {
774 }
775
776#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
777 if (old_aniso != gl_texture_anisotropy.integer)
778 {
779 gltexture_t *glt;
780 gltexturepool_t *pool;
781 GLint oldbindtexnum;
782
784
786
787 switch(vid.renderpath)
788 {
789 case RENDERPATH_GL32:
790 case RENDERPATH_GLES2:
791 // ignore the first difference, any textures loaded by now probably had the same aniso value
792 if (first_time_aniso)
793 {
794 first_time_aniso = false;
795 break;
796 }
799 for (pool = gltexturepoolchain;pool;pool = pool->next)
800 {
801 for (glt = pool->gltchain;glt;glt = glt->chain)
802 {
803 // only update already uploaded images
804 if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP)
805 {
806 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
807
808 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
810
811 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
812 }
813 }
814 }
815 break;
816 }
817 }
818#endif
819}
820
822{
824 {
826 if (resizebuffer)
833 Host_Error("R_Upload: out of memory");
834 }
835}
836
837static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
838{
839 int textureenum = gltexturetypeenums[texturetype];
840 int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT;
841
843
844#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
846 {
848 if (gl_texture_anisotropy.integer != aniso)
850 qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR
851 }
852#endif
853 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR
854 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR
855#ifdef GL_TEXTURE_WRAP_R
856 if (gltexturetypedimensions[texturetype] >= 3)
857 {
858 qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR
859 }
860#endif
861
864 {
865 if (flags & TEXF_MIPMAP)
866 {
867 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR
868 }
869 else
870 {
871 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR
872 }
873 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR
874 }
876 {
877 if (flags & TEXF_MIPMAP)
878 {
880 {
881 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR
882 }
883 else
884 {
885 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR
886 }
887 }
888 else
889 {
890 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR
891 }
892 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR
893 }
894 else
895 {
896 if (flags & TEXF_MIPMAP)
897 {
898 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR
899 }
900 else
901 {
902 qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR
903 }
904 qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
905 }
906
907#ifndef USE_GLES2
908 switch(textype)
909 {
912 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);CHECKGLERROR
913 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
914 break;
917 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE, GL_NONE);CHECKGLERROR
918 qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);CHECKGLERROR
919 break;
920 default:
921 break;
922 }
923#endif
924
926}
927
928static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
929{
930 if (data == NULL)
931 Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier);
932
933 if (glt->texturetype != GLTEXTURETYPE_2D)
934 Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier);
935
936 if (glt->textype->textype == TEXTYPE_PALETTE)
937 Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier);
938
939 if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP))
940 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier);
941
942 if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1)
943 Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier);
944
945 // update a portion of the image
946
947 switch(vid.renderpath)
948 {
949 case RENDERPATH_GL32:
950 case RENDERPATH_GLES2:
951 {
952 int oldbindtexnum;
954 // we need to restore the texture binding after finishing the upload
956 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
957 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
958 qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR
959 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
960 }
961 break;
962 }
963}
964
965static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
966{
967 int i, mip = 0, width, height, depth;
968 GLint oldbindtexnum = 0;
969 const unsigned char *prevbuffer;
970 prevbuffer = data;
971
972 // error out if a stretch is needed on special texture types
973 if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth))
974 Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier);
975
976 // when picmip or maxsize is applied, we scale up to a power of 2 multiple
977 // of the target size and then use the mipmap reduction function to get
978 // high quality supersampled results
979 for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1);
980 for (height = glt->tileheight;height < glt->inputheight;height <<= 1);
981 for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1);
982
983 if (prevbuffer == NULL)
984 {
985 width = glt->tilewidth;
986 height = glt->tileheight;
987 depth = glt->tiledepth;
988// R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel);
989// memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel);
990// prevbuffer = resizebuffer;
991 }
992 else
993 {
994 if (glt->textype->textype == TEXTYPE_PALETTE)
995 {
996 // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code
998 Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette);
999 prevbuffer = colorconvertbuffer;
1000 }
1001 if (glt->flags & TEXF_RGBMULTIPLYBYALPHA)
1002 {
1003 // multiply RGB channels by A channel before uploading
1004 int alpha;
1006 for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4)
1007 {
1008 alpha = prevbuffer[i+3];
1009 colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8;
1010 colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8;
1011 colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8;
1013 }
1014 prevbuffer = colorconvertbuffer;
1015 }
1016 // scale up to a power of 2 size (if appropriate)
1017 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1018 {
1021 prevbuffer = resizebuffer;
1022 }
1023 // apply mipmap reduction algorithm to get down to picmip/max_size
1024 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1025 {
1027 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1028 prevbuffer = resizebuffer;
1029 }
1030 }
1031
1032 // do the appropriate upload type...
1033 switch(vid.renderpath)
1034 {
1035 case RENDERPATH_GL32:
1036 case RENDERPATH_GLES2:
1037 if (glt->texnum) // not renderbuffers
1038 {
1040
1041 // we need to restore the texture binding after finishing the upload
1043 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1044 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1045
1046#ifndef USE_GLES2
1049 else
1052#endif
1053 switch(glt->texturetype)
1054 {
1055 case GLTEXTURETYPE_2D:
1056 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1057 if (glt->flags & TEXF_MIPMAP)
1058 {
1059 while (width > 1 || height > 1 || depth > 1)
1060 {
1062 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1063 prevbuffer = resizebuffer;
1064 qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1065 }
1066 }
1067 break;
1068 case GLTEXTURETYPE_3D:
1069#ifndef USE_GLES2
1070 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1071 if (glt->flags & TEXF_MIPMAP)
1072 {
1073 while (width > 1 || height > 1 || depth > 1)
1074 {
1076 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1077 prevbuffer = resizebuffer;
1078 qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1079 }
1080 }
1081#endif
1082 break;
1084 // convert and upload each side in turn,
1085 // from a continuous block of input texels
1086 texturebuffer = (unsigned char *)prevbuffer;
1087 for (i = 0;i < 6;i++)
1088 {
1089 prevbuffer = texturebuffer;
1091 if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth)
1092 {
1095 prevbuffer = resizebuffer;
1096 }
1097 // picmip/max_size
1098 while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth)
1099 {
1101 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
1102 prevbuffer = resizebuffer;
1103 }
1104 mip = 0;
1105 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1106 if (glt->flags & TEXF_MIPMAP)
1107 {
1108 while (width > 1 || height > 1 || depth > 1)
1109 {
1111 Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
1112 prevbuffer = resizebuffer;
1113 qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
1114 }
1115 }
1116 }
1117 break;
1118 }
1120 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1121 }
1122 break;
1123 }
1124}
1125
1126static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int miplevel, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
1127{
1128 int i, size;
1129 gltexture_t *glt;
1130 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1131 textypeinfo_t *texinfo, *texinfo2;
1132 unsigned char *temppixels = NULL;
1133 qbool swaprb;
1134
1135 if (cls.state == ca_dedicated)
1136 return NULL;
1137
1138 // see if we need to swap red and blue (BGRA <-> RGBA conversion)
1139 if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA)
1140 {
1141 int numpixels = width * height * depth * sides;
1142 size = numpixels * 4;
1143 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1144 if (data)
1145 {
1146 const unsigned char *p;
1147 unsigned char *o = temppixels;
1148 for (i = 0;i < numpixels;i++, o += 4)
1149 {
1150 p = (const unsigned char *)palette + 4*data[i];
1151 o[0] = p[2];
1152 o[1] = p[1];
1153 o[2] = p[0];
1154 o[3] = p[3];
1155 }
1156 }
1157 data = temppixels;
1158 textype = TEXTYPE_RGBA;
1159 }
1160 swaprb = false;
1161 switch(textype)
1162 {
1163 case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break;
1164 case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break;
1165 case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break;
1166 case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break;
1167 default: break;
1168 }
1169 if (swaprb)
1170 {
1171 // swap bytes
1172 static int rgbaswapindices[4] = {2, 1, 0, 3};
1173 size = width * height * depth * sides * 4;
1174 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1175 if (data)
1176 Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
1177 data = temppixels;
1178 }
1179
1180 // if sRGB texture formats are not supported, convert input to linear and upload as normal types
1182 {
1183 qbool convertsRGB = false;
1184 switch(textype)
1185 {
1186 case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break;
1187 case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break;
1188 case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break;
1189 case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break;
1190 case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break;
1191 case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break;
1192 case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break;
1193 default:
1194 break;
1195 }
1196 if (convertsRGB && data)
1197 {
1198 size = width * height * depth * sides * 4;
1199 if (!temppixels)
1200 {
1201 temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
1202 memcpy(temppixels, data, size);
1203 data = temppixels;
1204 }
1205 Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
1206 }
1207 }
1208
1209 texinfo = R_GetTexTypeInfo(textype, flags);
1210 size = width * height * depth * sides * texinfo->inputbytesperpixel;
1211 if (size < 1)
1212 {
1213 Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size);
1214 return NULL;
1215 }
1216
1217 // clear the alpha flag if the texture has no transparent pixels
1218 switch(textype)
1219 {
1220 case TEXTYPE_PALETTE:
1222 if (flags & TEXF_ALPHA)
1223 {
1224 flags &= ~TEXF_ALPHA;
1225 if (data)
1226 {
1227 for (i = 0;i < size;i++)
1228 {
1229 if (((unsigned char *)&palette[data[i]])[3] < 255)
1230 {
1231 flags |= TEXF_ALPHA;
1232 break;
1233 }
1234 }
1235 }
1236 }
1237 break;
1238 case TEXTYPE_RGBA:
1239 case TEXTYPE_BGRA:
1240 case TEXTYPE_SRGB_RGBA:
1241 case TEXTYPE_SRGB_BGRA:
1242 if (flags & TEXF_ALPHA)
1243 {
1244 flags &= ~TEXF_ALPHA;
1245 if (data)
1246 {
1247 for (i = 3;i < size;i += 4)
1248 {
1249 if (data[i] < 255)
1250 {
1251 flags |= TEXF_ALPHA;
1252 break;
1253 }
1254 }
1255 }
1256 }
1257 break;
1262 break;
1263 case TEXTYPE_DXT1:
1264 case TEXTYPE_SRGB_DXT1:
1265 break;
1266 case TEXTYPE_DXT1A:
1267 case TEXTYPE_SRGB_DXT1A:
1268 case TEXTYPE_DXT3:
1269 case TEXTYPE_SRGB_DXT3:
1270 case TEXTYPE_DXT5:
1271 case TEXTYPE_SRGB_DXT5:
1272 flags |= TEXF_ALPHA;
1273 break;
1274 case TEXTYPE_ALPHA:
1275 flags |= TEXF_ALPHA;
1276 break;
1280 flags |= TEXF_ALPHA;
1281 break;
1282 default:
1283 Sys_Error("R_LoadTexture: unknown texture type");
1284 }
1285
1286 texinfo2 = R_GetTexTypeInfo(textype, flags);
1287 if(size == width * height * depth * sides * texinfo->inputbytesperpixel)
1288 texinfo = texinfo2;
1289 else
1290 Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n");
1291
1293 if (identifier)
1294 dp_strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1295 glt->pool = pool;
1296 glt->chain = pool->gltchain;
1297 pool->gltchain = glt;
1298 glt->inputwidth = width;
1299 glt->inputheight = height;
1300 glt->inputdepth = depth;
1301 glt->flags = flags;
1302 glt->miplevel = (miplevel < 0) ? R_PicmipForFlags(flags) : miplevel; // note: if miplevel is -1, we know the texture is in original size and we can picmip it normally
1303 glt->textype = texinfo;
1304 glt->texturetype = texturetype;
1305 glt->inputdatasize = size;
1306 glt->palette = palette;
1307 glt->glinternalformat = texinfo->glinternalformat;
1308 glt->glformat = texinfo->glformat;
1309 glt->gltype = texinfo->gltype;
1310 glt->bytesperpixel = texinfo->internalbytesperpixel;
1311 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1312 glt->texnum = 0;
1313 glt->dirty = false;
1314 glt->glisdepthstencil = false;
1316 // init the dynamic texture attributes, too [11/22/2007 Black]
1317 glt->updatecallback = NULL;
1319
1320 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1321
1322 // upload the texture
1323 // data may be NULL (blank texture for dynamic rendering)
1324 switch(vid.renderpath)
1325 {
1326 case RENDERPATH_GL32:
1327 case RENDERPATH_GLES2:
1329 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1330 break;
1331 }
1332
1334 if (glt->flags & TEXF_ALLOWUPDATES)
1335 glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel);
1336
1337 glt->buffermodified = false;
1340
1341 // free any temporary processing buffer we allocated...
1342 if (temppixels)
1343 Mem_Free(temppixels);
1344
1345 // texture converting and uploading can take a while, so make sure we're sending keepalives
1346 // FIXME: this causes rendering during R_Shadow_DrawLights
1347// CL_KeepaliveMessage(false);
1348
1349 return (rtexture_t *)glt;
1350}
1351
1352rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1353{
1354 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette);
1355}
1356
1357rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1358{
1359 return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette);
1360}
1361
1362rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
1363{
1364 return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
1365}
1366
1367rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qbool filter)
1368{
1369 return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL);
1370}
1371
1372rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
1373{
1374 gltexture_t *glt;
1375 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1376 textypeinfo_t *texinfo;
1377
1378 if (cls.state == ca_dedicated)
1379 return NULL;
1380
1381 texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP);
1382
1384 if (identifier)
1385 dp_strlcpy (glt->identifier, identifier, sizeof(glt->identifier));
1386 glt->pool = pool;
1387 glt->chain = pool->gltchain;
1388 pool->gltchain = glt;
1389 glt->inputwidth = width;
1390 glt->inputheight = height;
1391 glt->inputdepth = 1;
1393 glt->miplevel = 0;
1394 glt->textype = texinfo;
1395 glt->texturetype = textype;
1397 glt->palette = NULL;
1398 glt->glinternalformat = texinfo->glinternalformat;
1399 glt->glformat = texinfo->glformat;
1400 glt->gltype = texinfo->gltype;
1401 glt->bytesperpixel = texinfo->internalbytesperpixel;
1402 glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
1403 glt->texnum = 0;
1404 glt->dirty = false;
1407 // init the dynamic texture attributes, too [11/22/2007 Black]
1408 glt->updatecallback = NULL;
1410
1411 GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels);
1412
1413 // upload the texture
1414 // data may be NULL (blank texture for dynamic rendering)
1415 switch(vid.renderpath)
1416 {
1417 case RENDERPATH_GL32:
1418 case RENDERPATH_GLES2:
1420 qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR
1421 qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR
1422 qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR
1423 // note we can query the renderbuffer for info with glGetRenderbufferParameteriv for GL_WIDTH, GL_HEIGHt, GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_INTERNAL_FORMAT
1424 qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR
1425 break;
1426 }
1427
1428 return (rtexture_t *)glt;
1429}
1430
1431int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qbool skipuncompressed, qbool hasalpha)
1432{
1433#ifdef USE_GLES2
1434 return -1; // unsupported on this platform
1435#else
1436 gltexture_t *glt = (gltexture_t *)rt;
1437 unsigned char *dds;
1438 int oldbindtexnum;
1439 int bytesperpixel = 0;
1440 int bytesperblock = 0;
1441 int dds_flags;
1442 int dds_format_flags;
1443 int dds_caps1;
1444 int dds_caps2;
1445 int ret;
1446 int mip;
1447 int mipmaps;
1448 int mipinfo[16][4];
1449 int ddssize = 128;
1451 const char *ddsfourcc;
1452 if (!rt)
1453 return -1; // NULL pointer
1454 if (!strcmp(gl_version, "2.0.5885 WinXP Release"))
1455 return -2; // broken driver - crashes on reading internal format
1456 if (!qglGetTexLevelParameteriv)
1457 return -2;
1459 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
1460 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
1461 qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
1462 switch(internalformat)
1463 {
1464 default: ddsfourcc = NULL;bytesperpixel = 4;break;
1466 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break;
1467 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break;
1468 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break;
1469 }
1470 // if premultiplied alpha, say so in the DDS file
1472 {
1473 switch(internalformat)
1474 {
1475 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break;
1476 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break;
1477 }
1478 }
1479 if (!bytesperblock && skipuncompressed)
1480 return -3; // skipped
1481 memset(mipinfo, 0, sizeof(mipinfo));
1482 mipinfo[0][0] = glt->tilewidth;
1483 mipinfo[0][1] = glt->tileheight;
1484 mipmaps = 1;
1485 if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1))
1486 {
1487 for (mip = 1;mip < 16;mip++)
1488 {
1489 mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1;
1490 mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1;
1491 if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1)
1492 {
1493 mip++;
1494 break;
1495 }
1496 }
1497 mipmaps = mip;
1498 }
1499 for (mip = 0;mip < mipmaps;mip++)
1500 {
1501 mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel;
1502 mipinfo[mip][3] = ddssize;
1503 ddssize += mipinfo[mip][2];
1504 }
1505 dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize);
1506 if (!dds)
1507 return -4;
1508 dds_caps1 = 0x1000; // DDSCAPS_TEXTURE
1509 dds_caps2 = 0;
1510 if (bytesperblock)
1511 {
1512 dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE
1513 dds_format_flags = 0x4; // DDPF_FOURCC
1514 }
1515 else
1516 {
1517 dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
1518 dds_format_flags = 0x40; // DDPF_RGB
1519 }
1520 if (mipmaps)
1521 {
1522 dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
1523 dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
1524 }
1525 if(hasalpha)
1526 dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
1527 memcpy(dds, "DDS ", 4);
1528 StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so
1529 StoreLittleLong(dds+8, dds_flags);
1530 StoreLittleLong(dds+12, mipinfo[0][1]); // height
1531 StoreLittleLong(dds+16, mipinfo[0][0]); // width
1532 StoreLittleLong(dds+24, 0); // depth
1533 StoreLittleLong(dds+28, mipmaps); // mipmaps
1534 StoreLittleLong(dds+76, 32); // format size
1535 StoreLittleLong(dds+80, dds_format_flags);
1536 StoreLittleLong(dds+108, dds_caps1);
1537 StoreLittleLong(dds+112, dds_caps2);
1538 if (bytesperblock)
1539 {
1540 StoreLittleLong(dds+20, mipinfo[0][2]); // linear size
1541 memcpy(dds+84, ddsfourcc, 4);
1542 for (mip = 0;mip < mipmaps;mip++)
1543 {
1544 qglGetCompressedTexImage(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR
1545 }
1546 }
1547 else
1548 {
1549 StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch
1550 StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel
1551 dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks
1552 for (mip = 0;mip < mipmaps;mip++)
1553 {
1554 qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR
1555 }
1556 }
1557 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1558 ret = FS_WriteFile(filename, dds, ddssize);
1559 Mem_Free(dds);
1560 return ret ? ddssize : -5;
1561#endif
1562}
1563
1564#ifdef __ANDROID__
1565// ELUAN: FIXME: separate this code
1566#include "ktx10/include/ktx.h"
1567#endif
1568
1569rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qbool srgb, int flags, qbool *hasalphaflag, float *avgcolor, int miplevel, qbool optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
1570{
1571 int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height;
1572 //int dds_flags;
1573 textype_t textype;
1574 int bytesperblock, bytesperpixel;
1575 int mipcomplete;
1576 gltexture_t *glt;
1577 gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
1578 textypeinfo_t *texinfo;
1579 int mip, mipwidth, mipheight, mipsize, mipsize_total;
1580 unsigned int c, r, g, b;
1581 GLint oldbindtexnum = 0;
1582 unsigned char *mippixels;
1583 unsigned char *mippixels_start;
1584 unsigned char *ddspixels;
1585 unsigned char *dds;
1586 fs_offset_t ddsfilesize;
1587 unsigned int ddssize;
1588 qbool force_swdecode;
1589#ifdef __ANDROID__
1590 // ELUAN: FIXME: separate this code
1591 char vabuf[1024];
1592 char vabuf2[1024];
1593 int strsize;
1594 KTX_dimensions sizes;
1595#endif
1596
1597 if (cls.state == ca_dedicated)
1598 return NULL;
1599
1600#ifdef __ANDROID__
1601 // ELUAN: FIXME: separate this code
1603 {
1604 Con_DPrintf("KTX texture format is only supported on the GLES2 renderpath\n");
1605 return NULL;
1606 }
1607
1608 // some textures are specified with extensions, so it becomes .tga.dds
1609 FS_StripExtension (filename, vabuf2, sizeof(vabuf2));
1610 FS_StripExtension (vabuf2, vabuf, sizeof(vabuf));
1611 FS_DefaultExtension (vabuf, ".ktx", sizeof(vabuf));
1612 strsize = strlen(vabuf);
1613 if (strsize > 5)
1614 for (i = 0; i <= strsize - 4; i++) // copy null termination
1615 vabuf[i] = vabuf[i + 4];
1616
1617 Con_DPrintf("Loading %s...\n", vabuf);
1618 dds = FS_LoadFile(vabuf, tempmempool, true, &ddsfilesize);
1619 ddssize = ddsfilesize;
1620
1621 if (!dds)
1622 {
1623 Con_DPrintf("Not found!\n");
1624 return NULL; // not found
1625 }
1626 Con_DPrintf("Found!\n");
1627
1628 if (flags & TEXF_ALPHA)
1629 {
1630 Con_DPrintf("KTX texture with alpha not supported yet, disabling\n");
1631 flags &= ~TEXF_ALPHA;
1632 }
1633
1634 {
1635 GLenum target;
1636 GLenum glerror;
1637 GLboolean isMipmapped;
1638 KTX_error_code ktxerror;
1639
1641
1642 // texture uploading can take a while, so make sure we're sending keepalives
1643 CL_KeepaliveMessage(false);
1644
1645 // create the texture object
1649 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
1651
1652 // upload the texture
1653 // we need to restore the texture binding after finishing the upload
1654
1655 // NOTE: some drivers fail with ETC1 NPOT (only PowerVR?). This may make the driver crash later.
1656 ktxerror = ktxLoadTextureM(dds, ddssize, &glt->texnum, &target, &sizes, &isMipmapped, &glerror,
1657 0, NULL);// can't CHECKGLERROR, the lib catches it
1658
1659 // FIXME: delete texture if we fail here
1660 if (target != GL_TEXTURE_2D)
1661 {
1662 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1663 Mem_Free(dds);
1664 Con_DPrintf("%s target != GL_TEXTURE_2D, target == %x\n", vabuf, target);
1665 return NULL; // FIXME: delete the texture from memory
1666 }
1667
1668 if (KTX_SUCCESS == ktxerror)
1669 {
1670 textype = TEXTYPE_ETC1;
1671 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1672
1673 // return whether this texture is transparent
1674 if (hasalphaflag)
1675 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1676
1677 // TODO: apply gl_picmip
1678 // TODO: avgcolor
1679 // TODO: srgb
1680 // TODO: only load mipmaps if requested
1681
1682 if (isMipmapped)
1683 flags |= TEXF_MIPMAP;
1684 else
1685 flags &= ~TEXF_MIPMAP;
1686
1687 texinfo = R_GetTexTypeInfo(textype, flags);
1688
1689 dp_strlcpy(glt->identifier, vabuf, sizeof(glt->identifier));
1690 glt->pool = pool;
1691 glt->chain = pool->gltchain;
1692 pool->gltchain = glt;
1693 glt->inputwidth = sizes.width;
1694 glt->inputheight = sizes.height;
1695 glt->inputdepth = 1;
1696 glt->flags = flags;
1697 glt->textype = texinfo;
1699 glt->inputdatasize = ddssize;
1700 glt->glinternalformat = texinfo->glinternalformat;
1701 glt->glformat = texinfo->glformat;
1702 glt->gltype = texinfo->gltype;
1703 glt->bytesperpixel = texinfo->internalbytesperpixel;
1704 glt->sides = 1;
1706 glt->tilewidth = sizes.width;
1707 glt->tileheight = sizes.height;
1708 glt->tiledepth = 1;
1709 glt->miplevels = isMipmapped ? 1 : 0; // FIXME
1710
1711 // after upload we have to set some parameters...
1712#ifdef GL_TEXTURE_MAX_LEVEL
1713 /* FIXME
1714 if (dds_miplevels >= 1 && !mipcomplete)
1715 {
1716 // need to set GL_TEXTURE_MAX_LEVEL
1717 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
1718 }
1719 */
1720#endif
1722
1723 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1724 Mem_Free(dds);
1725 return (rtexture_t *)glt;
1726 }
1727 else
1728 {
1729 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
1730 Mem_Free(dds);
1731 Con_DPrintf("KTX texture %s failed to load: %x\n", vabuf, ktxerror);
1732 return NULL;
1733 }
1734 }
1735#endif // __ANDROID__
1736
1737 dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize);
1738 ddssize = ddsfilesize;
1739
1740 if (!dds)
1741 {
1743 Log_Printf("ddstexturefailures.log", "%s\n", filename);
1744 return NULL; // not found
1745 }
1746
1747 if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32)
1748 {
1749 Mem_Free(dds);
1750 Con_Printf("^1%s: not a DDS image\n", filename);
1751 return NULL;
1752 }
1753
1754 //dds_flags = BuffLittleLong(dds+8);
1755 dds_format_flags = BuffLittleLong(dds+80);
1756 dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1;
1757 dds_width = BuffLittleLong(dds+16);
1758 dds_height = BuffLittleLong(dds+12);
1759 ddspixels = dds + 128;
1760
1762 if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
1763 flags &= ~TEXF_ALPHA;
1764
1765 //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
1766 if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
1767 {
1768 // very sloppy BGRA 32bit identification
1769 textype = TEXTYPE_BGRA;
1770 flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
1771 bytesperblock = 0;
1772 bytesperpixel = 4;
1773 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
1774 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1775 {
1776 Mem_Free(dds);
1777 Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
1778 return NULL;
1779 }
1781 {
1782 // check alpha
1783 for (i = 3;i < size;i += 4)
1784 if (ddspixels[i] < 255)
1785 break;
1786 if (i >= size)
1787 flags &= ~TEXF_ALPHA;
1788 }
1789 }
1790 else if (!memcmp(dds+84, "DXT1", 4))
1791 {
1792 // we need to find out if this is DXT1 (opaque) or DXT1A (transparent)
1793 // LadyHavoc: it is my belief that this does not infringe on the
1794 // patent because it is not decoding pixels...
1795 textype = TEXTYPE_DXT1;
1796 bytesperblock = 8;
1797 bytesperpixel = 0;
1798 //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock;
1799 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1800 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1801 {
1802 Mem_Free(dds);
1803 Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
1804 return NULL;
1805 }
1806 if (flags & TEXF_ALPHA)
1807 {
1809 {
1810 // check alpha
1811 for (i = 0;i < size;i += bytesperblock)
1812 if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
1813 {
1814 // NOTE: this assumes sizeof(unsigned int) == 4
1815 unsigned int data = * (unsigned int *) &(ddspixels[i+4]);
1816 // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel)
1817 if(data & (data<<1) & 0xAAAAAAAA)//rgh
1818 break;
1819 }
1820 if (i < size)
1821 textype = TEXTYPE_DXT1A;
1822 else
1823 flags &= ~TEXF_ALPHA;
1824 }
1826 textype = TEXTYPE_DXT1A;
1827 else
1828 {
1829 flags &= ~TEXF_ALPHA;
1830 }
1831 }
1832 }
1833 else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4))
1834 {
1835 if(!memcmp(dds+84, "DXT2", 4))
1836 {
1838 {
1839 Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename);
1840 }
1841 }
1842 else
1843 {
1845 {
1846 Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename);
1847 }
1848 }
1849 textype = TEXTYPE_DXT3;
1850 bytesperblock = 16;
1851 bytesperpixel = 0;
1852 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1853 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1854 {
1855 Mem_Free(dds);
1856 Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
1857 return NULL;
1858 }
1859 // we currently always assume alpha
1860 }
1861 else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4))
1862 {
1863 if(!memcmp(dds+84, "DXT4", 4))
1864 {
1866 {
1867 Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename);
1868 }
1869 }
1870 else
1871 {
1873 {
1874 Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename);
1875 }
1876 }
1877 textype = TEXTYPE_DXT5;
1878 bytesperblock = 16;
1879 bytesperpixel = 0;
1880 size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock);
1881 if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize))
1882 {
1883 Mem_Free(dds);
1884 Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
1885 return NULL;
1886 }
1887 // we currently always assume alpha
1888 }
1889 else
1890 {
1891 Mem_Free(dds);
1892 Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename);
1893 return NULL;
1894 }
1895
1896 // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1
1897 if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5))
1898 {
1899 textype = TEXTYPE_DXT1;
1900 bytesperblock = 8;
1901 ddssize -= 128;
1902 ddssize /= 2;
1903 for (i = 0;i < (int)ddssize;i += bytesperblock)
1904 memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8);
1905 ddssize += 128;
1906 }
1907
1908 force_swdecode = false;
1909 if(bytesperblock)
1910 {
1912 {
1914 force_swdecode = true;
1915 }
1916 else
1917 {
1919 {
1920 // unsupported
1921 Mem_Free(dds);
1922 return NULL;
1923 }
1924 force_swdecode = true;
1925 }
1926 }
1927
1928 // return whether this texture is transparent
1929 if (hasalphaflag)
1930 *hasalphaflag = (flags & TEXF_ALPHA) != 0;
1931
1932 // if we SW decode, choose 2 sizes bigger
1933 if(force_swdecode)
1934 {
1935 // this is quarter res, so do not scale down more than we have to
1936 miplevel -= 2;
1937
1938 if(miplevel < 0)
1939 Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename);
1940 }
1941
1942 // this is where we apply gl_picmip
1943 mippixels_start = ddspixels;
1944 mipwidth = dds_width;
1945 mipheight = dds_height;
1946 while(miplevel >= 1 && dds_miplevels >= 1)
1947 {
1948 if (mipwidth <= 1 && mipheight <= 1)
1949 break;
1950 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1951 mippixels_start += mipsize; // just skip
1952 --dds_miplevels;
1953 --miplevel;
1954 if (mipwidth > 1)
1955 mipwidth >>= 1;
1956 if (mipheight > 1)
1957 mipheight >>= 1;
1958 }
1959 mipsize_total = ddssize - 128 - (mippixels_start - ddspixels);
1960 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
1961
1962 // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt)
1963
1964 // fake decode S3TC if needed
1965 if(force_swdecode)
1966 {
1967 int mipsize_new = mipsize_total / bytesperblock * 4;
1968 unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new);
1969 unsigned char *p = mipnewpixels;
1970 for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4)
1971 {
1972 // UBSan: unsigned literals because promotion to int causes signed overflow when mippixels_start >= 128
1973 c = mippixels_start[i] + 256u*mippixels_start[i+1] + 65536u*mippixels_start[i+2] + 16777216u*mippixels_start[i+3];
1974 p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1975 p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f);
1976 p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f);
1977 if(textype == TEXTYPE_DXT5)
1978 p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]);
1979 else if(textype == TEXTYPE_DXT3)
1980 p[3] = (
1981 (mippixels_start[i-8] & 0x0F)
1982 + (mippixels_start[i-8] >> 4)
1983 + (mippixels_start[i-7] & 0x0F)
1984 + (mippixels_start[i-7] >> 4)
1985 + (mippixels_start[i-6] & 0x0F)
1986 + (mippixels_start[i-6] >> 4)
1987 + (mippixels_start[i-5] & 0x0F)
1988 + (mippixels_start[i-5] >> 4)
1989 ) * (0.125f / 15.0f * 255.0f);
1990 else
1991 p[3] = 255;
1992 }
1993
1994 textype = TEXTYPE_BGRA;
1995 bytesperblock = 0;
1996 bytesperpixel = 4;
1997
1998 // as each block becomes a pixel, we must use pixel count for this
1999 mipwidth = (mipwidth + 3) / 4;
2000 mipheight = (mipheight + 3) / 4;
2001 mipsize = bytesperpixel * mipwidth * mipheight;
2002 mippixels_start = mipnewpixels;
2003 mipsize_total = mipsize_new;
2004 }
2005
2006 // start mip counting
2007 mippixels = mippixels_start;
2008
2009 // calculate average color if requested
2010 if (avgcolor)
2011 {
2012 float f;
2013 Vector4Clear(avgcolor);
2014 if (bytesperblock)
2015 {
2016 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock)
2017 {
2018 // UBSan: unsigned literals because promotion to int causes signed overflow when mippixels >= 128
2019 c = mippixels[i] + 256u*mippixels[i+1] + 65536u*mippixels[i+2] + 16777216u*mippixels[i+3];
2020 avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F);
2021 avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F);
2022 avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F);
2023 if(textype == TEXTYPE_DXT5)
2024 avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f);
2025 else if(textype == TEXTYPE_DXT3)
2026 avgcolor[3] += (
2027 (mippixels_start[i-8] & 0x0F)
2028 + (mippixels_start[i-8] >> 4)
2029 + (mippixels_start[i-7] & 0x0F)
2030 + (mippixels_start[i-7] >> 4)
2031 + (mippixels_start[i-6] & 0x0F)
2032 + (mippixels_start[i-6] >> 4)
2033 + (mippixels_start[i-5] & 0x0F)
2034 + (mippixels_start[i-5] >> 4)
2035 ) * (0.125f / 15.0f);
2036 else
2037 avgcolor[3] += 1.0f;
2038 }
2039 f = (float)bytesperblock / mipsize;
2040 avgcolor[0] *= (0.5f / 31.0f) * f;
2041 avgcolor[1] *= (0.5f / 63.0f) * f;
2042 avgcolor[2] *= (0.5f / 31.0f) * f;
2043 avgcolor[3] *= f;
2044 }
2045 else
2046 {
2047 for (i = 0;i < mipsize;i += 4)
2048 {
2049 avgcolor[0] += mippixels[i+2];
2050 avgcolor[1] += mippixels[i+1];
2051 avgcolor[2] += mippixels[i];
2052 avgcolor[3] += mippixels[i+3];
2053 }
2054 f = (1.0f / 255.0f) * bytesperpixel / mipsize;
2055 avgcolor[0] *= f;
2056 avgcolor[1] *= f;
2057 avgcolor[2] *= f;
2058 avgcolor[3] *= f;
2059 }
2060 }
2061
2062 // if we want sRGB, convert now
2063 if(srgb)
2064 {
2066 {
2067 switch(textype)
2068 {
2069 case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break;
2070 case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break;
2071 case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break;
2072 case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break;
2073 case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break;
2074 default:
2075 break;
2076 }
2077 }
2078 else
2079 {
2080 switch(textype)
2081 {
2082 case TEXTYPE_DXT1:
2083 case TEXTYPE_DXT1A:
2084 case TEXTYPE_DXT3:
2085 case TEXTYPE_DXT5:
2086 {
2087 for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock)
2088 {
2089 int c0, c1, c0new, c1new;
2090 c0 = mippixels_start[i] + 256*mippixels_start[i+1];
2091 r = ((c0 >> 11) & 0x1F);
2092 g = ((c0 >> 5) & 0x3F);
2093 b = ((c0 ) & 0x1F);
2094 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2095 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2096 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2097 c0new = (r << 11) | (g << 5) | b;
2098 c1 = mippixels_start[i+2] + 256*mippixels_start[i+3];
2099 r = ((c1 >> 11) & 0x1F);
2100 g = ((c1 >> 5) & 0x3F);
2101 b = ((c1 ) & 0x1F);
2102 r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2103 g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2104 b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB
2105 c1new = (r << 11) | (g << 5) | b;
2106 // swap the colors if needed to fix order
2107 if(c0 > c1) // thirds
2108 {
2109 if(c0new < c1new)
2110 {
2111 c = c0new;
2112 c0new = c1new;
2113 c1new = c;
2114 if(c0new == c1new)
2115 mippixels_start[i+4] ^= 0x55;
2116 mippixels_start[i+5] ^= 0x55;
2117 mippixels_start[i+6] ^= 0x55;
2118 mippixels_start[i+7] ^= 0x55;
2119 }
2120 else if(c0new == c1new)
2121 {
2122 mippixels_start[i+4] = 0x00;
2123 mippixels_start[i+5] = 0x00;
2124 mippixels_start[i+6] = 0x00;
2125 mippixels_start[i+7] = 0x00;
2126 }
2127 }
2128 else // half + transparent
2129 {
2130 if(c0new > c1new)
2131 {
2132 c = c0new;
2133 c0new = c1new;
2134 c1new = c;
2135 mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55;
2136 mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55;
2137 mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55;
2138 mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55;
2139 }
2140 }
2141 mippixels_start[i] = c0new & 255;
2142 mippixels_start[i+1] = c0new >> 8;
2143 mippixels_start[i+2] = c1new & 255;
2144 mippixels_start[i+3] = c1new >> 8;
2145 }
2146 }
2147 break;
2148 case TEXTYPE_RGBA:
2149 Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock);
2150 break;
2151 default:
2152 break;
2153 }
2154 }
2155 }
2156
2157 // when not requesting mipmaps, do not load them
2158 if(!(flags & TEXF_MIPMAP))
2159 dds_miplevels = 0;
2160
2161 if (dds_miplevels >= 1)
2162 flags |= TEXF_MIPMAP;
2163 else
2164 flags &= ~TEXF_MIPMAP;
2165
2166 texinfo = R_GetTexTypeInfo(textype, flags);
2167
2169 dp_strlcpy (glt->identifier, filename, sizeof(glt->identifier));
2170 glt->pool = pool;
2171 glt->chain = pool->gltchain;
2172 pool->gltchain = glt;
2173 glt->inputwidth = mipwidth;
2174 glt->inputheight = mipheight;
2175 glt->inputdepth = 1;
2176 glt->flags = flags;
2177 glt->textype = texinfo;
2179 glt->inputdatasize = ddssize;
2180 glt->glinternalformat = texinfo->glinternalformat;
2181 glt->glformat = texinfo->glformat;
2182 glt->gltype = texinfo->gltype;
2183 glt->bytesperpixel = texinfo->internalbytesperpixel;
2184 glt->sides = 1;
2186 glt->tilewidth = mipwidth;
2187 glt->tileheight = mipheight;
2188 glt->tiledepth = 1;
2189 glt->miplevels = dds_miplevels;
2190
2191 // texture uploading can take a while, so make sure we're sending keepalives
2192 CL_KeepaliveMessage(false);
2193
2194 // create the texture object
2195 switch(vid.renderpath)
2196 {
2197 case RENDERPATH_GL32:
2198 case RENDERPATH_GLES2:
2201 oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
2202 qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR
2203 qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
2204 break;
2205 }
2206
2207 // upload the texture
2208 // we need to restore the texture binding after finishing the upload
2209 mipcomplete = false;
2210
2211 for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel
2212 {
2213 unsigned char *upload_mippixels = mippixels;
2214 int upload_mipwidth = mipwidth;
2215 int upload_mipheight = mipheight;
2216 mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel;
2217 if (mippixels + mipsize > mippixels_start + mipsize_total)
2218 break;
2219 switch(vid.renderpath)
2220 {
2221 case RENDERPATH_GL32:
2222 case RENDERPATH_GLES2:
2223 if (bytesperblock)
2224 {
2225 qglCompressedTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR
2226 }
2227 else
2228 {
2229 qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR
2230 }
2231 break;
2232 }
2233 if(upload_mippixels != mippixels)
2234 Mem_Free(upload_mippixels);
2235 mippixels += mipsize;
2236 if (mipwidth <= 1 && mipheight <= 1)
2237 {
2238 mipcomplete = true;
2239 break;
2240 }
2241 if (mipwidth > 1)
2242 mipwidth >>= 1;
2243 if (mipheight > 1)
2244 mipheight >>= 1;
2245 }
2246
2247 // after upload we have to set some parameters...
2248 switch(vid.renderpath)
2249 {
2250 case RENDERPATH_GL32:
2251 case RENDERPATH_GLES2:
2252#ifdef GL_TEXTURE_MAX_LEVEL
2253 if (dds_miplevels >= 1 && !mipcomplete)
2254 {
2255 // need to set GL_TEXTURE_MAX_LEVEL
2256 qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR
2257 }
2258#endif
2260 qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
2261 break;
2262 }
2263
2264 Mem_Free(dds);
2265 if(force_swdecode)
2266 Mem_Free((unsigned char *) mippixels_start);
2267 return (rtexture_t *)glt;
2268}
2269
2271{
2272 return rt ? ((gltexture_t *)rt)->inputwidth : 0;
2273}
2274
2276{
2277 return rt ? ((gltexture_t *)rt)->inputheight : 0;
2278}
2279
2281{
2282 return rt ? ((gltexture_t *)rt)->flags : 0;
2283}
2284
2285void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth, int combine)
2286{
2287 gltexture_t *glt = (gltexture_t *)rt;
2288 if (data == NULL)
2289 Host_Error("R_UpdateTexture: no data supplied");
2290 if (glt == NULL)
2291 Host_Error("R_UpdateTexture: no texture supplied");
2292 if (!glt->texnum)
2293 {
2294 Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool);
2295 return;
2296 }
2297 // update part of the texture
2298 if (glt->bufferpixels)
2299 {
2300 size_t j, bpp = glt->bytesperpixel;
2301
2302 // depth and sides are not fully implemented here - can still do full updates but not partial.
2303 if (glt->inputdepth != 1 || glt->sides != 1)
2304 Host_Error("R_UpdateTexture on buffered texture that is not 2D\n");
2305 if (x < 0 || y < 0 || z < 0 || glt->tilewidth < x + width || glt->tileheight < y + height || glt->tiledepth < z + depth)
2306 Host_Error("R_UpdateTexture on buffered texture with out of bounds coordinates (%i %i %i to %i %i %i is not within 0 0 0 to %i %i %i)", x, y, z, x + width, y + height, z + depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
2307
2308 for (j = 0; j < (size_t)height; j++)
2309 memcpy(glt->bufferpixels + ((y + j) * glt->tilewidth + x) * bpp, data + j * width * bpp, width * bpp);
2310
2311 switch(combine)
2312 {
2313 case 0:
2314 // immediately update the part of the texture, no combining
2316 break;
2317 case 1:
2318 // keep track of the region that is modified, decide later how big the partial update area is
2319 if (glt->buffermodified)
2320 {
2321 glt->modified_mins[0] = min(glt->modified_mins[0], x);
2322 glt->modified_mins[1] = min(glt->modified_mins[1], y);
2323 glt->modified_mins[2] = min(glt->modified_mins[2], z);
2324 glt->modified_maxs[0] = max(glt->modified_maxs[0], x + width);
2325 glt->modified_maxs[1] = max(glt->modified_maxs[1], y + height);
2326 glt->modified_maxs[2] = max(glt->modified_maxs[2], z + depth);
2327 }
2328 else
2329 {
2330 glt->buffermodified = true;
2331 glt->modified_mins[0] = x;
2332 glt->modified_mins[1] = y;
2333 glt->modified_mins[2] = z;
2334 glt->modified_maxs[0] = x + width;
2335 glt->modified_maxs[1] = y + height;
2336 glt->modified_maxs[2] = z + depth;
2337 }
2338 glt->dirty = true;
2339 break;
2340 default:
2341 case 2:
2342 // mark the entire texture as dirty, it will be uploaded later
2343 glt->buffermodified = true;
2344 glt->modified_mins[0] = 0;
2345 glt->modified_mins[1] = 0;
2346 glt->modified_mins[2] = 0;
2347 glt->modified_maxs[0] = glt->tilewidth;
2348 glt->modified_maxs[1] = glt->tileheight;
2349 glt->modified_maxs[2] = glt->tiledepth;
2350 glt->dirty = true;
2351 break;
2352 }
2353 }
2354 else
2356}
2357
2359{
2360 if (rt)
2361 {
2362 gltexture_t *glt;
2363 glt = (gltexture_t *)rt;
2364 if (glt->flags & GLTEXF_DYNAMIC)
2366 if (glt->buffermodified && glt->bufferpixels)
2367 {
2368 glt->buffermodified = false;
2369 // Because we currently don't set the relevant upload stride parameters, just make it full width.
2370 glt->modified_mins[0] = 0;
2371 glt->modified_maxs[0] = glt->tilewidth;
2372 // Check also if it's updating at least half the height of the texture.
2373 if (glt->modified_maxs[1] - glt->modified_mins[1] > glt->tileheight / 2)
2375 else
2376 R_UploadPartialTexture(glt, glt->bufferpixels + (size_t)glt->modified_mins[1] * glt->tilewidth * glt->bytesperpixel, glt->modified_mins[0], glt->modified_mins[1], glt->modified_mins[2], glt->modified_maxs[0] - glt->modified_mins[0], glt->modified_maxs[1] - glt->modified_mins[1], glt->modified_maxs[2] - glt->modified_mins[2]);
2377 }
2380 glt->dirty = false;
2381 return glt->texnum;
2382 }
2383 else
2384 return r_texture_white->texnum;
2385}
2386
2388{
2389 gltexture_t *glt = (gltexture_t *)rt;
2390
2392}
2393
2395{
2396 int miplevel = 0;
2397 if(flags & TEXF_PICMIP)
2398 {
2399 miplevel += gl_picmip.integer;
2400 if (flags & TEXF_ISWORLD)
2401 {
2403 miplevel += gl_picmip_world.integer;
2404 else
2405 miplevel = 0;
2406 }
2407 else if (flags & TEXF_ISSPRITE)
2408 {
2410 miplevel += gl_picmip_sprites.integer;
2411 else
2412 miplevel = 0;
2413 }
2414 else
2415 miplevel += gl_picmip_other.integer;
2416 }
2417 return max(0, miplevel);
2418}
client_static_t cls
Definition cl_main.c:116
void CL_KeepaliveMessage(qbool readmessages)
Definition cl_parse.c:314
cvar_t scr_screenshot_jpeg
Definition cl_screen.c:59
cvar_t scr_screenshot_png
Definition cl_screen.c:61
@ ca_dedicated
Definition client.h:530
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
Definition cmd.c:1661
static int Cmd_Argc(cmd_state_t *cmd)
Definition cmd.h:249
static const char * Cmd_Argv(cmd_state_t *cmd, int arg)
Cmd_Argv(cmd, ) will return an empty string (not a NULL) if arg > argc, so string operations are alwa...
Definition cmd.h:254
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53
int BuffLittleLong(const unsigned char *buffer)
Extract a little endian 32bit int from the given buffer.
Definition com_msg.c:71
void StoreLittleLong(unsigned char *buffer, unsigned int i)
Encode a little endian 32bit int to the given buffer.
Definition com_msg.c:95
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Log_Printf(const char *logfilename, const char *fmt,...)
Definition console.c:655
vector size
float flags
void Cvar_SetValueQuick(cvar_t *var, float value)
Definition cvar.c:473
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
Definition cvar.c:599
float alpha
qbool FS_WriteFile(const char *filename, const void *data, fs_offset_t len)
Definition fs.c:3592
void FS_DefaultExtension(char *path, const char *extension, size_t size_path)
Definition fs.c:3641
unsigned char * FS_LoadFile(const char *path, mempool_t *pool, qbool quiet, fs_offset_t *filesizepointer)
Definition fs.c:3540
static int(ZEXPORT *qz_inflate)(z_stream *strm
void FS_StripExtension(const char *in, char *out, size_t size_out)
Definition fs.c:3611
int64_t fs_offset_t
Definition fs.h:37
void GL_ActiveTexture(unsigned int num)
int R_Mesh_TexBound(unsigned int unitnum, int id)
void R_Mesh_ClearBindingsForTexture(int texnum)
rtexture_t * r_texture_white
Definition gl_rmain.c:273
static textypeinfo_t textype_depth24stencil8
static textypeinfo_t textype_rgba_compress
static textypeinfo_t textype_sRGB_dxt1
void R_PurgeTexture(rtexture_t *rt)
static textypeinfo_t textype_bgra_compress
static textypeinfo_t * R_GetTexTypeInfo(textype_t textype, int flags)
int R_RealGetTexture(rtexture_t *rt)
void R_FreeTexturePool(rtexturepool_t **rtexturepool)
cvar_t gl_texturecompression_q3bsplightmaps
Definition gl_textures.c:43
void R_ClearTexture(rtexture_t *rt)
int R_TextureFlags(rtexture_t *rt)
static void r_textures_shutdown(void)
static gltexturepool_t * gltexturepoolchain
static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL]
static textypeinfo_t textype_sRGB_palette
static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype)
static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth)
static void r_textures_newmap(void)
static textypeinfo_t textype_bgra_alpha
void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data)
cvar_t gl_texturecompression_lightcubemaps
Definition gl_textures.c:46
static textypeinfo_t textype_shadowmap16_raw
cvar_t gl_texturecompression
Definition gl_textures.c:37
static textypeinfo_t textype_sRGB_bgra_alpha
static textypeinfo_t textype_rgba_alpha_compress
static memexpandablearray_t texturearray
Definition gl_textures.c:59
static textypeinfo_t textype_sRGB_bgra_compress
cvar_t gl_max_size
Definition gl_textures.c:27
static textypeinfo_t textype_alpha
cvar_t r_picmipworld
Definition gl_textures.c:31
rtexture_t * R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
cvar_t r_texture_dds_swdecode
Definition gl_textures.c:51
static mempool_t * texturemempool
Definition gl_textures.c:58
static void r_textures_devicerestored(void)
static textypeinfo_t textype_colorbuffer
qbool gl_filter_force
Definition gl_textures.c:53
static textypeinfo_t textype_dxt5
static textypeinfo_t textype_sRGB_bgra_alpha_compress
cvar_t gl_texturecompression_sprites
Definition gl_textures.c:48
int R_TextureHeight(rtexture_t *rt)
static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels)
cvar_t gl_picmip_sprites
Definition gl_textures.c:32
cvar_t gl_texturecompression_sky
Definition gl_textures.c:45
static glmode_t modes[6]
static textypeinfo_t textype_dxt1a
static textypeinfo_t textype_sRGB_rgba_alpha_compress
void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth, int combine)
void R_TextureStats_Print(qbool printeach, qbool printpool, qbool printtotal)
static textypeinfo_t textype_rgba
cvar_t gl_picmip
Definition gl_textures.c:29
static textypeinfo_t textype_sRGB_dxt3
static unsigned char * resizebuffer
rtexture_t * R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qbool filter)
static textypeinfo_t textype_sRGB_palette_alpha
static textypeinfo_t textype_bgra
static textypeinfo_t textype_sRGB_bgra
static textypeinfo_t textype_rgba_alpha
static int cubemapside[6]
static void R_UpdateDynamicTexture(gltexture_t *glt)
static textypeinfo_t textype_sRGB_rgba_alpha
cvar_t gl_texturecompression_reflectmask
Definition gl_textures.c:47
cvar_t gl_picmip_world
Definition gl_textures.c:30
int R_TextureWidth(rtexture_t *rt)
static textypeinfo_t textype_shadowmap16_comp
static rtexture_t * R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int miplevel, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette)
cvar_t gl_texturecompression_color
Definition gl_textures.c:38
static const unsigned char * texturebuffer
int gl_filter_mag
Definition gl_textures.c:55
rtexture_t * R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qbool srgb, int flags, qbool *hasalphaflag, float *avgcolor, int miplevel, qbool optionaltexture)
static textypeinfo_t textype_bgra_alpha_compress
static textypeinfo_t textype_colorbuffer16f
static textypeinfo_t textype_palette
static void GL_TextureMode_f(cmd_state_t *cmd)
static textypeinfo_t textype_palette_alpha
cvar_t gl_picmip_other
Definition gl_textures.c:34
static void r_textures_start(void)
static textypeinfo_t textype_sRGB_rgba_compress
#define TEXTUREPOOL_SENTINEL
int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qbool skipuncompressed, qbool hasalpha)
static textypeinfo_t textype_shadowmap24_raw
cvar_t gl_texturecompression_glow
Definition gl_textures.c:41
static textypeinfo_t textype_sRGB_rgba
static int gltexturetypeenums[GLTEXTURETYPE_TOTAL]
static void r_textures_devicelost(void)
rtexture_t * R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
rtexturepool_t * R_AllocTexturePool(void)
void R_FreeTexture(rtexture_t *rt)
cvar_t r_texture_dds_load_alphamode
Definition gl_textures.c:49
static textypeinfo_t textype_dxt3
static textypeinfo_t textype_colorbuffer32f
cvar_t r_texture_dds_load_logfailure
Definition gl_textures.c:50
cvar_t gl_texturecompression_2d
Definition gl_textures.c:42
void R_Textures_Init(void)
gltexturetype_t
@ GLTEXTURETYPE_CUBEMAP
@ GLTEXTURETYPE_TOTAL
@ GLTEXTURETYPE_3D
@ GLTEXTURETYPE_2D
cvar_t gl_texture_anisotropy
Definition gl_textures.c:36
static void R_MakeResizeBufferBigger(int size)
static textypeinfo_t textype_sRGB_dxt1a
static textypeinfo_t textype_depth16
void R_MarkDirtyTexture(rtexture_t *rt)
rtexture_t * R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
cvar_t r_picmipsprites
Definition gl_textures.c:33
static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
cvar_t gl_texturecompression_q3bspdeluxemaps
Definition gl_textures.c:44
cvar_t gl_max_lightmapsize
Definition gl_textures.c:28
static int R_CalcTexelDataSize(gltexture_t *glt)
void R_Textures_Frame(void)
static textypeinfo_t textype_dxt1
cvar_t gl_texturecompression_gloss
Definition gl_textures.c:40
int R_PicmipForFlags(int flags)
static textypeinfo_t textype_sRGB_dxt5
static textypeinfo_t textype_depth24
#define GLTEXF_DYNAMIC
Definition gl_textures.c:65
static textypeinfo_t textype_shadowmap24_comp
static unsigned char * colorconvertbuffer
cvar_t r_lerpimages
Definition gl_textures.c:35
static void R_TextureStats_f(cmd_state_t *cmd)
static int resizebuffersize
int gl_filter_min
Definition gl_textures.c:54
rtexture_t * R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
cvar_t gl_texturecompression_normal
Definition gl_textures.c:39
#define GL_TEXTURE_MAX_ANISOTROPY_EXT
Definition glquake.h:199
GLubyte GLubyte GLubyte z
Definition glquake.h:782
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y
Definition glquake.h:266
#define GL_TEXTURE_COMPARE_FUNC
Definition glquake.h:209
unsigned int GLuint
Definition glquake.h:54
#define GL_NONE
Definition glquake.h:127
#define GL_FASTEST
Definition glquake.h:67
GLenum GLsizei width
Definition glquake.h:622
#define GL_NICEST
Definition glquake.h:68
GLenum GLsizei GLsizei height
Definition glquake.h:622
#define CHECKGLERROR
Definition glquake.h:1059
#define GL_TEXTURE_MIN_FILTER
Definition glquake.h:94
#define GL_TEXTURE_WRAP_R
Definition glquake.h:92
#define GL_COMPARE_R_TO_TEXTURE
Definition glquake.h:210
int GLint
Definition glquake.h:51
#define GL_DEPTH24_STENCIL8
Definition glquake.h:374
#define GL_TEXTURE_WRAP_S
Definition glquake.h:90
#define GL_DEPTH_COMPONENT16
Definition glquake.h:202
#define GL_TEXTURE_CUBE_MAP
Definition glquake.h:262
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
Definition glquake.h:269
#define GL_NEAREST_MIPMAP_NEAREST
Definition glquake.h:102
#define GL_UNSIGNED_SHORT
Definition glquake.h:121
#define GL_RGBA16F
Definition glquake.h:1028
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
Definition glquake.h:411
#define GL_TEXTURE_MAX_LEVEL
Definition glquake.h:98
#define GL_PACK_ALIGNMENT
Definition glquake.h:95
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glquake.h:609
#define GL_LINEAR
Definition glquake.h:101
unsigned char GLboolean
Definition glquake.h:46
GLint GLenum GLint GLint y
Definition glquake.h:651
#define GL_NEAREST_MIPMAP_LINEAR
Definition glquake.h:103
#define GL_BGRA
Definition glquake.h:547
#define GL_SRGB_ALPHA
Definition glquake.h:398
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
Definition glquake.h:533
GLint GLenum GLsizei GLsizei GLsizei depth
Definition glquake.h:648
#define GL_UNSIGNED_INT
Definition glquake.h:123
#define GL_RGB
Definition glquake.h:154
#define GL_TEXTURE_3D
Definition glquake.h:1035
#define GL_FLOAT
Definition glquake.h:124
#define GL_UNSIGNED_INT_24_8
Definition glquake.h:373
#define GL_LINEAR_MIPMAP_LINEAR
Definition glquake.h:105
GLint GLenum GLint x
Definition glquake.h:651
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT
Definition glquake.h:530
#define GL_TEXTURE_COMPRESSION_HINT
Definition glquake.h:524
#define GL_NEAREST
Definition glquake.h:100
#define GL_UNSIGNED_BYTE
Definition glquake.h:119
GLsizeiptr const GLvoid * data
Definition glquake.h:639
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
Definition glquake.h:410
#define GL_RENDERBUFFER
Definition glquake.h:322
#define GL_LEQUAL
Definition glquake.h:162
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
Definition glquake.h:267
#define GL_UNPACK_ALIGNMENT
Definition glquake.h:96
unsigned int GLenum
Definition glquake.h:45
GLenum internalformat
Definition glquake.h:622
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z
Definition glquake.h:268
#define GL_RGBA
Definition glquake.h:155
#define GL_LINEAR_MIPMAP_NEAREST
Definition glquake.h:104
#define GL_TEXTURE_INTERNAL_FORMAT
Definition glquake.h:97
#define GL_HALF_FLOAT
Definition glquake.h:1037
#define GL_REPEAT
Definition glquake.h:110
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
Definition glquake.h:532
#define GL_DEPTH_COMPONENT
Definition glquake.h:192
#define GL_DEPTH_STENCIL
Definition glquake.h:372
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
Definition glquake.h:531
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X
Definition glquake.h:264
#define GL_TEXTURE_WRAP_T
Definition glquake.h:91
const GLchar * name
Definition glquake.h:601
#define GL_TEXTURE_MAG_FILTER
Definition glquake.h:93
#define GL_RGBA32F
Definition glquake.h:1022
#define GL_ALPHA
Definition glquake.h:153
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
Definition glquake.h:409
#define GL_SRGB
Definition glquake.h:350
#define GL_TEXTURE_2D
Definition glquake.h:89
#define GL_DEPTH_COMPONENT24
Definition glquake.h:203
#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
Definition glquake.h:408
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X
Definition glquake.h:265
#define GL_CLAMP_TO_EDGE
Definition glquake.h:276
#define GL_TEXTURE_COMPARE_MODE
Definition glquake.h:208
void Host_Error(const char *error,...)
Definition host.c:85
void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels)
Definition image.c:930
void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality)
Definition image.c:1675
void Image_Copy8bitBGRA(const unsigned char *in, unsigned char *out, int pixels, const unsigned int *pal)
Definition image.c:129
void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int *depth, int destwidth, int destheight, int destdepth)
Definition image.c:1689
void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qbool inputflipx, qbool inputflipy, qbool inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices)
Definition image.c:24
#define Image_LinearFloatFromsRGB(c)
Definition image.h:69
qbool PNG_OpenLibrary(void)
Definition image_png.c:143
qbool JPEG_OpenLibrary(void)
Definition jpeg.c:492
void JPEG_CloseLibrary(void)
Definition jpeg.c:538
#define max(A, B)
Definition mathlib.h:38
#define min(A, B)
Definition mathlib.h:37
#define VectorClear(a)
Definition mathlib.h:97
#define bound(min, num, max)
Definition mathlib.h:34
#define Vector4Clear(a)
Definition mathlib.h:82
float strlen(string s)
void cmd(string command,...)
float floor(float f)
string target
Definition progsdefs.qc:193
int i
#define INTOVERFLOW_ADD(a, b)
Definition qdefs.h:220
#define INTOVERFLOW_NORMALIZE(a)
Definition qdefs.h:225
#define INTOVERFLOW_MUL(a, b)
Definition qdefs.h:222
#define MAX_QPATH
max length of a quake game pathname
Definition qdefs.h:169
#define INTOVERFLOW_DIV(a, b)
Definition qdefs.h:223
#define NULL
Definition qtypes.h:12
bool qbool
Definition qtypes.h:9
void R_RegisterModule(const char *name, void(*start)(void), void(*shutdown)(void), void(*newmap)(void), void(*devicelost)(void), void(*devicerestored)(void))
Definition r_modules.c:25
#define TEXF_RGBMULTIPLYBYALPHA
Definition r_textures.h:13
#define TEXF_PICMIP
Definition r_textures.h:21
#define TEXF_ALLOWUPDATES
Definition r_textures.h:31
#define TEXF_ALPHA
Definition r_textures.h:9
#define TEXF_FORCELINEAR
Definition r_textures.h:19
#define TEXF_MIPMAP
Definition r_textures.h:11
#define TEXF_ISWORLD
Definition r_textures.h:33
#define TEXF_ISSPRITE
Definition r_textures.h:35
#define TEXF_FORCENEAREST
Definition r_textures.h:17
#define TEXF_COMPRESS
Definition r_textures.h:23
textype_t
Definition r_textures.h:44
@ TEXTYPE_SRGB_DXT1
Definition r_textures.h:75
@ TEXTYPE_DXT5
Definition r_textures.h:63
@ TEXTYPE_PALETTE
Definition r_textures.h:49
@ TEXTYPE_ETC1
Definition r_textures.h:66
@ TEXTYPE_SHADOWMAP16_RAW
Definition r_textures.h:98
@ TEXTYPE_SRGB_BGRA
Definition r_textures.h:73
@ TEXTYPE_ALPHA
Definition r_textures.h:55
@ TEXTYPE_SRGB_RGBA
Definition r_textures.h:71
@ TEXTYPE_COLORBUFFER
Definition r_textures.h:84
@ TEXTYPE_DXT1
Definition r_textures.h:57
@ TEXTYPE_SHADOWMAP16_COMP
Definition r_textures.h:96
@ TEXTYPE_SRGB_DXT5
Definition r_textures.h:81
@ TEXTYPE_SRGB_PALETTE
Definition r_textures.h:69
@ TEXTYPE_SRGB_DXT3
Definition r_textures.h:79
@ TEXTYPE_COLORBUFFER32F
Definition r_textures.h:88
@ TEXTYPE_DEPTHBUFFER24
Definition r_textures.h:92
@ TEXTYPE_DXT1A
Definition r_textures.h:59
@ TEXTYPE_DEPTHBUFFER16
Definition r_textures.h:90
@ TEXTYPE_BGRA
Definition r_textures.h:53
@ TEXTYPE_DXT3
Definition r_textures.h:61
@ TEXTYPE_SRGB_DXT1A
Definition r_textures.h:77
@ TEXTYPE_RGBA
Definition r_textures.h:51
@ TEXTYPE_SHADOWMAP24_RAW
Definition r_textures.h:102
@ TEXTYPE_DEPTHBUFFER24STENCIL8
Definition r_textures.h:94
@ TEXTYPE_SHADOWMAP24_COMP
Definition r_textures.h:100
@ TEXTYPE_COLORBUFFER16F
Definition r_textures.h:86
#define TEXF_CLAMP
Definition r_textures.h:15
void(* updatecallback_t)(rtexture_t *rt, void *data)
Definition r_textures.h:168
#define TEXF_PERSISTENT
Definition r_textures.h:25
#define TEXF_RENDERTARGET
Definition r_textures.h:37
dp_FragColor r
return ret
dp_FragColor g
precision highp float
Definition shader_glsl.h:53
float f
dp_FragColor b
cactive_t state
Definition client.h:568
command interpreter state - the tokenizing and execution of commands, as well as pointers to which cv...
Definition cmd.h:127
Definition cvar.h:66
int integer
Definition cvar.h:73
int magnification
const char * name
int minification
int renderbuffernum
int gltexturetypeenum
const unsigned int * palette
char identifier[MAX_QPATH+32]
struct gltexturepool_s * pool
int glinternalformat
unsigned char * bufferpixels
int modified_maxs[3]
qbool glisdepthstencil
textypeinfo_t * textype
struct gltexture_s * chain
qbool buffermodified
void * updatecallback_data
updatecallback_t updatecallback
unsigned char * inputtexels
int modified_mins[3]
struct gltexture_s * gltchain
unsigned int sentinel
struct gltexturepool_s * next
int internalbytesperpixel
Definition gl_textures.c:72
textype_t textype
Definition gl_textures.c:70
int inputbytesperpixel
Definition gl_textures.c:71
const char * name
Definition gl_textures.c:69
float glinternalbytesperpixel
Definition gl_textures.c:73
qbool ext_texture_filter_anisotropic
Definition vid.h:49
qbool ext_texture_compression_s3tc
Definition vid.h:48
qbool ext_texture_srgb
Definition vid.h:50
unsigned int maxtexturesize_2d
Definition vid.h:83
int forcetextype
always use GL_BGRA for D3D, always use GL_RGBA for GLES, etc
Definition vid.h:91
unsigned int maxtexturesize_3d
Definition vid.h:84
unsigned int maxtexturesize_cubemap
Definition vid.h:85
renderpath_t renderpath
Definition vid.h:80
unsigned int max_anisotropy
Definition vid.h:86
viddef_support_t support
Definition vid.h:89
void Sys_Error(const char *error,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
Causes the entire program to exit ASAP.
Definition sys_shared.c:724
@ RENDERPATH_GLES2
Definition vid.h:38
@ RENDERPATH_GL32
Definition vid.h:37
const char * gl_version
begins with 1.0.0, 1.1.0, 1.2.0, 1.2.1, 1.3.0, 1.3.1, or 1.4.0
Definition vid_shared.c:194
viddef_t vid
global video state
Definition vid_shared.c:64
size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l)
Definition zone.c:763
void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray)
Definition zone.c:675
void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record)
Definition zone.c:743
void * Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l)
Definition zone.c:695
void * Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index)
Definition zone.c:780
mempool_t * tempmempool
Definition zone.c:794
void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l)
Definition zone.c:683
#define Mem_Free(mem)
Definition zone.h:96
#define Mem_FreePool(pool)
Definition zone.h:105
#define Mem_Alloc(pool, size)
Definition zone.h:92
#define Mem_AllocPool(name, flags, parent)
Definition zone.h:104