1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21 // draw.c -- this is the only file outside the refresh that touches the
22 // vid buffer
23
24 #include "quakedef.h"
25
26 #define GL_COLOR_INDEX8_EXT 0x80E5
27
28
29 cvar_t gl_nobind = CVAR2("gl_nobind", "0");
30 cvar_t gl_max_size = CVAR2("gl_max_size", "1024");
31 cvar_t gl_picmip = CVAR2("gl_picmip", "0");
32
33 byte *draw_chars; // 8*8 graphic characters
34 qpic_t *draw_disc;
35 qpic_t *draw_backtile;
36
37 int translate_texture;
38 int char_texture;
39
40 typedef struct
41 {
42 int texnum;
43 float sl, tl, sh, th;
44 } glpic_t;
45
46 typedef union
47 {
48 qpic_t qpic;
49 struct {
50 // First part is from qpic
51 int width;
52 int height;
53
54 glpic_t glpic;
55 } g;
56 } packedGlpic_t;
57
58 typedef union
59 {
60 byte buffer[sizeof(qpic_t) + sizeof(glpic_t)];
61 packedGlpic_t pics;
62 } conback_t;
63
64 conback_t conbackUnion;
65
66 #define conback_buffer (conbackUnion.buffer)
67 packedGlpic_t *conback = &conbackUnion.pics;
68
69 int gl_lightmap_format = 4;
70 int gl_solid_format = 3;
71 int gl_alpha_format = 4;
72
73 #if 1 // Standard defaults
74 int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
75 int gl_filter_max = GL_LINEAR;
76 #else
77 int gl_filter_min = GL_NEAREST_MIPMAP_NEAREST;
78 int gl_filter_max = GL_NEAREST;
79 #endif
80
81 int texels;
82
83 typedef struct
84 {
85 int texnum;
86 char identifier[64];
87 int width, height;
88 qboolean mipmap;
89 } gltexture_t;
90
91 #define MAX_GLTEXTURES 1024
92 gltexture_t gltextures[MAX_GLTEXTURES];
93 int numgltextures;
94
95 // GlQuake creates textures, but never deletes them. This approach works fine on
96 // computers with lots of RAM and/or swap, but not so well on our swapless
97 // RAM-constrained system.
98 //
99 // We work around this problem by adding a level of indirection. We
100 // hook GL_LoadTexture to store enough information to recreate a texture.
101 // Then we hook GL_BindTexture to consult a table to see whether a texture
102 // is currently in memory or not. If it isn't, we throw out some other
103 // texture and bring the required texture back into memory. In this way
104 // we can limit the working set of textures.
105 //
106 // The texture data is stored in a memory-mapped file that is backed by
107 // a file on the sd card. It is recreated each time the game is run. We
108 // don't bother deleting it.
109
110 #define USE_TEXTURE_STORE
111
112 #ifdef USE_TEXTURE_STORE
113
114 #include <unistd.h>
115 #include <sys/types.h>
116 #include <sys/mman.h>
117 #include <fcntl.h>
118 #include <errno.h>
119
120 // Allow named textures to be evicted from memory.
121
122 #define TEXTURE_STORE_NAME "glquake/texture.store"
123
124 class textureStore {
125
126 private:
127 static const GLuint UNUSED = (GLuint) -2;
128 static const GLuint PAGED_OUT = (GLuint) -1;
129
130 struct entry
131 {
132 entry* next;
133 entry* prev;
134 GLuint real_texnum; // UNUSED, PAGED_OUT
135 byte* pData; // 0 ==> not created by us.
136 size_t size;
137 qboolean alpha;
138 int width;
139 int height;
140 qboolean mipmap;
141
entrytextureStore::entry142 entry() {
143 next = 0;
144 prev = 0;
145 real_texnum = UNUSED;
146 pData = 0;
147 }
148
149
unlinktextureStore::entry150 void unlink() {
151 if (next) {
152 next->prev = prev;
153 }
154 if (prev) {
155 prev->next = next;
156 }
157 next = 0;
158 prev = 0;
159 }
160
insertBeforetextureStore::entry161 void insertBefore(entry* e){
162 if (e) {
163 prev = e->prev;
164 if ( prev ) {
165 prev->next = this;
166 }
167 next = e;
168 e->prev = this;
169 }
170 else {
171 prev = 0;
172 next = 0;
173 }
174 }
175 };
176
177 public:
178
get()179 static textureStore* get() {
180 if (g_pTextureCache == 0) {
181 g_pTextureCache = new textureStore();
182 }
183 return g_pTextureCache;
184 }
185
186 // Equivalent of glBindTexture, but uses the virtual texture table
187
bind(int virtTexNum)188 void bind(int virtTexNum) {
189 if ( (unsigned int) virtTexNum >= TEXTURE_STORE_NUM_TEXTURES) {
190 Sys_Error("not in the range we're managing");
191 }
192 mBoundTextureID = virtTexNum;
193 entry* e = &mTextures[virtTexNum];
194
195 if ( e->real_texnum == UNUSED) {
196 glGenTextures( 1, &e->real_texnum);
197 }
198
199 if ( e->pData == 0) {
200 glBindTexture(GL_TEXTURE_2D, e->real_texnum);
201 return;
202 }
203
204 update(e);
205 }
206
update(entry * e)207 void update(entry* e)
208 {
209 // Update the "LRU" part of the cache
210 unlink(e);
211 e->insertBefore(mFirst);
212 mFirst = e;
213 if (! mLast) {
214 mLast = e;
215 }
216
217 if (e->real_texnum == PAGED_OUT ) {
218 // Create a real texture
219 // Make sure there is enough room for this texture
220 ensure(e->size);
221
222 glGenTextures( 1, &e->real_texnum);
223
224 glBindTexture(GL_TEXTURE_2D, e->real_texnum);
225 GL_Upload8 (e->pData, e->width, e->height, e->mipmap,
226 e->alpha);
227 }
228 else {
229 glBindTexture(GL_TEXTURE_2D, e->real_texnum);
230 }
231 }
232
233 // Create a texture, and remember the data so we can create
234 // it again later.
235
create(int width,int height,byte * data,qboolean mipmap,qboolean alpha)236 void create(int width, int height, byte* data, qboolean mipmap,
237 qboolean alpha) {
238 int size = width * height;
239 if (size + mLength > mCapacity) {
240 Sys_Error("Ran out of virtual texture space. %d", size);
241 };
242 entry* e = &mTextures[mBoundTextureID];
243
244 // Call evict in case the currently bound texture id is already
245 // in use. (Shouldn't happen in Quake.)
246 // To Do: reclaim the old texture memory from the virtual memory.
247
248 evict(e);
249
250 e->alpha = alpha;
251 e->pData = mBase + mLength;
252 memcpy(e->pData, data, size);
253 e->size = size;
254 e->width = width;
255 e->height = height;
256 e->mipmap = mipmap;
257 e->real_texnum = PAGED_OUT;
258 mLength += size;
259
260 update(e);
261 }
262
263 // Re-upload the current textures because we've been reset.
rebindAll()264 void rebindAll() {
265 grabMagicTextureIds();
266 for (entry* e = mFirst; e; e = e->next ) {
267 if (! (e->real_texnum == UNUSED || e->real_texnum == PAGED_OUT)) {
268 glBindTexture(GL_TEXTURE_2D, e->real_texnum);
269 if (e->pData) {
270 GL_Upload8 (e->pData, e->width, e->height, e->mipmap,
271 e->alpha);
272 }
273 }
274 }
275 }
276
277 private:
278
textureStore()279 textureStore() {
280 grabMagicTextureIds();
281 mFirst = 0;
282 mLast = 0;
283 mTextureCount = 0;
284
285 char fullpath[MAX_OSPATH];
286 sprintf(fullpath, "%s/%s", com_gamedir, TEXTURE_STORE_NAME);
287
288 mFileId = open(fullpath, O_RDWR | O_CREAT, 0666);
289 if ( mFileId == -1 ) {
290 Sys_Error("Could not open texture store file %s: %d", fullpath,
291 errno);
292 }
293
294 if (-1 == lseek(mFileId, TEXTURE_STORE_SIZE-1, SEEK_SET)) {
295 Sys_Error("Could not extend the texture store file size. %d",
296 errno);
297 }
298 char end;
299 end = 0;
300 if (-1 == write(mFileId, &end, 1)) {
301 Sys_Error("Could not write last byte of the texture store file. %d",
302 errno);
303 }
304
305 mBase = (byte*) mmap((caddr_t)0, TEXTURE_STORE_SIZE,
306 PROT_READ | PROT_WRITE, MAP_PRIVATE, mFileId, 0);
307
308 if (mBase == (byte*) -1) {
309 Sys_Error("Could not mmap file %s: %d", fullpath, errno);
310 }
311 mLength = 0;
312 mCapacity = TEXTURE_STORE_SIZE;
313 mRamUsed = 0;
314 mRamSize = LIVE_TEXTURE_LIMIT;
315 }
316
~textureStore()317 ~textureStore() {
318 munmap(mBase, mCapacity);
319 COM_CloseFile(mFileId);
320 }
321
grabMagicTextureIds()322 void grabMagicTextureIds() {
323 // reserve these two texture ids.
324 glBindTexture(GL_TEXTURE_2D, UNUSED);
325 glBindTexture(GL_TEXTURE_2D, PAGED_OUT);
326 }
327
unlink(entry * e)328 void unlink(entry* e) {
329 if (e == mFirst) {
330 mFirst = e->next;
331 }
332 if (e == mLast) {
333 mLast = e->prev;
334 }
335 e->unlink();
336 }
337
ensure(int size)338 void ensure(int size) {
339 while ( mRamSize - mRamUsed < (unsigned int) size) {
340 entry* e = mLast;
341 if(! e) {
342 Sys_Error("Ran out of entries");
343 return;
344 }
345 evict(e);
346 }
347 mRamUsed += size;
348 }
349
evict(entry * e)350 void evict(entry* e) {
351 unlink(e);
352 if ( e->pData ) {
353 glDeleteTextures(1, &e->real_texnum);
354 e->real_texnum = PAGED_OUT;
355 mRamUsed -= e->size;
356 }
357 }
358
359 static const size_t TEXTURE_STORE_SIZE = 16 * 1024 * 1024;
360 static const size_t LIVE_TEXTURE_LIMIT = 1 * 1024 * 1024;
361 static const size_t TEXTURE_STORE_NUM_TEXTURES = 512;
362
363 int mFileId;
364 byte* mBase; // Base address of the memory mapped file
365 size_t mLength; // How much of the mm file we are currently using
366 size_t mCapacity; // Total size of the memory mapped file
367
368 // Keep track of texture RAM.
369 size_t mRamUsed;
370 size_t mRamSize;
371
372 // The virtual textures
373
374
375 entry mTextures[MAX_GLTEXTURES];
376 entry* mFirst; // LRU queue
377 entry* mLast;
378 size_t mTextureCount; // How many virtual textures have been allocated
379
380 static textureStore* g_pTextureCache;
381
382 int mBoundTextureID;
383 };
384
385 textureStore* textureStore::g_pTextureCache;
386
387 #endif
388
389
GL_Bind(int texnum)390 void GL_Bind (int texnum)
391 {
392 if (gl_nobind.value)
393 texnum = char_texture;
394 if (currenttexture == texnum)
395 return;
396 currenttexture = texnum;
397 #ifdef _WIN32
398 bindTexFunc (GL_TEXTURE_2D, texnum);
399 #else
400
401 #ifdef USE_TEXTURE_STORE
402 textureStore::get()->bind(texnum);
403 #else
404 glBindTexture(GL_TEXTURE_2D, texnum);
405 #endif
406
407 #endif
408 }
409
410
411 /*
412 =============================================================================
413
414 scrap allocation
415
416 Allocate all the little status bar obejcts into a single texture
417 to crutch up stupid hardware / drivers
418
419 =============================================================================
420 */
421
422 #define MAX_SCRAPS 2
423 #define BLOCK_WIDTH 256
424 #define BLOCK_HEIGHT 256
425
426 int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
427 byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
428 qboolean scrap_dirty;
429 int scrap_texnum;
430
431 // returns a texture number and the position inside it
Scrap_AllocBlock(int w,int h,int * x,int * y)432 int Scrap_AllocBlock (int w, int h, int *x, int *y)
433 {
434 int i, j;
435 int best, best2;
436 int bestx;
437 int texnum;
438
439 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
440 {
441 best = BLOCK_HEIGHT;
442
443 for (i=0 ; i<BLOCK_WIDTH-w ; i++)
444 {
445 best2 = 0;
446
447 for (j=0 ; j<w ; j++)
448 {
449 if (scrap_allocated[texnum][i+j] >= best)
450 break;
451 if (scrap_allocated[texnum][i+j] > best2)
452 best2 = scrap_allocated[texnum][i+j];
453 }
454 if (j == w)
455 { // this is a valid spot
456 *x = i;
457 *y = best = best2;
458 }
459 }
460
461 if (best + h > BLOCK_HEIGHT)
462 continue;
463
464 for (i=0 ; i<w ; i++)
465 scrap_allocated[texnum][*x + i] = best + h;
466
467 return texnum;
468 }
469
470 Sys_Error ("Scrap_AllocBlock: full");
471 return 0;
472 }
473
474 int scrap_uploads;
475
Scrap_Upload(void)476 void Scrap_Upload (void)
477 {
478 int texnum;
479
480 scrap_uploads++;
481
482 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) {
483 GL_Bind(scrap_texnum + texnum);
484 GL_Upload8 (scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
485 }
486 scrap_dirty = false;
487 }
488
489 //=============================================================================
490 /* Support Routines */
491
492 typedef struct cachepic_s
493 {
494 char name[MAX_QPATH];
495 qpic_t pic;
496 byte padding[32]; // for appended glpic
497 } cachepic_t;
498
499 #define MAX_CACHED_PICS 128
500 cachepic_t menu_cachepics[MAX_CACHED_PICS];
501 int menu_numcachepics;
502
503 byte menuplyr_pixels[4096];
504
505 int pic_texels;
506 int pic_count;
507
508
509 /*
510 ================
511 GL_LoadPicTexture
512 ================
513 */
GL_LoadPicTexture(qpic_t * pic)514 int GL_LoadPicTexture (qpic_t *pic)
515 {
516 return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
517 }
518
519
Draw_PicFromWad(const char * name)520 qpic_t *Draw_PicFromWad (const char *name)
521 {
522 packedGlpic_t *pp;
523
524 pp = (packedGlpic_t*) W_GetLumpName (name);
525
526 qpic_t* p = & pp->qpic;
527 glpic_t* gl = & pp->g.glpic;
528
529 // load little ones into the scrap
530 if (p->width < 64 && p->height < 64)
531 {
532 int x, y;
533 int i, j, k;
534 int texnum;
535
536 texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
537 scrap_dirty = true;
538 k = 0;
539 for (i=0 ; i<p->height ; i++)
540 for (j=0 ; j<p->width ; j++, k++)
541 scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
542 texnum += scrap_texnum;
543 gl->texnum = texnum;
544 gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
545 gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
546 gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
547 gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
548
549 pic_count++;
550 pic_texels += p->width*p->height;
551 }
552 else
553 {
554 gl->texnum = GL_LoadPicTexture (p);
555 gl->sl = 0;
556 gl->sh = 1;
557 gl->tl = 0;
558 gl->th = 1;
559 }
560 return p;
561 }
562
563
564 /*
565 ================
566 Draw_CachePic
567 ================
568 */
Draw_CachePic(const char * path)569 qpic_t *Draw_CachePic (const char *path)
570 {
571 cachepic_t *pic;
572 int i;
573 qpic_t *dat;
574 glpic_t *gl;
575
576 for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
577 if (!strcmp (path, pic->name))
578 return &pic->pic;
579
580 if (menu_numcachepics == MAX_CACHED_PICS)
581 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
582 menu_numcachepics++;
583 strcpy (pic->name, path);
584
585 //
586 // load the pic from disk
587 //
588 dat = (qpic_t *)COM_LoadTempFile (path);
589 if (!dat)
590 Sys_Error ("Draw_CachePic: failed to load %s", path);
591 SwapPic (dat);
592
593 // HACK HACK HACK --- we need to keep the bytes for
594 // the translatable player picture just for the menu
595 // configuration dialog
596 if (!strcmp (path, "gfx/menuplyr.lmp"))
597 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
598
599 pic->pic.width = dat->width;
600 pic->pic.height = dat->height;
601
602 glpic_t temp;
603 gl = &temp;
604 gl->texnum = GL_LoadPicTexture (dat);
605 gl->sl = 0;
606 gl->sh = 1;
607 gl->tl = 0;
608 gl->th = 1;
609
610 memcpy(pic->pic.data, &temp, sizeof(temp));
611
612 return &pic->pic;
613 }
614
615
Draw_CharToConback(int num,byte * dest)616 void Draw_CharToConback (int num, byte *dest)
617 {
618 int row, col;
619 byte *source;
620 int drawline;
621 int x;
622
623 row = num>>4;
624 col = num&15;
625 source = draw_chars + (row<<10) + (col<<3);
626
627 drawline = 8;
628
629 while (drawline--)
630 {
631 for (x=0 ; x<8 ; x++)
632 if (source[x] != 255)
633 dest[x] = 0x60 + source[x];
634 source += 128;
635 dest += 320;
636 }
637
638 }
639
640 typedef struct
641 {
642 const char *name;
643 int minimize, maximize;
644 } glmode_t;
645
646 glmode_t modes[] = {
647 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
648 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
649 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
650 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
651 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
652 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
653 };
654
655 /*
656 ===============
657 Draw_TextureMode_f
658 ===============
659 */
Draw_TextureMode_f(void)660 void Draw_TextureMode_f (void)
661 {
662 int i;
663 gltexture_t *glt;
664
665 if (Cmd_Argc() == 1)
666 {
667 for (i=0 ; i< 6 ; i++)
668 if (gl_filter_min == modes[i].minimize)
669 {
670 Con_Printf ("%s\n", modes[i].name);
671 return;
672 }
673 Con_Printf ("current filter is unknown???\n");
674 return;
675 }
676
677 for (i=0 ; i< 6 ; i++)
678 {
679 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
680 break;
681 }
682 if (i == 6)
683 {
684 Con_Printf ("bad filter name\n");
685 return;
686 }
687
688 gl_filter_min = modes[i].minimize;
689 gl_filter_max = modes[i].maximize;
690
691 // change all the existing mipmap texture objects
692 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
693 {
694 if (glt->mipmap)
695 {
696 GL_Bind (glt->texnum);
697 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
698 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
699 }
700 }
701 }
702
703 /*
704 ===============
705 Draw_Init
706 ===============
707 */
Draw_Init(void)708 void Draw_Init (void)
709 {
710 int i;
711 qpic_t *cb;
712 byte *dest, *src;
713 int x, y;
714 char ver[40];
715 glpic_t *gl;
716 int start;
717 byte *ncdata;
718 int f, fstep;
719
720
721 Cvar_RegisterVariable (&gl_nobind);
722 Cvar_RegisterVariable (&gl_max_size);
723 Cvar_RegisterVariable (&gl_picmip);
724
725 // 3dfx can only handle 256 wide textures
726 if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
727 strstr((char *)gl_renderer, "Glide"))
728 Cvar_Set ("gl_max_size", "256");
729
730 Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
731
732 // load the console background and the charset
733 // by hand, because we need to write the version
734 // string into the background before turning
735 // it into a texture
736 draw_chars = (byte*) W_GetLumpName ("conchars");
737 for (i=0 ; i<256*64 ; i++)
738 if (draw_chars[i] == 0)
739 draw_chars[i] = 255; // proper transparent color
740
741 // now turn them into textures
742 char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
743
744 start = Hunk_LowMark();
745
746 cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp");
747 if (!cb)
748 Sys_Error ("Couldn't load gfx/conback.lmp");
749 SwapPic (cb);
750
751 // hack the version number directly into the pic
752 #if defined(__linux__)
753 sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
754 #else
755 sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION);
756 #endif
757 dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);
758 y = strlen(ver);
759 for (x=0 ; x<y ; x++)
760 Draw_CharToConback (ver[x], dest+(x<<3));
761
762 #if 0
763 conback->width = vid.conwidth;
764 conback->height = vid.conheight;
765
766 // scale console to vid size
767 dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback");
768
769 for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth)
770 {
771 src = cb->data + cb->width * (y*cb->height/vid.conheight);
772 if (vid.conwidth == cb->width)
773 memcpy (dest, src, vid.conwidth);
774 else
775 {
776 f = 0;
777 fstep = cb->width*0x10000/vid.conwidth;
778 for (x=0 ; x<vid.conwidth ; x+=4)
779 {
780 dest[x] = src[f>>16];
781 f += fstep;
782 dest[x+1] = src[f>>16];
783 f += fstep;
784 dest[x+2] = src[f>>16];
785 f += fstep;
786 dest[x+3] = src[f>>16];
787 f += fstep;
788 }
789 }
790 }
791 #else
792 conback->g.width = cb->width;
793 conback->g.height = cb->height;
794 ncdata = cb->data;
795 #endif
796
797 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
798 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
799
800 gl = &conback->g.glpic;
801 gl->texnum = GL_LoadTexture ("conback", conback->g.width, conback->g.height, ncdata, false, false);
802 gl->sl = 0;
803 gl->sh = 1;
804 gl->tl = 0;
805 gl->th = 1;
806 conback->g.width = vid.width;
807 conback->g.height = vid.height;
808
809 // free loaded console
810 Hunk_FreeToLowMark(start);
811
812 // save a texture slot for translated picture
813 translate_texture = texture_extension_number++;
814
815 // save slots for scraps
816 scrap_texnum = texture_extension_number;
817 texture_extension_number += MAX_SCRAPS;
818
819 //
820 // get the other pics we need
821 //
822 draw_disc = Draw_PicFromWad ("disc");
823 draw_backtile = Draw_PicFromWad ("backtile");
824 }
825
826
827
828 /*
829 ================
830 Draw_Character
831
832 Draws one 8*8 graphics character with 0 being transparent.
833 It can be clipped to the top of the screen to allow the console to be
834 smoothly scrolled off.
835 ================
836 */
Draw_Character(int x,int y,int num)837 void Draw_Character (int x, int y, int num)
838 {
839 byte *dest;
840 byte *source;
841 unsigned short *pusdest;
842 int drawline;
843 int row, col;
844 float frow, fcol, size;
845
846 if (num == 32)
847 return; // space
848
849 num &= 255;
850
851 if (y <= -8)
852 return; // totally off screen
853
854 row = num>>4;
855 col = num&15;
856
857 frow = row*0.0625;
858 fcol = col*0.0625;
859 size = 0.0625;
860
861 GL_Bind (char_texture);
862
863 #ifdef USE_OPENGLES
864 DrawQuad(x, y, 8, 8, fcol, frow, size, size);
865 #else
866 glBegin (GL_QUADS);
867 glTexCoord2f (fcol, frow);
868 glVertex2f (x, y);
869 glTexCoord2f (fcol + size, frow);
870 glVertex2f (x+8, y);
871 glTexCoord2f (fcol + size, frow + size);
872 glVertex2f (x+8, y+8);
873 glTexCoord2f (fcol, frow + size);
874 glVertex2f (x, y+8);
875 glEnd ();
876 #endif
877 }
878
879 /*
880 ================
881 Draw_String
882 ================
883 */
Draw_String(int x,int y,const char * str)884 void Draw_String (int x, int y, const char *str)
885 {
886 while (*str)
887 {
888 Draw_Character (x, y, *str);
889 str++;
890 x += 8;
891 }
892 }
893
894 /*
895 ================
896 Draw_DebugChar
897
898 Draws a single character directly to the upper right corner of the screen.
899 This is for debugging lockups by drawing different chars in different parts
900 of the code.
901 ================
902 */
Draw_DebugChar(char num)903 void Draw_DebugChar (char num)
904 {
905 }
906
907 /*
908 =============
909 Draw_AlphaPic
910 =============
911 */
Draw_AlphaPic(int x,int y,packedGlpic_t * ppic,float alpha)912 void Draw_AlphaPic (int x, int y, packedGlpic_t *ppic, float alpha)
913 {
914 byte *dest, *source;
915 unsigned short *pusdest;
916 int v, u;
917 glpic_t *gl;
918
919 if (scrap_dirty)
920 Scrap_Upload ();
921 gl = & ppic->g.glpic;
922 glDisable(GL_ALPHA_TEST);
923 glEnable (GL_BLEND);
924 // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
925 // glCullFace(GL_FRONT);
926 glColor4f (1,1,1,alpha);
927 GL_Bind (gl->texnum);
928 #ifdef USE_OPENGLES
929 DrawQuad(x, y, ppic->g.width, ppic->g.height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
930 #else
931 glBegin (GL_QUADS);
932 glTexCoord2f (gl->sl, gl->tl);
933 glVertex2f (x, y);
934 glTexCoord2f (gl->sh, gl->tl);
935 glVertex2f (x+pic->width, y);
936 glTexCoord2f (gl->sh, gl->th);
937 glVertex2f (x+pic->width, y+pic->height);
938 glTexCoord2f (gl->sl, gl->th);
939 glVertex2f (x, y+pic->height);
940 glEnd ();
941 #endif
942 glColor4f (1,1,1,1);
943 glEnable(GL_ALPHA_TEST);
944 glDisable (GL_BLEND);
945 }
946
947
948 /*
949 =============
950 Draw_Pic
951 =============
952 */
Draw_Pic(int x,int y,qpic_t * pic)953 void Draw_Pic (int x, int y, qpic_t *pic)
954 {
955 byte *dest, *source;
956 unsigned short *pusdest;
957 int v, u;
958 glpic_t *gl;
959
960 if (scrap_dirty)
961 Scrap_Upload ();
962 glpic_t temp;
963 memcpy(&temp, pic->data, sizeof(temp));
964 gl = & temp;
965 glColor4f (1,1,1,1);
966 GL_Bind (gl->texnum);
967 #ifdef USE_OPENGLES
968 DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
969 #else
970 glBegin (GL_QUADS);
971 glTexCoord2f (gl->sl, gl->tl);
972 glVertex2f (x, y);
973 glTexCoord2f (gl->sh, gl->tl);
974 glVertex2f (x+pic->width, y);
975 glTexCoord2f (gl->sh, gl->th);
976 glVertex2f (x+pic->width, y+pic->height);
977 glTexCoord2f (gl->sl, gl->th);
978 glVertex2f (x, y+pic->height);
979 glEnd ();
980 #endif
981 }
982
983
984 /*
985 =============
986 Draw_TransPic
987 =============
988 */
Draw_TransPic(int x,int y,qpic_t * pic)989 void Draw_TransPic (int x, int y, qpic_t *pic)
990 {
991 byte *dest, *source, tbyte;
992 unsigned short *pusdest;
993 int v, u;
994
995 if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
996 (unsigned)(y + pic->height) > vid.height)
997 {
998 Sys_Error ("Draw_TransPic: bad coordinates");
999 }
1000
1001 Draw_Pic (x, y, pic);
1002 }
1003
1004
1005 /*
1006 =============
1007 Draw_TransPicTranslate
1008
1009 Only used for the player color selection menu
1010 =============
1011 */
Draw_TransPicTranslate(int x,int y,qpic_t * pic,byte * translation)1012 void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
1013 {
1014 int v, u, c;
1015 unsigned trans[64*64], *dest;
1016 byte *src;
1017 int p;
1018
1019 GL_Bind (translate_texture);
1020
1021 c = pic->width * pic->height;
1022
1023 dest = trans;
1024 for (v=0 ; v<64 ; v++, dest += 64)
1025 {
1026 src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
1027 for (u=0 ; u<64 ; u++)
1028 {
1029 p = src[(u*pic->width)>>6];
1030 if (p == 255)
1031 dest[u] = p;
1032 else
1033 dest[u] = d_8to24table[translation[p]];
1034 }
1035 }
1036
1037 glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
1038
1039 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1040 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1041
1042 glColor3f (1,1,1);
1043 #ifdef USE_OPENGLES
1044 DrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1);
1045 #else
1046 glBegin (GL_QUADS);
1047 glTexCoord2f (0, 0);
1048 glVertex2f (x, y);
1049 glTexCoord2f (1, 0);
1050 glVertex2f (x+pic->width, y);
1051 glTexCoord2f (1, 1);
1052 glVertex2f (x+pic->width, y+pic->height);
1053 glTexCoord2f (0, 1);
1054 glVertex2f (x, y+pic->height);
1055 glEnd ();
1056 #endif
1057 }
1058
1059
1060 /*
1061 ================
1062 Draw_ConsoleBackground
1063
1064 ================
1065 */
Draw_ConsoleBackground(int lines)1066 void Draw_ConsoleBackground (int lines)
1067 {
1068 int y = (vid.height * 3) >> 2;
1069
1070 if (lines > y)
1071 Draw_Pic(0, lines - vid.height, &conback->qpic);
1072 else
1073 Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
1074 }
1075
1076
1077 /*
1078 =============
1079 Draw_TileClear
1080
1081 This repeats a 64*64 tile graphic to fill the screen around a sized down
1082 refresh window.
1083 =============
1084 */
1085
1086 typedef union ByteToInt_t {
1087 byte b[4];
1088 int i;
1089 } ByteToInt;
1090
Draw_TileClear(int x,int y,int w,int h)1091 void Draw_TileClear (int x, int y, int w, int h)
1092 {
1093 glColor3f (1,1,1);
1094 ByteToInt b;
1095 memcpy(b.b, draw_backtile->data, sizeof(b.b));
1096 GL_Bind (b.i);
1097 #ifdef USE_OPENGLES
1098 DrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0);
1099 #else
1100 glBegin (GL_QUADS);
1101 glTexCoord2f (x/64.0, y/64.0);
1102 glVertex2f (x, y);
1103 glTexCoord2f ( (x+w)/64.0, y/64.0);
1104 glVertex2f (x+w, y);
1105 glTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
1106 glVertex2f (x+w, y+h);
1107 glTexCoord2f ( x/64.0, (y+h)/64.0 );
1108 glVertex2f (x, y+h);
1109 glEnd ();
1110 #endif
1111 }
1112
1113
1114 /*
1115 =============
1116 Draw_Fill
1117
1118 Fills a box of pixels with a single color
1119 =============
1120 */
Draw_Fill(int x,int y,int w,int h,int c)1121 void Draw_Fill (int x, int y, int w, int h, int c)
1122 {
1123 glDisable (GL_TEXTURE_2D);
1124 glColor3f (host_basepal[c*3]/255.0,
1125 host_basepal[c*3+1]/255.0,
1126 host_basepal[c*3+2]/255.0);
1127
1128 #ifdef USE_OPENGLES
1129 DrawQuad_NoTex(x, y, w, h);
1130 #else
1131 glBegin (GL_QUADS);
1132
1133 glVertex2f (x,y);
1134 glVertex2f (x+w, y);
1135 glVertex2f (x+w, y+h);
1136 glVertex2f (x, y+h);
1137
1138 glEnd ();
1139 #endif
1140 glColor3f (1,1,1);
1141 glEnable (GL_TEXTURE_2D);
1142 }
1143 //=============================================================================
1144
1145 /*
1146 ================
1147 Draw_FadeScreen
1148
1149 ================
1150 */
Draw_FadeScreen(void)1151 void Draw_FadeScreen (void)
1152 {
1153 glEnable (GL_BLEND);
1154 glDisable (GL_TEXTURE_2D);
1155 glColor4f (0, 0, 0, 0.8);
1156 #ifdef USE_OPENGLES
1157 DrawQuad_NoTex(0, 0, vid.width, vid.height);
1158 #else
1159 glBegin (GL_QUADS);
1160
1161 glVertex2f (0,0);
1162 glVertex2f (vid.width, 0);
1163 glVertex2f (vid.width, vid.height);
1164 glVertex2f (0, vid.height);
1165
1166 glEnd ();
1167 #endif
1168 glColor4f (1,1,1,1);
1169 glEnable (GL_TEXTURE_2D);
1170 glDisable (GL_BLEND);
1171
1172 Sbar_Changed();
1173 }
1174
1175 //=============================================================================
1176
1177 /*
1178 ================
1179 Draw_BeginDisc
1180
1181 Draws the little blue disc in the corner of the screen.
1182 Call before beginning any disc IO.
1183 ================
1184 */
Draw_BeginDisc(void)1185 void Draw_BeginDisc (void)
1186 {
1187 if (!draw_disc)
1188 return;
1189 #ifdef USE_OPENGLES
1190 // !!! Implement this
1191 #else
1192 glDrawBuffer (GL_FRONT);
1193 Draw_Pic (vid.width - 24, 0, draw_disc);
1194 glDrawBuffer (GL_BACK);
1195 #endif
1196 }
1197
1198
1199 /*
1200 ================
1201 Draw_EndDisc
1202
1203 Erases the disc icon.
1204 Call after completing any disc IO
1205 ================
1206 */
Draw_EndDisc(void)1207 void Draw_EndDisc (void)
1208 {
1209 }
1210
1211 /*
1212 ================
1213 GL_Set2D
1214
1215 Setup as if the screen was 320*200
1216 ================
1217 */
GL_Set2D(void)1218 void GL_Set2D (void)
1219 {
1220 glViewport (glx, gly, glwidth, glheight);
1221
1222 glMatrixMode(GL_PROJECTION);
1223 glLoadIdentity ();
1224 #ifdef USE_OPENGLES
1225 glOrthof (0, vid.width, vid.height, 0, -99999, 99999);
1226 #else
1227 glOrtho (0, vid.width, vid.height, 0, -99999, 99999);
1228 #endif
1229
1230 glMatrixMode(GL_MODELVIEW);
1231 glLoadIdentity ();
1232
1233 glDisable (GL_DEPTH_TEST);
1234 glDisable (GL_CULL_FACE);
1235 glDisable (GL_BLEND);
1236 glEnable (GL_ALPHA_TEST);
1237 // glDisable (GL_ALPHA_TEST);
1238
1239 glColor4f (1,1,1,1);
1240 }
1241
1242 //====================================================================
1243
1244 /*
1245 ================
1246 GL_FindTexture
1247 ================
1248 */
GL_FindTexture(const char * identifier)1249 int GL_FindTexture (const char *identifier)
1250 {
1251 int i;
1252 gltexture_t *glt;
1253
1254 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
1255 {
1256 if (!strcmp (identifier, glt->identifier))
1257 return gltextures[i].texnum;
1258 }
1259
1260 return -1;
1261 }
1262
1263 /*
1264 ================
1265 GL_ResampleTexture
1266 ================
1267 */
GL_ResampleTexture(unsigned * in,int inwidth,int inheight,unsigned * out,int outwidth,int outheight)1268 void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
1269 {
1270 int i, j;
1271 unsigned *inrow;
1272 unsigned frac, fracstep;
1273
1274 fracstep = inwidth*0x10000/outwidth;
1275 for (i=0 ; i<outheight ; i++, out += outwidth)
1276 {
1277 inrow = in + inwidth*(i*inheight/outheight);
1278 frac = fracstep >> 1;
1279 for (j=0 ; j<outwidth ; j+=4)
1280 {
1281 out[j] = inrow[frac>>16];
1282 frac += fracstep;
1283 out[j+1] = inrow[frac>>16];
1284 frac += fracstep;
1285 out[j+2] = inrow[frac>>16];
1286 frac += fracstep;
1287 out[j+3] = inrow[frac>>16];
1288 frac += fracstep;
1289 }
1290 }
1291 }
1292
1293 /*
1294 ================
1295 GL_Resample8BitTexture -- JACK
1296 ================
1297 */
GL_Resample8BitTexture(unsigned char * in,int inwidth,int inheight,unsigned char * out,int outwidth,int outheight)1298 void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight)
1299 {
1300 int i, j;
1301 unsigned char *inrow;
1302 unsigned frac, fracstep;
1303
1304 fracstep = inwidth*0x10000/outwidth;
1305 for (i=0 ; i<outheight ; i++, out += outwidth)
1306 {
1307 inrow = in + inwidth*(i*inheight/outheight);
1308 frac = fracstep >> 1;
1309 for (j=0 ; j<outwidth ; j+=4)
1310 {
1311 out[j] = inrow[frac>>16];
1312 frac += fracstep;
1313 out[j+1] = inrow[frac>>16];
1314 frac += fracstep;
1315 out[j+2] = inrow[frac>>16];
1316 frac += fracstep;
1317 out[j+3] = inrow[frac>>16];
1318 frac += fracstep;
1319 }
1320 }
1321 }
1322
1323
1324 /*
1325 ================
1326 GL_MipMap
1327
1328 Operates in place, quartering the size of the texture
1329 ================
1330 */
GL_MipMap(byte * in,int width,int height)1331 void GL_MipMap (byte *in, int width, int height)
1332 {
1333 int i, j;
1334 byte *out;
1335
1336 width <<=2;
1337 height >>= 1;
1338 out = in;
1339 for (i=0 ; i<height ; i++, in+=width)
1340 {
1341 for (j=0 ; j<width ; j+=8, out+=4, in+=8)
1342 {
1343 out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
1344 out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
1345 out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
1346 out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
1347 }
1348 }
1349 }
1350
1351 #ifdef SUPPORT_8BIT_MIPMAPGENERATION
1352 /*
1353 ================
1354 GL_MipMap8Bit
1355
1356 Mipping for 8 bit textures
1357
1358 The "in" and "out" arguments can point to the same buffer if desired
1359 ================
1360 */
GL_MipMap8Bit(byte * in,byte * out,int width,int height)1361 void GL_MipMap8Bit (byte *in, byte* out, int width, int height)
1362 {
1363 int i, j;
1364 unsigned short r,g,b;
1365 byte *at1, *at2, *at3, *at4;
1366
1367 // width <<=2;
1368 height >>= 1;
1369 for (i=0 ; i<height ; i++, in+=width)
1370 {
1371 for (j=0 ; j<width ; j+=2, out+=1, in+=2)
1372 {
1373 at1 = (byte *) (d_8to24table + in[0]);
1374 at2 = (byte *) (d_8to24table + in[1]);
1375 at3 = (byte *) (d_8to24table + in[width+0]);
1376 at4 = (byte *) (d_8to24table + in[width+1]);
1377
1378 r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
1379 g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
1380 b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
1381
1382 out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
1383 }
1384 }
1385 }
1386
1387 #endif // SUPPORT_8BIT_MIPMAPGENERATION
1388
glTexImage2DHelper(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid * pixels)1389 void glTexImage2DHelper( GLenum target,
1390 GLint level,
1391 GLint internalformat,
1392 GLsizei width,
1393 GLsizei height,
1394 GLint border,
1395 GLenum format,
1396 GLenum type,
1397 const GLvoid *pixels )
1398 {
1399 // In full OpenGL The internalformat can be 1..4, to indicate how many components of the data are valid.
1400 // OpenGL ES requires the internalformat argument match the format for glTexImage2D.
1401
1402 glTexImage2D(target, level, format, width, height, border, format, type, pixels);
1403 }
1404
1405
1406 // Uncomment to enable manual MipMap generation
1407 #define USE_MANUAL_MIPMAP_GEN
1408
1409 // Uncomment one of the following:
1410
1411 // #define USE_16BPP_WITH_8888_ALPHA
1412 // #define USE_16BPP_WITH_5551_ALPHA // <--- This has bugs on the simulator and the device. (Device has all alpha images invisible.)
1413 #define USE_16BPP_WITH_4444_ALPHA // <--- This has bugs on the simulator, works in device
1414 // #define USE_32BPP
1415 // #define USE_32BPP_MANUAL_MIPMAP_GEN
1416
1417 #ifdef USE_MANUAL_MIPMAP_GEN
1418
average4(unsigned int a,unsigned int b,unsigned int c,unsigned int d,unsigned int shift,unsigned int mask)1419 inline unsigned int average4(unsigned int a, unsigned int b,
1420 unsigned int c, unsigned int d,
1421 unsigned int shift, unsigned int mask) {
1422 unsigned int aElem = (a >> shift) & mask;
1423 unsigned int bElem = (b >> shift) & mask;
1424 unsigned int cElem = (c >> shift) & mask;
1425 unsigned int dElem = (d >> shift) & mask;
1426 unsigned int avgElem = ((aElem + bElem + cElem + dElem) >> 2) & mask;
1427 return avgElem << shift;
1428 }
1429
average2(unsigned int a,unsigned int b,unsigned int shift,unsigned int mask)1430 inline unsigned int average2(unsigned int a, unsigned int b,
1431 unsigned int shift, unsigned int mask) {
1432 unsigned int aElem = (a >> shift) & mask;
1433 unsigned int bElem = (b >> shift) & mask;
1434 unsigned int avgElem = ((aElem + bElem) >> 1) & mask;
1435 return avgElem << shift;
1436 }
1437
average4444(unsigned int a,unsigned int b)1438 inline unsigned int average4444(unsigned int a, unsigned int b) {
1439 return
1440 average2(a,b,0,0xf) |
1441 average2(a,b,4,0xf) |
1442 average2(a,b,8,0xf) |
1443 average2(a,b,12,0xf);
1444 }
1445
average565(unsigned int a,unsigned int b)1446 inline unsigned int average565(unsigned int a, unsigned int b) {
1447 return
1448 average2(a,b,0,0x1f) |
1449 average2(a,b,5,0x3f) |
1450 average2(a,b,11,0x1f);
1451 }
1452
average2_8888(unsigned int a,unsigned int b)1453 inline unsigned int average2_8888(unsigned int a, unsigned int b) {
1454 return
1455 average2(a,b,0,0xff) |
1456 average2(a,b,8,0xff) |
1457 average2(a,b,16,0xff) |
1458 average2(a,b,24,0xff);
1459 }
1460
average4_8888(unsigned int a,unsigned int b,unsigned int c,unsigned int d)1461 inline unsigned int average4_8888(unsigned int a, unsigned int b,
1462 unsigned int c, unsigned int d) {
1463 return
1464 average4(a,b,c,d,0,0xff) |
1465 average4(a,b,c,d,8,0xff) |
1466 average4(a,b,c,d,16,0xff) |
1467 average4(a,b,c,d,24,0xff);
1468 }
1469
1470 #endif
1471
1472 // pData is 8 bpp 32-bit color
1473
1474
sendTexture(int mipLevel,int width,int height,unsigned int * pData,qboolean alpha)1475 void sendTexture(int mipLevel, int width, int height, unsigned int* pData, qboolean alpha) {
1476 if (alpha) {
1477 #if defined(USE_16BPP_WITH_8888_ALPHA)
1478 // 8888
1479 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1480 #elif defined(USE_16BPP_WITH_5551_ALPHA)
1481 // 5551
1482 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0);
1483 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1484 #else
1485 // 4444
1486 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
1487 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1488 #endif
1489 }
1490 else {
1491 #if 0
1492 // 8888
1493 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1494 #else
1495 // 565
1496 static unsigned short scaled[1024*512]; // [512*256];
1497 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
1498 // Some OpenGL ES implementations do not have to be able to convert from GL_RGBA to GL_RGB format, so
1499 // we must do it manually here:
1500 unsigned char* pSrc = (unsigned char*) pData;
1501 unsigned short* pDest = scaled;
1502 for (int y = 0; y < height; y++) {
1503 for (int x = 0; x < width; x++) {
1504 *pDest++ = ((pSrc[0] >> 3) << 11) |
1505 ((pSrc[1] >> 2) << 5) |
1506 (pSrc[2] >> 3);
1507 pSrc += 4;
1508 }
1509 }
1510 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, scaled);
1511 #endif
1512 }
1513 }
1514
1515 /*
1516 ===============
1517 GL_Upload32
1518 ===============
1519 */
GL_Upload32(unsigned * data,int width,int height,qboolean mipmap,qboolean alpha)1520 void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha)
1521 {
1522 int samples;
1523 int scaled_width, scaled_height;
1524 static unsigned scaled[1024*512]; // [512*256];
1525
1526 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1527 ;
1528 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1529 ;
1530
1531 scaled_width >>= (int)gl_picmip.value;
1532 scaled_height >>= (int)gl_picmip.value;
1533
1534 if (scaled_width > gl_max_size.value)
1535 scaled_width = (int) gl_max_size.value;
1536 if (scaled_height > gl_max_size.value)
1537 scaled_height = (int) gl_max_size.value;
1538
1539 if (scaled_width * scaled_height > (int) sizeof(scaled)/4)
1540 Sys_Error ("GL_LoadTexture: too big");
1541
1542 samples = alpha ? gl_alpha_format : gl_solid_format;
1543
1544 texels += scaled_width * scaled_height;
1545
1546 if (scaled_width == width && scaled_height == height)
1547 {
1548 #if 0 // Disable this optimization, we want to be able to easily switch texture formats
1549 if (!mipmap)
1550 {
1551 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
1552 goto done;
1553 }
1554 #endif
1555 memcpy (scaled, data, width*height*4);
1556 }
1557 else
1558 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
1559
1560 #if defined(USE_16BPP_WITH_8888_ALPHA) || defined(USE_16BPP_WITH_5551_ALPHA) || defined(USE_16BPP_WITH_4444_ALPHA)
1561 // Upload as 16 bpp
1562
1563 #ifdef USE_MANUAL_MIPMAP_GEN
1564 #else
1565 // Use automatic MIPMAP generation
1566 if (mipmap)
1567 {
1568 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
1569 }
1570 #endif
1571
1572 sendTexture(0, scaled_width, scaled_height, scaled, alpha);
1573
1574 #ifdef USE_MANUAL_MIPMAP_GEN
1575 if (mipmap) {
1576 // Compute mip levels
1577 int mipWidth = scaled_width;
1578 int mipHeight = scaled_height;
1579 int mipLevel = 1;
1580 while (mipWidth > 1 || mipHeight > 1) {
1581 if (mipWidth > 1 && mipHeight > 1) {
1582 // Scale horizontally and vertically
1583 int srcWidth = mipWidth;
1584 mipWidth >>= 1;
1585 mipHeight >>= 1;
1586 const unsigned int* pIn = (const unsigned int*) scaled;
1587 unsigned int* pOut = (unsigned int*) scaled;
1588 for(int y = 0; y < mipHeight; y++) {
1589 for (int x = 0; x < mipWidth; x++) {
1590 *pOut++ = average4_8888(pIn[0], pIn[1],
1591 pIn[srcWidth], pIn[srcWidth+1]);
1592 pIn += 2;
1593 }
1594 pIn += srcWidth;
1595 }
1596 }
1597 else {
1598 // Scale horizontally:
1599 if (mipWidth > 1) {
1600 mipWidth >>= 1;
1601 const unsigned int* pIn = (const unsigned int*) scaled;
1602 unsigned int* pOut = (unsigned int*) scaled;
1603 unsigned int numTexels = mipHeight * mipWidth;
1604 for(unsigned int i = 0; i < numTexels; i++) {
1605 *pOut++ = average2_8888(pIn[0], pIn[1]);
1606 pIn += 2;
1607 }
1608 }
1609 // Scale vertically:
1610 if (mipHeight > 1) {
1611 mipHeight >>= 1;
1612 const unsigned int* pIn = (const unsigned int*) scaled;
1613 unsigned int* pOut = (unsigned int*) scaled;
1614 for(int y = 0; y < mipHeight; y++) {
1615 for (int x = 0; x < mipWidth; x++) {
1616 *pOut++ = average2_8888(pIn[0], pIn[mipWidth]);
1617 pIn += 1;
1618 }
1619 pIn += mipWidth;
1620 }
1621 }
1622 }
1623
1624 sendTexture(mipLevel, mipWidth, mipHeight, scaled, alpha);
1625 mipLevel++;
1626 }
1627 }
1628
1629 #else
1630 if (mipmap)
1631 {
1632 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0);
1633 }
1634 #endif
1635
1636 #elif defined(USE_32BPP)
1637 // 8888
1638 // Use automatic MIPMAP generation
1639 if (mipmap)
1640 {
1641 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
1642 }
1643 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1644 if (mipmap)
1645 {
1646 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0);
1647 }
1648 #else
1649 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1650 if (mipmap)
1651 {
1652 int miplevel;
1653
1654 miplevel = 0;
1655 while (scaled_width > 1 || scaled_height > 1)
1656 {
1657 GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
1658 scaled_width >>= 1;
1659 scaled_height >>= 1;
1660 if (scaled_width < 1)
1661 scaled_width = 1;
1662 if (scaled_height < 1)
1663 scaled_height = 1;
1664 miplevel++;
1665 glTexImage2DHelper (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1666 }
1667 }
1668 #endif
1669 done: ;
1670
1671 if (mipmap)
1672 {
1673 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1674 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1675 }
1676 else
1677 {
1678 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1679 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1680 }
1681 }
1682
1683 #ifdef USE_OPENGLES
1684
GL_Upload8_EXT(byte * data,int width,int height,qboolean mipmap,qboolean alpha)1685 void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
1686 {
1687 int i, s, bytesUsed;
1688 qboolean noalpha;
1689 int p;
1690 static unsigned j;
1691 static unsigned char compressedTextureBuffer[1024*512]; // [512*256];
1692 unsigned char* pTex = compressedTextureBuffer;
1693 int scaled_width, scaled_height;
1694 int miplevel = 0;
1695
1696 int originalScaledWidth;
1697 int originalScaledHeight;
1698
1699 s = width*height;
1700 // if there are no transparent pixels, make it a 3 component
1701 // texture even if it was specified as otherwise
1702 if (alpha)
1703 {
1704 noalpha = true;
1705 for (i=0 ; i<s ; i++)
1706 {
1707 if (data[i] == 255)
1708 noalpha = false;
1709 }
1710
1711 if (alpha && noalpha)
1712 alpha = false;
1713 }
1714 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1715 ;
1716 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1717 ;
1718
1719 scaled_width >>= (int)gl_picmip.value;
1720 scaled_height >>= (int)gl_picmip.value;
1721
1722 if (scaled_width > gl_max_size.value)
1723 scaled_width = (int) gl_max_size.value;
1724 if (scaled_height > gl_max_size.value)
1725 scaled_height = (int) gl_max_size.value;
1726
1727 if (scaled_width * scaled_height > ((int) (sizeof(compressedTextureBuffer) * 3 / 4)))
1728 Sys_Error ("GL_LoadTexture: too big");
1729
1730 // Copy the palette
1731
1732 int entrySize = alpha ? 4 : 3;
1733 int paletteSize = entrySize * 256;
1734 {
1735 byte* pDest = compressedTextureBuffer;
1736 const byte* pSrc = host_basepal;
1737 if(alpha)
1738 {
1739 for(int i = 0; i< 255; i++)
1740 {
1741 *pDest++ = *pSrc++;
1742 *pDest++ = *pSrc++;
1743 *pDest++ = *pSrc++;
1744 *pDest++ = 0xff;
1745 }
1746 // Entry 255 is transparent
1747 *pDest++ = 0x00;
1748 *pDest++ = 0x00;
1749 *pDest++ = 0x00;
1750 *pDest++ = 0x00;
1751 }
1752 else
1753 {
1754 memcpy(pDest, pSrc, paletteSize);
1755 }
1756 }
1757
1758 bytesUsed = paletteSize;
1759 pTex += paletteSize;
1760
1761 texels += scaled_width * scaled_height;
1762
1763 if (scaled_width == width && scaled_height == height)
1764 {
1765 memcpy (pTex, data, scaled_width*scaled_height);
1766 }
1767 else
1768 GL_Resample8BitTexture (data, width, height, pTex, scaled_width, scaled_height);
1769
1770 bytesUsed += scaled_width * scaled_height;
1771
1772 miplevel = 0;
1773
1774 originalScaledWidth = scaled_width;
1775 originalScaledHeight = scaled_height;
1776
1777 if (mipmap)
1778 {
1779 #ifdef SUPPORT_8BIT_MIPMAPGENERATION
1780 miplevel = 1;
1781 while (scaled_width > 1 || scaled_height > 1)
1782 {
1783 byte* pDest = (byte*) pTex + scaled_width * scaled_height;
1784 GL_MipMap8Bit ((byte *)pTex, pDest, scaled_width, scaled_height);
1785 pTex = pDest;
1786 scaled_width >>= 1;
1787 scaled_height >>= 1;
1788 if (scaled_width < 1)
1789 scaled_width = 1;
1790 if (scaled_height < 1)
1791 scaled_height = 1;
1792 bytesUsed += scaled_width * scaled_height;
1793 miplevel++;
1794 }
1795 #else
1796 Sys_Error("Unsupported attempt to generate 8 bit mip mapped texture. #define SUPPORT_8BIT_MIPMAPGENERATION");
1797 #endif
1798 }
1799
1800 GLint internalFormat = alpha ? GL_PALETTE8_RGBA8_OES : GL_PALETTE8_RGB8_OES;
1801 glCompressedTexImage2D (GL_TEXTURE_2D, -miplevel, internalFormat,
1802 originalScaledWidth, originalScaledHeight,
1803 0, bytesUsed, compressedTextureBuffer);
1804
1805 if (mipmap)
1806 {
1807 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1808 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1809 }
1810 else
1811 {
1812 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1813 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1814 }
1815 }
1816
1817 #else
1818
GL_Upload8_EXT(byte * data,int width,int height,qboolean mipmap,qboolean alpha)1819 void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
1820 {
1821 int i, s;
1822 qboolean noalpha;
1823 int p;
1824 static unsigned j;
1825 int samples;
1826 static unsigned char scaled[1024*512]; // [512*256];
1827 int scaled_width, scaled_height;
1828
1829 s = width*height;
1830 // if there are no transparent pixels, make it a 3 component
1831 // texture even if it was specified as otherwise
1832 if (alpha)
1833 {
1834 noalpha = true;
1835 for (i=0 ; i<s ; i++)
1836 {
1837 if (data[i] == 255)
1838 noalpha = false;
1839 }
1840
1841 if (alpha && noalpha)
1842 alpha = false;
1843 }
1844 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1845 ;
1846 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1847 ;
1848
1849 scaled_width >>= (int)gl_picmip.value;
1850 scaled_height >>= (int)gl_picmip.value;
1851
1852 if (scaled_width > gl_max_size.value)
1853 scaled_width = gl_max_size.value;
1854 if (scaled_height > gl_max_size.value)
1855 scaled_height = gl_max_size.value;
1856
1857 if (scaled_width * scaled_height > (int) sizeof(scaled))
1858 Sys_Error ("GL_LoadTexture: too big");
1859
1860 samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
1861
1862 texels += scaled_width * scaled_height;
1863
1864 if (scaled_width == width && scaled_height == height)
1865 {
1866 if (!mipmap)
1867 {
1868 glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
1869 goto done;
1870 }
1871 memcpy (scaled, data, width*height);
1872 }
1873 else
1874 GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
1875
1876 glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled);
1877 if (mipmap)
1878 {
1879 #ifdef SUPPORT_8BIT_MIPMAPGENERATION
1880 int miplevel;
1881
1882 miplevel = 0;
1883 while (scaled_width > 1 || scaled_height > 1)
1884 {
1885 GL_MipMap8Bit ((byte *)scaled, (byte*) scaled, scaled_width, scaled_height);
1886 scaled_width >>= 1;
1887 scaled_height >>= 1;
1888 if (scaled_width < 1)
1889 scaled_width = 1;
1890 if (scaled_height < 1)
1891 scaled_height = 1;
1892 miplevel++;
1893 glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
1894 }
1895 #else
1896 Sys_Error("Unsupported attept to generate 8 bit mip mapped texture.");
1897 #endif
1898 }
1899 done: ;
1900
1901
1902 if (mipmap)
1903 {
1904 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1905 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1906 }
1907 else
1908 {
1909 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1910 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1911 }
1912 }
1913
1914 #endif // ! OPENGL_ES
1915
1916 /*
1917 ===============
1918 GL_Upload8
1919 ===============
1920 */
GL_Upload8(byte * data,int width,int height,qboolean mipmap,qboolean alpha)1921 void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
1922 {
1923 static unsigned trans[640*480]; // FIXME, temporary
1924 int i, s;
1925 qboolean noalpha;
1926 int p;
1927
1928 s = width*height;
1929 // if there are no transparent pixels, make it a 3 component
1930 // texture even if it was specified as otherwise
1931 if (alpha)
1932 {
1933 noalpha = true;
1934 for (i=0 ; i<s ; i++)
1935 {
1936 p = data[i];
1937 if (p == 255)
1938 noalpha = false;
1939 trans[i] = d_8to24table[p];
1940 }
1941
1942 if (alpha && noalpha)
1943 alpha = false;
1944 }
1945 else
1946 {
1947 if (s&3)
1948 Sys_Error ("GL_Upload8: s&3");
1949 for (i=0 ; i<s ; i+=4)
1950 {
1951 trans[i] = d_8to24table[data[i]];
1952 trans[i+1] = d_8to24table[data[i+1]];
1953 trans[i+2] = d_8to24table[data[i+2]];
1954 trans[i+3] = d_8to24table[data[i+3]];
1955 }
1956 }
1957
1958 if (VID_Is8bit() && (data!=scrap_texels[0])
1959 #if !defined(USE_OPENGLES)
1960 && !alpha
1961 #endif
1962 ) {
1963 GL_Upload8_EXT (data, width, height, mipmap, alpha);
1964 return;
1965 }
1966 GL_Upload32 (trans, width, height, mipmap, alpha);
1967 }
1968
1969 /*
1970 ================
1971 GL_LoadTexture
1972 ================
1973 */
GL_LoadTexture(const char * identifier,int width,int height,byte * data,qboolean mipmap,qboolean alpha)1974 int GL_LoadTexture (const char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha)
1975 {
1976 qboolean noalpha;
1977 int i, p, s;
1978 gltexture_t *glt;
1979
1980 // see if the texture is allready present
1981 if (identifier[0])
1982 {
1983 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
1984 {
1985 if (!strcmp (identifier, glt->identifier))
1986 {
1987 if (width != glt->width || height != glt->height)
1988 Sys_Error ("GL_LoadTexture: cache mismatch");
1989 return gltextures[i].texnum;
1990 }
1991 }
1992 #ifdef USE_OPENGLES
1993 // Surely we want to remember this new texture.
1994 // Doing this costs 1% fps per timedemo on a DX7 PC,
1995 // probably because of the linear search through the
1996 // texture cache, but it saves 10 MB of VM growth per
1997 // level load. It also makes the GL_TEXTUREMODE
1998 // console command work correctly.
1999 numgltextures++;
2000 #endif
2001 }
2002 else {
2003 glt = &gltextures[numgltextures];
2004 numgltextures++;
2005 }
2006
2007 strcpy (glt->identifier, identifier);
2008 glt->texnum = texture_extension_number;
2009 glt->width = width;
2010 glt->height = height;
2011 glt->mipmap = mipmap;
2012
2013 GL_Bind(texture_extension_number);
2014
2015 #ifdef USE_TEXTURE_STORE
2016
2017 textureStore::get()->create(width, height, data, mipmap, alpha);
2018
2019 #else
2020
2021 GL_Upload8 (data, width, height, mipmap, alpha);
2022
2023 #endif
2024
2025 texture_extension_number++;
2026 return texture_extension_number-1;
2027 }
2028
2029
2030 /****************************************/
2031
2032 static GLenum oldtarget = TEXTURE0_SGIS;
2033
GL_SelectTexture(GLenum target)2034 void GL_SelectTexture (GLenum target)
2035 {
2036 if (!gl_mtexable)
2037 return;
2038 #ifdef USE_OPENGLES
2039 glActiveTexture(target);
2040 #else
2041 qglSelectTextureSGIS(target);
2042 #endif
2043 if (target == oldtarget)
2044 return;
2045 cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture;
2046 currenttexture = cnttextures[target-TEXTURE0_SGIS];
2047 oldtarget = target;
2048 }
2049
2050 // OpenGL ES compatible DrawQuad utility
2051
2052 #define BEGIN_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
2053 #define END_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
2054
DrawQuad_NoTex(float x,float y,float w,float h)2055 void DrawQuad_NoTex(float x, float y, float w, float h)
2056 {
2057 BEGIN_QUAD
2058
2059 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
2060 short index[4] = {0, 1, 2, 3};
2061 glVertexPointer( 2, GL_FLOAT, 0, vertex);
2062 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2063 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
2064 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2065
2066 END_QUAD
2067 }
2068
DrawQuad(float x,float y,float w,float h,float u,float v,float uw,float vh)2069 void DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh)
2070 {
2071 BEGIN_QUAD
2072
2073 float texcoord[2*4] = {u, v, u + uw, v, u + uw, v + vh, u, v + vh};
2074 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
2075 unsigned short index[4] = {0, 1, 2, 3};
2076 glTexCoordPointer( 2, GL_FLOAT, 0, texcoord);
2077 glVertexPointer( 2, GL_FLOAT, 0, vertex);
2078 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
2079
2080 END_QUAD
2081 }
2082
2083 #ifdef USE_OPENGLES
2084
2085 // Reimplementation of OpenGL functions that are missing in OpenGL ES
2086
glColor3f(GLfloat r,GLfloat g,GLfloat b)2087 void glColor3f(GLfloat r, GLfloat g, GLfloat b)
2088 {
2089 glColor4f(r, g, b, 1.0f);
2090 }
2091
glColor4fv(GLfloat * pColor)2092 void glColor4fv(GLfloat* pColor)
2093 {
2094 glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]);
2095 }
2096
2097 float gVertexBuffer[VERTEXARRAYSIZE];
2098 float gColorBuffer[VERTEXARRAYSIZE];
2099 float gTexCoordBuffer[VERTEXARRAYSIZE];
2100
2101 // Called when we've lost the OpenGL context and have to recreate it.
2102 extern void GL_Init();
2103 extern void R_InitParticleTexture2();
2104 extern void GL_UploadLightmaps();
2105 extern void R_ReloadSky();
2106
GL_ReInit()2107 void GL_ReInit() {
2108 GL_Init();
2109 textureStore::get()->rebindAll();
2110 scrap_dirty = true;
2111 R_InitParticleTexture2();
2112 GL_UploadLightmaps();
2113 R_ReloadSky();
2114 }
2115
2116 #endif
2117
2118 #ifdef DEBUG_OPENGL_CALLS
checkGLImp(const char * state,const char * file,int line)2119 void checkGLImp(const char* state, const char* file, int line) {
2120 GLenum error = glGetError();
2121 if (error != GL_NO_ERROR) {
2122 Sys_Error("%s: error 0x%04X at %s:%d\n", state, error, file, line);
2123 }
2124 }
2125
2126 #endif
2127