UFO: Alien Invasion
Loading...
Searching...
No Matches
r_image.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 1997-2001 Id Software, Inc.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "r_local.h"
26#include "r_error.h"
27#include "r_geoscape.h"
28#include "../../shared/images.h"
29#include "../cl_screen.h"
30
31#define MAX_IMAGEHASH 256
33
34#define IMAGE_ARRAY_SIZE 128
35typedef struct imageArray_s {
37 struct imageArray_s* next;
39
42
43/* Wicked for()-loop to go through all images in the r_images linked list. Parameters are: (int i, image_t* image, imageArray_t* imageArray) */
44#define FOR_EACH_IMAGE(i, image, imageArray) \
45 for (i = 0, imageArray = &r_images, image = &imageArray->images[0]; i < r_numImages; i++, image++, \
46 (i % IMAGE_ARRAY_SIZE) ? 0 : (image = (imageArray = imageArray->next) ? &imageArray->images[0] : nullptr))
47
48
49/* generic environment map */
51
52/* lense flares */
54
55#define MAX_TEXTURE_SIZE 8192
56
62{
63 int i;
64 image_t* image;
65 imageArray_t* images;
66
67 /* clear previously loaded materials */
68 FOR_EACH_IMAGE(i, image, images) {
69 material_t* m = &image->material;
70 materialStage_t* s = m->stages;
71
72 while (s) { /* free the stages chain */
73 materialStage_t* ss = s->next;
74 Mem_Free(s);
75 s = ss;
76 }
77
79 }
80}
81
85void R_ImageList_f (void)
86{
87 int i, cnt;
88 image_t* image;
89 imageArray_t* images;
90 int texels;
91
92 Com_Printf("------------------\n");
93 texels = 0;
94 cnt = 0;
95
96 FOR_EACH_IMAGE(i, image, images) {
97 const char* type;
98 if (!image->texnum)
99 continue;
100 cnt++;
101 texels += image->upload_width * image->upload_height;
102 switch (image->type) {
103 case it_effect:
104 type = "EF";
105 break;
106 case it_skin:
107 type = "SK";
108 break;
109 case it_wrappic:
110 type = "WR";
111 break;
112 case it_chars:
113 type = "CH";
114 break;
115 case it_static:
116 type = "ST";
117 break;
118 case it_normalmap:
119 type = "NM";
120 break;
121 case it_material:
122 type = "MA";
123 break;
124 case it_lightmap:
125 type = "LM";
126 break;
127 case it_world:
128 type = "WO";
129 break;
130 case it_pic:
131 type = "PI";
132 break;
133 default:
134 type = " ";
135 break;
136 }
137
138 Com_Printf("%s %4i %4i RGB: %5i idx: %s\n", type, image->upload_width, image->upload_height, image->texnum, image->name);
139 }
140 Com_Printf("Total textures: %i/%i (max textures: %i)\n", cnt, r_numImages, MAX_GL_TEXTURES);
141 Com_Printf("Total texel count (not counting mipmaps): %i\n", texels);
142}
143
152void R_LoadImage (const char* name, byte** pic, int* width, int* height)
153{
154 char filenameTemp[MAX_QPATH];
155 SDL_Surface* surf;
156
157 if (Q_strnull(name))
158 Com_Error(ERR_FATAL, "R_LoadImage: nullptr name");
159
160 Com_StripExtension(name, filenameTemp, sizeof(filenameTemp));
161
162 if ((surf = Img_LoadImage(filenameTemp))) {
163 const size_t size = (surf->w * surf->h) * 4;
164 *width = surf->w;
165 *height = surf->h;
167 memcpy(*pic, surf->pixels, size);
168 SDL_FreeSurface(surf);
169 }
170}
171
172void R_ScaleTexture (const unsigned* in, int inwidth, int inheight, unsigned* out, int outwidth, int outheight)
173{
174 int i;
175 unsigned p1[MAX_TEXTURE_SIZE], p2[MAX_TEXTURE_SIZE];
176 const unsigned fracstep = inwidth * 0x10000 / outwidth;
177
178 assert(outwidth <= MAX_TEXTURE_SIZE);
179
180 unsigned frac = fracstep >> 2;
181 for (i = 0; i < outwidth; i++) {
182 p1[i] = 4 * (frac >> 16);
183 frac += fracstep;
184 }
185 frac = 3 * (fracstep >> 2);
186 for (i = 0; i < outwidth; i++) {
187 p2[i] = 4 * (frac >> 16);
188 frac += fracstep;
189 }
190
191 for (i = 0; i < outheight; i++, out += outwidth) {
192 const int index = inwidth * (int) ((i + 0.25) * inheight / outheight);
193 const unsigned* inrow = in + index;
194 const int index2 = inwidth * (int) ((i + 0.75) * inheight / outheight);
195 const unsigned* inrow2 = in + index2;
196
197 assert(index < inwidth * inheight);
198 assert(index2 < inwidth * inheight);
199
200 for (int j = 0; j < outwidth; j++) {
201 const byte* pix1 = (const byte*) inrow + p1[j];
202 const byte* pix2 = (const byte*) inrow + p2[j];
203 const byte* pix3 = (const byte*) inrow2 + p1[j];
204 const byte* pix4 = (const byte*) inrow2 + p2[j];
205 ((byte*) (out + j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2;
206 ((byte*) (out + j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2;
207 ((byte*) (out + j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2;
208 ((byte*) (out + j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2;
209 }
210 }
211}
212
220void R_GetScaledTextureSize (int width, int height, int* scaledWidth, int* scaledHeight)
221{
222 for (*scaledWidth = 1; *scaledWidth < width; *scaledWidth <<= 1) {}
223 for (*scaledHeight = 1; *scaledHeight < height; *scaledHeight <<= 1) {}
224
225 while (*scaledWidth > r_config.maxTextureSize || *scaledHeight > r_config.maxTextureSize) {
226 *scaledWidth >>= 1;
227 *scaledHeight >>= 1;
228 }
229
230 if (*scaledWidth > MAX_TEXTURE_SIZE)
231 *scaledWidth = MAX_TEXTURE_SIZE;
232 else if (*scaledWidth < 1)
233 *scaledWidth = 1;
234
235 if (*scaledHeight > MAX_TEXTURE_SIZE)
236 *scaledHeight = MAX_TEXTURE_SIZE;
237 else if (*scaledHeight < 1)
238 *scaledHeight = 1;
239}
240
242{
243 return type == it_pic || type == it_worldrelated;
244}
245
246#ifdef GL_VERSION_ES_CM_1_0
247inline static void R_StripAlpha (const unsigned* data, unsigned* buffer, const unsigned count)
248{
249 for (unsigned i = 0; i < count; ++i, ++data) {
250 memmove(((byte*)buffer) + i * 3, (const byte*)data, 3);
251 }
252}
253#endif
254
262void R_UploadTexture (const unsigned* data, int width, int height, image_t* image)
263{
264 const bool mipmap = (image->type != it_pic && image->type != it_worldrelated && image->type != it_chars);
265 const bool clamp = R_IsClampedImageType(image->type);
266#ifdef GL_VERSION_ES_CM_1_0
267 GLint texFormat = GL_RGB;
268#else
269 GLint texFormat = r_config.gl_compressed_solid_format ? r_config.gl_compressed_solid_format : r_config.gl_solid_format;
270#endif
271
272 /* scan the texture for any non-255 alpha */
273 int i;
274 const byte* scan;
275 const int c = width * height;
276 /* set scan to the first alpha byte */
277 for (i = 0, scan = ((const byte*) data) + 3; i < c; ++i, scan += 4) {
278 if (*scan != 255) {
279#ifdef GL_VERSION_ES_CM_1_0
280 texFormat = GL_RGBA;
281#else
282 texFormat = r_config.gl_compressed_alpha_format ? r_config.gl_compressed_alpha_format : r_config.gl_alpha_format;
283#endif
284 image->has_alpha = true;
285 break;
286 }
287 }
288
289 int scaledWidth, scaledHeight;
290 R_GetScaledTextureSize(width, height, &scaledWidth, &scaledHeight);
291
292 image->upload_width = scaledWidth; /* after power of 2 and scales */
293 image->upload_height = scaledHeight;
294
295 unsigned* tmpBuff = nullptr;
296 /* some images need very little attention (pics, fonts, etc..) */
297 if (!mipmap && scaledWidth == width && scaledHeight == height) {
298 /* no mipmapping for these images to save memory */
299 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
300 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
301 if (clamp) {
302 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
303 R_CheckError();
304 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
305 R_CheckError();
306 }
307#ifdef GL_VERSION_ES_CM_1_0
308 /* Strip alpha, see comments below */
309 if (texFormat == GL_RGB) {
310 const int count = scaledWidth * scaledHeight;
311 tmpBuff = Mem_PoolAllocTypeN(unsigned, count, vid_imagePool);
312 R_StripAlpha(data, tmpBuff, count);
313 }
314 GLenum bFormat = texFormat;
315#else
316 GLenum bFormat = GL_RGBA;
317#endif
318 glTexImage2D(GL_TEXTURE_2D, 0, texFormat, scaledWidth, scaledHeight, 0, bFormat, GL_UNSIGNED_BYTE, tmpBuff ? tmpBuff : data);
319 if (tmpBuff)
320 Mem_Free(tmpBuff);
321 return;
322 }
323
324 if (scaledWidth != width || scaledHeight != height) { /* whereas others need to be scaled */
325 tmpBuff = Mem_PoolAllocTypeN(unsigned, scaledWidth * scaledHeight, vid_imagePool);
326 R_ScaleTexture(data, width, height, tmpBuff, scaledWidth, scaledHeight);
327 }
328
329#ifdef GL_VERSION_ES_CM_1_0
330 /*
331 * According to https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexImage2D.xml
332 * texture format *must* match the data format, which we *always* read as RGBA,
333 * so we need to strip the alpha if we want to upload as RGB, and we want: memory *is*
334 * usually a concern on an ES.
335 */
336 if (texFormat == GL_RGB) {
337 const int count = scaledWidth * scaledHeight;
338 if (!tmpBuff)
339 tmpBuff = Mem_PoolAllocTypeN(unsigned, count, vid_imagePool);
340 R_StripAlpha(c == count ? data : tmpBuff, tmpBuff, count);
341 }
342#endif
343
344 /* and mipmapped */
345 if (mipmap) {
346 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, r_config.gl_filter_min);
347 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, r_config.gl_filter_max);
348 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
349 if (r_config.anisotropic) {
350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic);
351 R_CheckError();
352 }
353#ifndef GL_VERSION_ES_CM_1_0
354 if (r_texture_lod->integer && r_config.lod_bias) {
355 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, r_texture_lod->value);
356 R_CheckError();
357 }
358#endif
359 } else {
360 if (r_config.anisotropic) {
361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
362 R_CheckError();
363 }
364 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, r_config.gl_filter_max);
365 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, r_config.gl_filter_max);
366 }
367 R_CheckError();
368
369 if (clamp) {
370 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
371 R_CheckError();
372 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
373 R_CheckError();
374 }
375
376#ifdef GL_VERSION_ES_CM_1_0
377 const GLenum bFormat = texFormat;
378#else
379 const GLenum bFormat = GL_RGBA;
380#endif
381 glTexImage2D(GL_TEXTURE_2D, 0, texFormat, scaledWidth, scaledHeight, 0, bFormat, GL_UNSIGNED_BYTE, tmpBuff ? tmpBuff : data);
382 R_CheckError();
383
384 if (tmpBuff)
385 Mem_Free(tmpBuff);
386}
387
391void R_SoftenTexture (byte* in, int width, int height, int bpp)
392{
393 const int size = width * height * bpp;
394
395 /* soften into a copy of the original image, as in-place would be incorrect */
396 byte* const out = Mem_PoolAllocTypeN(byte, size, vid_imagePool);
397 if (!out)
398 Com_Error(ERR_FATAL, "R_SoftenTexture: failed on allocation of %i bytes", width * height * bpp);
399
400 memcpy(out, in, size);
401
402 for (int i = 1; i < height - 1; i++) {
403 for (int j = 1; j < width - 1; j++) {
404 const byte* src = in + ((i * width) + j) * bpp; /* current input pixel */
405
406 const byte* u = (src - (width * bpp)); /* and it's neighbors */
407 const byte* d = (src + (width * bpp));
408 const byte* l = (src - (1 * bpp));
409 const byte* r = (src + (1 * bpp));
410
411 byte* dest = out + ((i * width) + j) * bpp; /* current output pixel */
412
413 for (int k = 0; k < bpp; k++)
414 dest[k] = (u[k] + d[k] + l[k] + r[k]) / 4;
415 }
416 }
417
418 /* copy the softened image over the input image, and free it */
419 memcpy(in, out, size);
420 Mem_Free(out);
421}
422
423void R_UploadAlpha (const image_t* image, const byte* alphaData)
424{
425 R_BindTexture(image->texnum);
426
427 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, image->width, image->height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, alphaData);
428 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, r_config.gl_filter_max);
429 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, r_config.gl_filter_max);
430 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
431 if (image->type == it_wrappic)
432 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
433}
434
435static inline void R_DeleteImage (image_t* image)
436{
437 const unsigned int hash = Com_HashKey(image->name, MAX_IMAGEHASH);
438 for (image_t** anchor = &imageHash[hash]; *anchor; anchor = &(*anchor)->hash_next) {
439 if (Q_streq((*anchor)->name, image->name)) {
440 HASH_Delete(anchor);
441 break;
442 }
443 }
444
445 /* free it */
446 glDeleteTextures(1, &image->texnum);
447 R_CheckError();
448
449 OBJZERO(*image);
450}
451
452image_t* R_GetImage (const char* name)
453{
454 image_t* image;
455 const unsigned hash = Com_HashKey(name, MAX_IMAGEHASH);
456
457 /* look for it */
458 for (image = imageHash[hash]; image; image = image->hash_next)
459 if (Q_streq(name, image->name))
460 return image;
461
462 return nullptr;
463}
464
475image_t* R_LoadImageData (const char* name, const byte* pic, int width, int height, imagetype_t type)
476{
477 image_t* image;
478 imageArray_t* images;
479 int i;
480 size_t len;
481 unsigned hash;
482
483 len = strlen(name);
484 if (len >= sizeof(image->name))
485 Com_Error(ERR_DROP, "R_LoadImageData: \"%s\" is too long", name);
486 if (len == 0)
487 Com_Error(ERR_DROP, "R_LoadImageData: name is empty");
488
489 /* look for it */
490 image = R_GetImage(name);
491 if (image) {
492 assert(image->texnum);
493 Com_Printf("R_LoadImageData: image '%s' is already uploaded\n", name);
494 return image;
495 }
496
497 /* find a free image_t, using a wicked for()-loop */
498 FOR_EACH_IMAGE(i, image, images) {
499 if (!image->texnum)
500 break;
501 }
502
503 if (i == r_numImages) {
504 /* Did we run out of space in the current array? Add a new array chunk */
505 if (r_numImages % IMAGE_ARRAY_SIZE == 0) {
506 for (images = &r_images; images->next;)
507 images = images->next;
509 image = &images->next->images[0];
510 }
511 r_numImages++;
512 }
513 OBJZERO(*image);
514 image->material = defaultMaterial;
515 image->has_alpha = false;
516 image->type = type;
517 image->width = width;
518 image->height = height;
519
521#ifdef COMPILE_UNITTESTS
522 {
523 static int texnum = 0;
524 image->texnum = ++texnum;
525 }
526#else
527 glGenTextures(1, &image->texnum);
528#endif
529
530 Q_strncpyz(image->name, name, sizeof(image->name));
531 /* drop extension */
532 if (len >= 4 && image->name[len - 4] == '.') {
533 image->name[len - 4] = '\0';
534 Com_Printf("Image with extension: '%s'\n", name);
535 }
536
538 HASH_Add(imageHash, image, hash);
539
540 if (pic) {
541 R_BindTexture(image->texnum);
542 R_UploadTexture((const unsigned* ) pic, width, height, image);
543 }
544 return image;
545}
546
547image_t* R_RenderToTexture (const char* name, int x, int y, int w, int h)
548{
549 image_t* img = R_GetImage(name);
550 const bool dimensionDiffer = img != nullptr && img->width != w && img->height != h;
551 if (img == nullptr || dimensionDiffer) {
552 if (dimensionDiffer) {
553 R_DeleteImage(img);
554 }
555 byte* const buf = Mem_PoolAllocTypeN(byte, w * h * 4, vid_imagePool);
556 img = R_LoadImageData(name, buf, w, h, it_effect);
557 Mem_Free(buf);
558 }
559
560 glFlush();
561#ifndef GL_VERSION_ES_CM_1_0
562 glReadBuffer(GL_BACK);
563#endif
565 R_BindTexture(img->texnum);
566 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, w, h, 0);
567
568 return img;
569}
570
576{
577 if (!img)
578 return;
579
580 img->type = type;
581 R_BindTexture(img->texnum);
582
584 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
585 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
586 } else {
587 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
588 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
589 }
590}
591
603image_t* R_FindImage (const char* pname, imagetype_t type)
604{
605 char lname[MAX_QPATH];
606 image_t* image;
607 SDL_Surface* surf;
608
609 if (!pname || !pname[0])
610 Com_Error(ERR_FATAL, "R_FindImage: nullptr name");
611
612 /* drop extension */
613 Com_StripExtension(pname, lname, sizeof(lname));
614
615 image = R_GetImage(lname);
616 if (image) {
617 /* Warn if game tries to use same image with different texture mapping modes */
619 Com_Printf("Warning: inconsistent usage of image %s (%i,%i)\n", image->name, image->type, type);
620 R_ChangeImageType(image, type);
625 }
626 return image;
627 }
628
629 if ((surf = Img_LoadImage(lname))) {
630 image = R_LoadImageData(lname, (byte*)surf->pixels, surf->w, surf->h, type);
631 SDL_FreeSurface(surf);
632 if (image->type == it_world) {
633 image->normalmap = R_FindImage(va("%s_nm", image->name), it_normalmap);
634 if (image->normalmap == r_noTexture)
635 image->normalmap = nullptr;
636 }
637 if (image->type != it_glowmap) {
638 image->glowmap = R_FindImage(va("%s_gm", image->name), it_glowmap);
639 if (image->glowmap == r_noTexture)
640 image->glowmap = nullptr;
641 }
642 if (image->type != it_normalmap) {
643 image->normalmap = R_FindImage(va("%s_nm", image->name), it_normalmap);
644 if (image->normalmap == r_noTexture)
645 image->normalmap = nullptr;
646 }
647 if (image->type != it_specularmap) {
648 image->specularmap = R_FindImage(va("%s_sm", image->name), it_specularmap);
649 if (image->specularmap == r_noTexture)
650 image->specularmap = nullptr;
651 }
652 if (image->type != it_roughnessmap) {
653 image->roughnessmap = R_FindImage(va("%s_rm", image->name), it_roughnessmap);
654 if (image->roughnessmap == r_noTexture)
655 image->roughnessmap = nullptr;
656 }
657 }
658
659 /* no fitting texture found */
660 if (!image)
661 image = r_noTexture;
662
663 return image;
664}
665
673const image_t* R_FindPics (const char* name)
674{
675 const image_t* image = R_FindImage(va("pics/%s", name), it_pic);
676 if (image == r_noTexture)
677 return nullptr;
678 return image;
679}
680
681bool R_ImageExists (const char* pname, ...)
682{
683 char const* const* const types = Img_GetImageTypes();
684 char filename[MAX_QPATH];
685 va_list ap;
686
687 va_start(ap, pname);
688 Q_vsnprintf(filename, sizeof(filename), pname, ap);
689 va_end(ap);
690
691 for (int i = 0; types[i]; i++) {
692 if (FS_CheckFile("%s.%s", filename, types[i]) != -1)
693 return true;
694 }
695 return false;
696}
697
703{
704 imageArray_t* images;
705
706 for (images = &r_images; images; images = images->next) {
707 if (imagePtr >= &images->images[0] && imagePtr <= &images->images[IMAGE_ARRAY_SIZE - 1])
708 return imagePtr - &images->images[0];
709 }
710
711 return -1;
712}
713
719{
720 imageArray_t* images;
721
722 if (i >= r_numImages || i < 0)
723 return nullptr;
724
725 for (images = &r_images; i >= IMAGE_ARRAY_SIZE; i -= IMAGE_ARRAY_SIZE)
726 images = images->next;
727
728 return &images->images[i];
729}
730
735void R_FreeImage (image_t* image)
736{
737 /* free image slot */
738 if (!image || !image->texnum)
739 return;
740
741 /* also free the several maps if they are loaded */
742 if (image->normalmap)
743 R_DeleteImage(image->normalmap);
744 if (image->glowmap)
745 R_DeleteImage(image->glowmap);
746 if (image->roughnessmap)
748 if (image->specularmap)
750 R_DeleteImage(image);
751}
752
758{
759 int i;
760 image_t* image;
761 imageArray_t* images;
762
763 R_CheckError();
764 /* Wicked for()-loop (tm) */
765 FOR_EACH_IMAGE(i, image, images) {
766 if (image->type < it_world)
767 continue; /* keep them */
768
769 /* free it */
770 R_FreeImage(image);
771 }
772}
773
774void R_InitImages (void)
775{
776 int i;
777
778 r_numImages = 0;
779
780 for (i = 0; i < MAX_ENVMAPTEXTURES; i++) {
781 r_envmaptextures[i] = R_FindImage(va("pics/envmaps/envmap_%i", i), it_effect);
783 Com_Error(ERR_FATAL, "Could not load environment map %i", i);
784 }
785
786 for (i = 0; i < NUM_FLARETEXTURES; i++) {
787 r_flaretextures[i] = R_FindImage(va("pics/flares/flare_%i", i), it_effect);
789 Com_Error(ERR_FATAL, "Could not load lens flare %i", i);
790 }
791}
792
797{
798 int i;
799 image_t* image;
800 imageArray_t* images;
801
802 R_CheckError();
803 /* Wicked for()-loop (tm) */
804 FOR_EACH_IMAGE(i, image, images) {
805 if (!image->texnum)
806 continue; /* free image_t slot */
807 R_DeleteImage(image);
808 }
811 r_numImages = 0;
812}
813
814static void R_ReloadImageData (image_t* image)
815{
816 SDL_Surface* surf;
817 if (image == r_noTexture || !image || !image->texnum)
818 return;
819
820 surf = Img_LoadImage(image->name);
821 if (!surf) {
822 Com_Printf("R_ReloadImageData: unable to load image %s\n", image->name);
823 surf = SDL_CreateRGBSurface(0, image->width, image->height, 32,
824 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
825 SDL_FillRect(surf, nullptr, 0x99ff33ff); /* A random color */
826 }
827 glGenTextures(1, &image->texnum);
828 R_BindTexture(image->texnum);
829 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
830 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
831 R_UploadTexture((unsigned* )surf->pixels, surf->w, surf->h, image);
832 SDL_FreeSurface(surf);
833}
834
835void R_ReloadImages (void)
836{
837 int i;
838 image_t* image;
839 imageArray_t* images;
840
841 R_CheckError();
842 glEnable(GL_TEXTURE_2D);
843 FOR_EACH_IMAGE(i, image, images) {
844 if (i % 5 == 0) {
845 SCR_DrawLoadingScreen(false, i * 100 / r_numImages);
846 }
847 R_ReloadImageData(image);
852 }
853}
854
855typedef struct {
856 const char* name;
859
861 {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, /* no filtering, no mipmaps */
862 {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, /* bilinear filtering, no mipmaps */
863 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, /* no filtering, mipmaps */
864 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, /* bilinear filtering, mipmaps */
865 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, /* trilinear filtering, mipmaps */
866 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} /* bilinear filtering, trilinear filtering, mipmaps */
867};
868
869void R_TextureMode (const char* string)
870{
871 int i;
872 const size_t size = lengthof(gl_texture_modes);
873 const glTextureMode_t* mode = nullptr;
874 for (i = 0; i < size; i++) {
876 if (!Q_strcasecmp(mode->name, string))
877 break;
878 }
879
880 if (mode == nullptr) {
881 Com_Printf("bad filter name\n");
882 return;
883 }
884
885 r_config.gl_filter_min = mode->minimize;
886 r_config.gl_filter_max = mode->maximize;
887
888 /* Wicked for()-loop (tm) */
889 image_t* image;
890 imageArray_t* images;
891 FOR_EACH_IMAGE(i, image, images) {
892 if (image->type == it_pic || image->type == it_worldrelated || image->type == it_chars)
893 continue; /* no mipmaps */
894
895 R_BindTexture(image->texnum);
896 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode->minimize);
897 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode->maximize);
898 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic);
899 R_CheckError();
900 }
901}
902
903#ifdef GL_VERSION_ES_CM_1_0
904void R_TextureSolidMode (const char* string)
905{
906}
907void R_TextureAlphaMode (const char* string)
908{
909}
910#else
911typedef struct {
912 const char* name;
913 int mode;
914} gltmode_t;
915
916static const gltmode_t gl_alpha_modes[] = {
917 {"GL_RGBA", GL_RGBA},
918 {"GL_RGBA8", GL_RGBA8},
919 {"GL_RGB5_A1", GL_RGB5_A1},
920 {"GL_RGBA4", GL_RGBA4},
921 {"GL_RGBA2", GL_RGBA2},
922 {"GL_LUMINANCE4_ALPHA4", GL_LUMINANCE4_ALPHA4},
923 {"GL_LUMINANCE6_ALPHA2", GL_LUMINANCE6_ALPHA2},
924 {"GL_LUMINANCE8_ALPHA8", GL_LUMINANCE8_ALPHA8},
925 {"GL_LUMINANCE12_ALPHA4", GL_LUMINANCE12_ALPHA4},
926 {"GL_LUMINANCE12_ALPHA12", GL_LUMINANCE12_ALPHA12},
927 {"GL_LUMINANCE16_ALPHA16", GL_LUMINANCE16_ALPHA16}
928};
929
930
931void R_TextureAlphaMode (const char* string)
932{
933 const size_t size = lengthof(gl_alpha_modes);
934
935 for (int i = 0; i < size; i++) {
936 const gltmode_t* mode = &gl_alpha_modes[i];
937 if (!Q_strcasecmp(mode->name, string)) {
938 r_config.gl_alpha_format = mode->mode;
939 return;
940 }
941 }
942
943 Com_Printf("bad alpha texture mode name (%s)\n", string);
944}
945
946static const gltmode_t gl_solid_modes[] = {
947 {"GL_RGB", GL_RGB},
948 {"GL_RGB8", GL_RGB8},
949 {"GL_RGB5", GL_RGB5},
950 {"GL_RGB4", GL_RGB4},
951 {"GL_R3_G3_B2", GL_R3_G3_B2},
952 {"GL_RGB2", GL_RGB2_EXT},
953 {"GL_RGB4", GL_RGB4_EXT},
954 {"GL_RGB5", GL_RGB5_EXT},
955 {"GL_RGB8", GL_RGB8_EXT},
956 {"GL_RGB10", GL_RGB10_EXT},
957 {"GL_RGB12", GL_RGB12_EXT},
958 {"GL_RGB16", GL_RGB16_EXT},
959 {"GL_LUMINANCE", GL_LUMINANCE},
960 {"GL_LUMINANCE4", GL_LUMINANCE4},
961 {"GL_LUMINANCE8", GL_LUMINANCE8},
962 {"GL_LUMINANCE12", GL_LUMINANCE12},
963 {"GL_LUMINANCE16", GL_LUMINANCE16}
964};
965
966void R_TextureSolidMode (const char* string)
967{
968 const size_t size = lengthof(gl_solid_modes);
969
970 for (int i = 0; i < size; i++) {
971 const gltmode_t* mode = &gl_solid_modes[i];
972 if (!Q_strcasecmp(mode->name, string)) {
973 r_config.gl_solid_format = mode->mode;
974 return;
975 }
976 }
977
978 Com_Printf("bad solid texture mode name (%s)\n", string);
979}
980#endif
memPool_t * vid_imagePool
Definition cl_main.cpp:88
void SCR_DrawLoadingScreen(bool string, int percent)
Precache and loading screen at startup.
Header for certain screen operations.
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define HASH_Delete(anchor)
Definition common.h:416
#define HASH_Add(hash, elem, index)
Definition common.h:407
#define ERR_DROP
Definition common.h:211
#define ERR_FATAL
Definition common.h:210
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition files.cpp:298
#define MAX_QPATH
Definition filesys.h:40
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *texels)
Definition gldummy.cpp:17
void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
Definition gldummy.cpp:13
void glGenTextures(GLsizei n, GLuint *textures)
Definition gldummy.cpp:22
char const *const * Img_GetImageTypes(void)
Definition images.cpp:56
SDL_Surface * Img_LoadImage(char const *name)
Loads the specified image from the game filesystem into an SDL_Surface.
Definition images.cpp:488
Image loading and saving functions.
voidpf void uLong size
Definition ioapi.h:42
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const char * filename
Definition ioapi.h:41
voidpf void * buf
Definition ioapi.h:42
const char int mode
Definition ioapi.h:41
static struct mdfour * m
Definition md4.cpp:35
#define Mem_PoolAllocTypeN(type, n, pool)
Definition mem.h:42
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_AllocType(type)
Definition mem.h:39
Error checking function.
#define R_CheckError()
Definition r_error.h:30
static wrapCache_t * hash[MAX_WRAP_HASH]
Definition r_font.cpp:86
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN GLenum GLuint * dest
Definition r_gl.h:101
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLint
Definition r_gl.h:135
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
QGL_EXTERN GLuint index
Definition r_gl.h:110
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
QGL_EXTERN const GLuint *QGL_EXTERN GLuint *QGL_EXTERN GLenum
Definition r_gl.h:127
void R_FreeWorldImages(void)
Any image that is a mesh or world texture will be removed here.
Definition r_image.cpp:757
#define MAX_TEXTURE_SIZE
Definition r_image.cpp:55
static void R_ChangeImageType(image_t *img, imagetype_t type)
Set up new image type and change texturemapping paramenters accordingly.
Definition r_image.cpp:575
void R_SoftenTexture(byte *in, int width, int height, int bpp)
Applies blurring to a texture.
Definition r_image.cpp:391
void R_FreeImage(image_t *image)
Free the image and its assigned maps (roughness, normal, specular, glow - if there are any).
Definition r_image.cpp:735
#define IMAGE_ARRAY_SIZE
Definition r_image.cpp:34
image_t * R_FindImage(const char *pname, imagetype_t type)
Finds or loads the given image.
Definition r_image.cpp:603
image_t * R_GetImageAtIndex(int i)
Returns an image pointer from the r_images linked list, as if r_images would be a plain contiguous ar...
Definition r_image.cpp:718
#define MAX_IMAGEHASH
Definition r_image.cpp:31
void R_GetScaledTextureSize(int width, int height, int *scaledWidth, int *scaledHeight)
Calculates the texture size that should be used to upload the texture data.
Definition r_image.cpp:220
void R_ImageList_f(void)
Shows all loaded images.
Definition r_image.cpp:85
static const glTextureMode_t gl_texture_modes[]
Definition r_image.cpp:860
void R_ReloadImages(void)
Definition r_image.cpp:835
static const gltmode_t gl_solid_modes[]
Definition r_image.cpp:946
void R_TextureAlphaMode(const char *string)
Definition r_image.cpp:931
image_t * r_envmaptextures[MAX_ENVMAPTEXTURES]
Definition r_image.cpp:50
int r_numImages
Definition r_image.cpp:41
void R_InitImages(void)
Definition r_image.cpp:774
image_t * R_LoadImageData(const char *name, const byte *pic, int width, int height, imagetype_t type)
Creates a new image from RGBA data. Stores it in the gltextures array and also uploads it.
Definition r_image.cpp:475
void R_UploadAlpha(const image_t *image, const byte *alphaData)
Definition r_image.cpp:423
static image_t * imageHash[MAX_IMAGEHASH]
Definition r_image.cpp:32
void R_TextureSolidMode(const char *string)
Definition r_image.cpp:966
int R_GetImageIndex(image_t *imagePtr)
Returns an index of the image pointer in the r_images linked list, as if r_images would be a plain co...
Definition r_image.cpp:702
void R_ImageClearMaterials(void)
Free previously loaded materials and their stages.
Definition r_image.cpp:61
static const gltmode_t gl_alpha_modes[]
Definition r_image.cpp:916
void R_LoadImage(const char *name, byte **pic, int *width, int *height)
Generic image-data loading fucntion.
Definition r_image.cpp:152
image_t * R_RenderToTexture(const char *name, int x, int y, int w, int h)
Definition r_image.cpp:547
void R_ScaleTexture(const unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
Definition r_image.cpp:172
imageArray_t r_images
Definition r_image.cpp:40
const image_t * R_FindPics(const char *name)
Searches for an image in the image array.
Definition r_image.cpp:673
image_t * r_flaretextures[NUM_FLARETEXTURES]
Definition r_image.cpp:53
#define FOR_EACH_IMAGE(i, image, imageArray)
Definition r_image.cpp:44
void R_ShutdownImages(void)
Definition r_image.cpp:796
bool R_ImageExists(const char *pname,...)
Definition r_image.cpp:681
static void R_DeleteImage(image_t *image)
Definition r_image.cpp:435
static bool R_IsClampedImageType(imagetype_t type)
Definition r_image.cpp:241
void R_TextureMode(const char *string)
Definition r_image.cpp:869
image_t * R_GetImage(const char *name)
Definition r_image.cpp:452
static void R_ReloadImageData(image_t *image)
Definition r_image.cpp:814
void R_UploadTexture(const unsigned *data, int width, int height, image_t *image)
Uploads the opengl texture to the server.
Definition r_image.cpp:262
#define MAX_ENVMAPTEXTURES
Definition r_image.h:111
#define NUM_FLARETEXTURES
Definition r_image.h:114
#define MAX_GL_TEXTURES
Definition r_image.h:76
image_t * r_noTexture
Definition r_main.cpp:51
imagetype_t
Definition r_image.h:41
@ it_pic
Definition r_image.h:45
@ it_material
Definition r_image.h:57
@ it_world
Definition r_image.h:54
@ it_effect
Definition r_image.h:43
@ it_roughnessmap
Definition r_image.h:51
@ it_skin
Definition r_image.h:47
@ it_worldrelated
Definition r_image.h:58
@ it_static
Definition r_image.h:44
@ it_specularmap
Definition r_image.h:50
@ it_normalmap
Definition r_image.h:48
@ it_chars
Definition r_image.h:42
@ it_glowmap
Definition r_image.h:49
@ it_wrappic
Definition r_image.h:46
@ it_lightmap
Definition r_image.h:55
local graphics definitions
rconfig_t r_config
Definition r_main.cpp:47
cvar_t * r_texture_lod
Definition r_main.cpp:65
material_t defaultMaterial
bool R_SelectTexture(gltexunit_t *texunit)
Returns false if the texunit is not supported.
Definition r_state.cpp:40
#define texunit_diffuse
Definition r_state.h:68
#define R_BindTexture(tn)
Definition r_state.h:184
#define Q_strcasecmp(a, b)
Definition shared.h:131
#define Q_streq(a, b)
Definition shared.h:136
bool Q_strnull(const char *string)
Definition shared.h:138
#define OBJZERO(obj)
Definition shared.h:178
#define lengthof(x)
Definition shared.h:105
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
unsigned int Com_HashKey(const char *name, int hashsize)
returns hash key for a string
Definition shared.cpp:336
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition shared.cpp:535
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
const char * name
Definition r_image.cpp:856
const char * name
Definition r_image.cpp:912
int upload_height
Definition r_image.h:65
char name[MAX_QPATH]
Definition r_image.h:62
int upload_width
Definition r_image.h:65
struct image_s * hash_next
Definition r_image.h:73
int height
Definition r_image.h:64
struct image_s * specularmap
Definition r_image.h:71
int width
Definition r_image.h:64
struct image_s * roughnessmap
Definition r_image.h:72
GLuint texnum
Definition r_image.h:66
struct image_s * normalmap
Definition r_image.h:69
bool has_alpha
Definition r_image.h:67
struct image_s * glowmap
Definition r_image.h:70
material_t material
Definition r_image.h:68
imagetype_t type
Definition r_image.h:63
image_t images[IMAGE_ARRAY_SIZE]
Definition r_image.cpp:36
struct imageArray_s * next
Definition r_image.cpp:37
struct materialStage_s * next
Definition r_material.h:147