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 x = 0;
537 y = 0;
538 texnum = Scrap_AllocBlock (p->width, p->height, &x, &y);
539 scrap_dirty = true;
540 k = 0;
541 for (i=0 ; i<p->height ; i++)
542 for (j=0 ; j<p->width ; j++, k++)
543 scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];
544 texnum += scrap_texnum;
545 gl->texnum = texnum;
546 gl->sl = (x+0.01)/(float)BLOCK_WIDTH;
547 gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;
548 gl->tl = (y+0.01)/(float)BLOCK_WIDTH;
549 gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;
550
551 pic_count++;
552 pic_texels += p->width*p->height;
553 }
554 else
555 {
556 gl->texnum = GL_LoadPicTexture (p);
557 gl->sl = 0;
558 gl->sh = 1;
559 gl->tl = 0;
560 gl->th = 1;
561 }
562 return p;
563 }
564
565
566 /*
567 ================
568 Draw_CachePic
569 ================
570 */
Draw_CachePic(const char * path)571 qpic_t *Draw_CachePic (const char *path)
572 {
573 cachepic_t *pic;
574 int i;
575 qpic_t *dat;
576 glpic_t *gl;
577
578 for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
579 if (!strcmp (path, pic->name))
580 return &pic->pic;
581
582 if (menu_numcachepics == MAX_CACHED_PICS)
583 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
584 menu_numcachepics++;
585 strcpy (pic->name, path);
586
587 //
588 // load the pic from disk
589 //
590 dat = (qpic_t *)COM_LoadTempFile (path);
591 if (!dat)
592 Sys_Error ("Draw_CachePic: failed to load %s", path);
593 SwapPic (dat);
594
595 // HACK HACK HACK --- we need to keep the bytes for
596 // the translatable player picture just for the menu
597 // configuration dialog
598 if (!strcmp (path, "gfx/menuplyr.lmp"))
599 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height);
600
601 pic->pic.width = dat->width;
602 pic->pic.height = dat->height;
603
604 glpic_t temp;
605 gl = &temp;
606 gl->texnum = GL_LoadPicTexture (dat);
607 gl->sl = 0;
608 gl->sh = 1;
609 gl->tl = 0;
610 gl->th = 1;
611
612 memcpy(pic->pic.data, &temp, sizeof(temp));
613
614 return &pic->pic;
615 }
616
617
Draw_CharToConback(int num,byte * dest)618 void Draw_CharToConback (int num, byte *dest)
619 {
620 int row, col;
621 byte *source;
622 int drawline;
623 int x;
624
625 row = num>>4;
626 col = num&15;
627 source = draw_chars + (row<<10) + (col<<3);
628
629 drawline = 8;
630
631 while (drawline--)
632 {
633 for (x=0 ; x<8 ; x++)
634 if (source[x] != 255)
635 dest[x] = 0x60 + source[x];
636 source += 128;
637 dest += 320;
638 }
639
640 }
641
642 typedef struct
643 {
644 const char *name;
645 int minimize, maximize;
646 } glmode_t;
647
648 glmode_t modes[] = {
649 {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
650 {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
651 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
652 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
653 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
654 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
655 };
656
657 /*
658 ===============
659 Draw_TextureMode_f
660 ===============
661 */
Draw_TextureMode_f(void)662 void Draw_TextureMode_f (void)
663 {
664 int i;
665 gltexture_t *glt;
666
667 if (Cmd_Argc() == 1)
668 {
669 for (i=0 ; i< 6 ; i++)
670 if (gl_filter_min == modes[i].minimize)
671 {
672 Con_Printf ("%s\n", modes[i].name);
673 return;
674 }
675 Con_Printf ("current filter is unknown???\n");
676 return;
677 }
678
679 for (i=0 ; i< 6 ; i++)
680 {
681 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
682 break;
683 }
684 if (i == 6)
685 {
686 Con_Printf ("bad filter name\n");
687 return;
688 }
689
690 gl_filter_min = modes[i].minimize;
691 gl_filter_max = modes[i].maximize;
692
693 // change all the existing mipmap texture objects
694 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
695 {
696 if (glt->mipmap)
697 {
698 GL_Bind (glt->texnum);
699 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
700 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
701 }
702 }
703 }
704
705 /*
706 ===============
707 Draw_Init
708 ===============
709 */
Draw_Init(void)710 void Draw_Init (void)
711 {
712 int i;
713 qpic_t *cb;
714 byte *dest, *src;
715 int x, y;
716 char ver[40];
717 glpic_t *gl;
718 int start;
719 byte *ncdata;
720 int f, fstep;
721
722
723 Cvar_RegisterVariable (&gl_nobind);
724 Cvar_RegisterVariable (&gl_max_size);
725 Cvar_RegisterVariable (&gl_picmip);
726
727 // 3dfx can only handle 256 wide textures
728 if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) ||
729 strstr((char *)gl_renderer, "Glide"))
730 Cvar_Set ("gl_max_size", "256");
731
732 Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
733
734 // load the console background and the charset
735 // by hand, because we need to write the version
736 // string into the background before turning
737 // it into a texture
738 draw_chars = (byte*) W_GetLumpName ("conchars");
739 for (i=0 ; i<256*64 ; i++)
740 if (draw_chars[i] == 0)
741 draw_chars[i] = 255; // proper transparent color
742
743 // now turn them into textures
744 char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
745
746 start = Hunk_LowMark();
747
748 cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp");
749 if (!cb)
750 Sys_Error ("Couldn't load gfx/conback.lmp");
751 SwapPic (cb);
752
753 // hack the version number directly into the pic
754 #if defined(__linux__)
755 sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION);
756 #else
757 sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION);
758 #endif
759 dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);
760 y = strlen(ver);
761 for (x=0 ; x<y ; x++)
762 Draw_CharToConback (ver[x], dest+(x<<3));
763
764 #if 0
765 conback->width = vid.conwidth;
766 conback->height = vid.conheight;
767
768 // scale console to vid size
769 dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback");
770
771 for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth)
772 {
773 src = cb->data + cb->width * (y*cb->height/vid.conheight);
774 if (vid.conwidth == cb->width)
775 memcpy (dest, src, vid.conwidth);
776 else
777 {
778 f = 0;
779 fstep = cb->width*0x10000/vid.conwidth;
780 for (x=0 ; x<vid.conwidth ; x+=4)
781 {
782 dest[x] = src[f>>16];
783 f += fstep;
784 dest[x+1] = src[f>>16];
785 f += fstep;
786 dest[x+2] = src[f>>16];
787 f += fstep;
788 dest[x+3] = src[f>>16];
789 f += fstep;
790 }
791 }
792 }
793 #else
794 conback->g.width = cb->width;
795 conback->g.height = cb->height;
796 ncdata = cb->data;
797 #endif
798
799 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
800 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
801
802 gl = &conback->g.glpic;
803 gl->texnum = GL_LoadTexture ("conback", conback->g.width, conback->g.height, ncdata, false, false);
804 gl->sl = 0;
805 gl->sh = 1;
806 gl->tl = 0;
807 gl->th = 1;
808 conback->g.width = vid.width;
809 conback->g.height = vid.height;
810
811 // free loaded console
812 Hunk_FreeToLowMark(start);
813
814 // save a texture slot for translated picture
815 translate_texture = texture_extension_number++;
816
817 // save slots for scraps
818 scrap_texnum = texture_extension_number;
819 texture_extension_number += MAX_SCRAPS;
820
821 //
822 // get the other pics we need
823 //
824 draw_disc = Draw_PicFromWad ("disc");
825 draw_backtile = Draw_PicFromWad ("backtile");
826 }
827
828
829
830 /*
831 ================
832 Draw_Character
833
834 Draws one 8*8 graphics character with 0 being transparent.
835 It can be clipped to the top of the screen to allow the console to be
836 smoothly scrolled off.
837 ================
838 */
Draw_Character(int x,int y,int num)839 void Draw_Character (int x, int y, int num)
840 {
841 byte *dest;
842 byte *source;
843 unsigned short *pusdest;
844 int drawline;
845 int row, col;
846 float frow, fcol, size;
847
848 if (num == 32)
849 return; // space
850
851 num &= 255;
852
853 if (y <= -8)
854 return; // totally off screen
855
856 row = num>>4;
857 col = num&15;
858
859 frow = row*0.0625;
860 fcol = col*0.0625;
861 size = 0.0625;
862
863 GL_Bind (char_texture);
864
865 #ifdef USE_OPENGLES
866 DrawQuad(x, y, 8, 8, fcol, frow, size, size);
867 #else
868 glBegin (GL_QUADS);
869 glTexCoord2f (fcol, frow);
870 glVertex2f (x, y);
871 glTexCoord2f (fcol + size, frow);
872 glVertex2f (x+8, y);
873 glTexCoord2f (fcol + size, frow + size);
874 glVertex2f (x+8, y+8);
875 glTexCoord2f (fcol, frow + size);
876 glVertex2f (x, y+8);
877 glEnd ();
878 #endif
879 }
880
881 /*
882 ================
883 Draw_String
884 ================
885 */
Draw_String(int x,int y,const char * str)886 void Draw_String (int x, int y, const char *str)
887 {
888 while (*str)
889 {
890 Draw_Character (x, y, *str);
891 str++;
892 x += 8;
893 }
894 }
895
896 /*
897 ================
898 Draw_DebugChar
899
900 Draws a single character directly to the upper right corner of the screen.
901 This is for debugging lockups by drawing different chars in different parts
902 of the code.
903 ================
904 */
Draw_DebugChar(char num)905 void Draw_DebugChar (char num)
906 {
907 }
908
909 /*
910 =============
911 Draw_AlphaPic
912 =============
913 */
Draw_AlphaPic(int x,int y,packedGlpic_t * ppic,float alpha)914 void Draw_AlphaPic (int x, int y, packedGlpic_t *ppic, float alpha)
915 {
916 byte *dest, *source;
917 unsigned short *pusdest;
918 int v, u;
919 glpic_t *gl;
920
921 if (scrap_dirty)
922 Scrap_Upload ();
923 gl = & ppic->g.glpic;
924 glDisable(GL_ALPHA_TEST);
925 glEnable (GL_BLEND);
926 // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
927 // glCullFace(GL_FRONT);
928 glColor4f (1,1,1,alpha);
929 GL_Bind (gl->texnum);
930 #ifdef USE_OPENGLES
931 DrawQuad(x, y, ppic->g.width, ppic->g.height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
932 #else
933 glBegin (GL_QUADS);
934 glTexCoord2f (gl->sl, gl->tl);
935 glVertex2f (x, y);
936 glTexCoord2f (gl->sh, gl->tl);
937 glVertex2f (x+pic->width, y);
938 glTexCoord2f (gl->sh, gl->th);
939 glVertex2f (x+pic->width, y+pic->height);
940 glTexCoord2f (gl->sl, gl->th);
941 glVertex2f (x, y+pic->height);
942 glEnd ();
943 #endif
944 glColor4f (1,1,1,1);
945 glEnable(GL_ALPHA_TEST);
946 glDisable (GL_BLEND);
947 }
948
949
950 /*
951 =============
952 Draw_Pic
953 =============
954 */
Draw_Pic(int x,int y,qpic_t * pic)955 void Draw_Pic (int x, int y, qpic_t *pic)
956 {
957 byte *dest, *source;
958 unsigned short *pusdest;
959 int v, u;
960 glpic_t *gl;
961
962 if (scrap_dirty)
963 Scrap_Upload ();
964 glpic_t temp;
965 memcpy(&temp, pic->data, sizeof(temp));
966 gl = & temp;
967 glColor4f (1,1,1,1);
968 GL_Bind (gl->texnum);
969 #ifdef USE_OPENGLES
970 DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);
971 #else
972 glBegin (GL_QUADS);
973 glTexCoord2f (gl->sl, gl->tl);
974 glVertex2f (x, y);
975 glTexCoord2f (gl->sh, gl->tl);
976 glVertex2f (x+pic->width, y);
977 glTexCoord2f (gl->sh, gl->th);
978 glVertex2f (x+pic->width, y+pic->height);
979 glTexCoord2f (gl->sl, gl->th);
980 glVertex2f (x, y+pic->height);
981 glEnd ();
982 #endif
983 }
984
985
986 /*
987 =============
988 Draw_TransPic
989 =============
990 */
Draw_TransPic(int x,int y,qpic_t * pic)991 void Draw_TransPic (int x, int y, qpic_t *pic)
992 {
993 byte *dest, *source, tbyte;
994 unsigned short *pusdest;
995 int v, u;
996
997 if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
998 (unsigned)(y + pic->height) > vid.height)
999 {
1000 Sys_Error ("Draw_TransPic: bad coordinates");
1001 }
1002
1003 Draw_Pic (x, y, pic);
1004 }
1005
1006
1007 /*
1008 =============
1009 Draw_TransPicTranslate
1010
1011 Only used for the player color selection menu
1012 =============
1013 */
Draw_TransPicTranslate(int x,int y,qpic_t * pic,byte * translation)1014 void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
1015 {
1016 int v, u, c;
1017 unsigned trans[64*64], *dest;
1018 byte *src;
1019 int p;
1020
1021 GL_Bind (translate_texture);
1022
1023 c = pic->width * pic->height;
1024
1025 dest = trans;
1026 for (v=0 ; v<64 ; v++, dest += 64)
1027 {
1028 src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];
1029 for (u=0 ; u<64 ; u++)
1030 {
1031 p = src[(u*pic->width)>>6];
1032 if (p == 255)
1033 dest[u] = p;
1034 else
1035 dest[u] = d_8to24table[translation[p]];
1036 }
1037 }
1038
1039 glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
1040
1041 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1042 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1043
1044 glColor3f (1,1,1);
1045 #ifdef USE_OPENGLES
1046 DrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1);
1047 #else
1048 glBegin (GL_QUADS);
1049 glTexCoord2f (0, 0);
1050 glVertex2f (x, y);
1051 glTexCoord2f (1, 0);
1052 glVertex2f (x+pic->width, y);
1053 glTexCoord2f (1, 1);
1054 glVertex2f (x+pic->width, y+pic->height);
1055 glTexCoord2f (0, 1);
1056 glVertex2f (x, y+pic->height);
1057 glEnd ();
1058 #endif
1059 }
1060
1061
1062 /*
1063 ================
1064 Draw_ConsoleBackground
1065
1066 ================
1067 */
Draw_ConsoleBackground(int lines)1068 void Draw_ConsoleBackground (int lines)
1069 {
1070 int y = (vid.height * 3) >> 2;
1071
1072 if (lines > y)
1073 Draw_Pic(0, lines - vid.height, &conback->qpic);
1074 else
1075 Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
1076 }
1077
1078
1079 /*
1080 =============
1081 Draw_TileClear
1082
1083 This repeats a 64*64 tile graphic to fill the screen around a sized down
1084 refresh window.
1085 =============
1086 */
1087
1088 typedef union ByteToInt_t {
1089 byte b[4];
1090 int i;
1091 } ByteToInt;
1092
Draw_TileClear(int x,int y,int w,int h)1093 void Draw_TileClear (int x, int y, int w, int h)
1094 {
1095 glColor3f (1,1,1);
1096 ByteToInt b;
1097 memcpy(b.b, draw_backtile->data, sizeof(b.b));
1098 GL_Bind (b.i);
1099 #ifdef USE_OPENGLES
1100 DrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0);
1101 #else
1102 glBegin (GL_QUADS);
1103 glTexCoord2f (x/64.0, y/64.0);
1104 glVertex2f (x, y);
1105 glTexCoord2f ( (x+w)/64.0, y/64.0);
1106 glVertex2f (x+w, y);
1107 glTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
1108 glVertex2f (x+w, y+h);
1109 glTexCoord2f ( x/64.0, (y+h)/64.0 );
1110 glVertex2f (x, y+h);
1111 glEnd ();
1112 #endif
1113 }
1114
1115
1116 /*
1117 =============
1118 Draw_Fill
1119
1120 Fills a box of pixels with a single color
1121 =============
1122 */
Draw_Fill(int x,int y,int w,int h,int c)1123 void Draw_Fill (int x, int y, int w, int h, int c)
1124 {
1125 glDisable (GL_TEXTURE_2D);
1126 glColor3f (host_basepal[c*3]/255.0,
1127 host_basepal[c*3+1]/255.0,
1128 host_basepal[c*3+2]/255.0);
1129
1130 #ifdef USE_OPENGLES
1131 DrawQuad_NoTex(x, y, w, h);
1132 #else
1133 glBegin (GL_QUADS);
1134
1135 glVertex2f (x,y);
1136 glVertex2f (x+w, y);
1137 glVertex2f (x+w, y+h);
1138 glVertex2f (x, y+h);
1139
1140 glEnd ();
1141 #endif
1142 glColor3f (1,1,1);
1143 glEnable (GL_TEXTURE_2D);
1144 }
1145 //=============================================================================
1146
1147 /*
1148 ================
1149 Draw_FadeScreen
1150
1151 ================
1152 */
Draw_FadeScreen(void)1153 void Draw_FadeScreen (void)
1154 {
1155 glEnable (GL_BLEND);
1156 glDisable (GL_TEXTURE_2D);
1157 glColor4f (0, 0, 0, 0.8);
1158 #ifdef USE_OPENGLES
1159 DrawQuad_NoTex(0, 0, vid.width, vid.height);
1160 #else
1161 glBegin (GL_QUADS);
1162
1163 glVertex2f (0,0);
1164 glVertex2f (vid.width, 0);
1165 glVertex2f (vid.width, vid.height);
1166 glVertex2f (0, vid.height);
1167
1168 glEnd ();
1169 #endif
1170 glColor4f (1,1,1,1);
1171 glEnable (GL_TEXTURE_2D);
1172 glDisable (GL_BLEND);
1173
1174 Sbar_Changed();
1175 }
1176
1177 //=============================================================================
1178
1179 /*
1180 ================
1181 Draw_BeginDisc
1182
1183 Draws the little blue disc in the corner of the screen.
1184 Call before beginning any disc IO.
1185 ================
1186 */
Draw_BeginDisc(void)1187 void Draw_BeginDisc (void)
1188 {
1189 if (!draw_disc)
1190 return;
1191 #ifdef USE_OPENGLES
1192 // !!! Implement this
1193 #else
1194 glDrawBuffer (GL_FRONT);
1195 Draw_Pic (vid.width - 24, 0, draw_disc);
1196 glDrawBuffer (GL_BACK);
1197 #endif
1198 }
1199
1200
1201 /*
1202 ================
1203 Draw_EndDisc
1204
1205 Erases the disc icon.
1206 Call after completing any disc IO
1207 ================
1208 */
Draw_EndDisc(void)1209 void Draw_EndDisc (void)
1210 {
1211 }
1212
1213 /*
1214 ================
1215 GL_Set2D
1216
1217 Setup as if the screen was 320*200
1218 ================
1219 */
GL_Set2D(void)1220 void GL_Set2D (void)
1221 {
1222 glViewport (glx, gly, glwidth, glheight);
1223
1224 glMatrixMode(GL_PROJECTION);
1225 glLoadIdentity ();
1226 #ifdef USE_OPENGLES
1227 glOrthof (0, vid.width, vid.height, 0, -99999, 99999);
1228 #else
1229 glOrtho (0, vid.width, vid.height, 0, -99999, 99999);
1230 #endif
1231
1232 glMatrixMode(GL_MODELVIEW);
1233 glLoadIdentity ();
1234
1235 glDisable (GL_DEPTH_TEST);
1236 glDisable (GL_CULL_FACE);
1237 glDisable (GL_BLEND);
1238 glEnable (GL_ALPHA_TEST);
1239 // glDisable (GL_ALPHA_TEST);
1240
1241 glColor4f (1,1,1,1);
1242 }
1243
1244 //====================================================================
1245
1246 /*
1247 ================
1248 GL_FindTexture
1249 ================
1250 */
GL_FindTexture(const char * identifier)1251 int GL_FindTexture (const char *identifier)
1252 {
1253 int i;
1254 gltexture_t *glt;
1255
1256 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
1257 {
1258 if (!strcmp (identifier, glt->identifier))
1259 return gltextures[i].texnum;
1260 }
1261
1262 return -1;
1263 }
1264
1265 /*
1266 ================
1267 GL_ResampleTexture
1268 ================
1269 */
GL_ResampleTexture(unsigned * in,int inwidth,int inheight,unsigned * out,int outwidth,int outheight)1270 void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
1271 {
1272 int i, j;
1273 unsigned *inrow;
1274 unsigned frac, fracstep;
1275
1276 fracstep = inwidth*0x10000/outwidth;
1277 for (i=0 ; i<outheight ; i++, out += outwidth)
1278 {
1279 inrow = in + inwidth*(i*inheight/outheight);
1280 frac = fracstep >> 1;
1281 for (j=0 ; j<outwidth ; j+=4)
1282 {
1283 out[j] = inrow[frac>>16];
1284 frac += fracstep;
1285 out[j+1] = inrow[frac>>16];
1286 frac += fracstep;
1287 out[j+2] = inrow[frac>>16];
1288 frac += fracstep;
1289 out[j+3] = inrow[frac>>16];
1290 frac += fracstep;
1291 }
1292 }
1293 }
1294
1295 /*
1296 ================
1297 GL_Resample8BitTexture -- JACK
1298 ================
1299 */
GL_Resample8BitTexture(unsigned char * in,int inwidth,int inheight,unsigned char * out,int outwidth,int outheight)1300 void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight)
1301 {
1302 int i, j;
1303 unsigned char *inrow;
1304 unsigned frac, fracstep;
1305
1306 fracstep = inwidth*0x10000/outwidth;
1307 for (i=0 ; i<outheight ; i++, out += outwidth)
1308 {
1309 inrow = in + inwidth*(i*inheight/outheight);
1310 frac = fracstep >> 1;
1311 for (j=0 ; j<outwidth ; j+=4)
1312 {
1313 out[j] = inrow[frac>>16];
1314 frac += fracstep;
1315 out[j+1] = inrow[frac>>16];
1316 frac += fracstep;
1317 out[j+2] = inrow[frac>>16];
1318 frac += fracstep;
1319 out[j+3] = inrow[frac>>16];
1320 frac += fracstep;
1321 }
1322 }
1323 }
1324
1325
1326 /*
1327 ================
1328 GL_MipMap
1329
1330 Operates in place, quartering the size of the texture
1331 ================
1332 */
GL_MipMap(byte * in,int width,int height)1333 void GL_MipMap (byte *in, int width, int height)
1334 {
1335 int i, j;
1336 byte *out;
1337
1338 width <<=2;
1339 height >>= 1;
1340 out = in;
1341 for (i=0 ; i<height ; i++, in+=width)
1342 {
1343 for (j=0 ; j<width ; j+=8, out+=4, in+=8)
1344 {
1345 out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
1346 out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
1347 out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
1348 out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
1349 }
1350 }
1351 }
1352
1353 #ifdef SUPPORT_8BIT_MIPMAPGENERATION
1354 /*
1355 ================
1356 GL_MipMap8Bit
1357
1358 Mipping for 8 bit textures
1359
1360 The "in" and "out" arguments can point to the same buffer if desired
1361 ================
1362 */
GL_MipMap8Bit(byte * in,byte * out,int width,int height)1363 void GL_MipMap8Bit (byte *in, byte* out, int width, int height)
1364 {
1365 int i, j;
1366 unsigned short r,g,b;
1367 byte *at1, *at2, *at3, *at4;
1368
1369 // width <<=2;
1370 height >>= 1;
1371 for (i=0 ; i<height ; i++, in+=width)
1372 {
1373 for (j=0 ; j<width ; j+=2, out+=1, in+=2)
1374 {
1375 at1 = (byte *) (d_8to24table + in[0]);
1376 at2 = (byte *) (d_8to24table + in[1]);
1377 at3 = (byte *) (d_8to24table + in[width+0]);
1378 at4 = (byte *) (d_8to24table + in[width+1]);
1379
1380 r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
1381 g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
1382 b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
1383
1384 out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
1385 }
1386 }
1387 }
1388
1389 #endif // SUPPORT_8BIT_MIPMAPGENERATION
1390
glTexImage2DHelper(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid * pixels)1391 void glTexImage2DHelper( GLenum target,
1392 GLint level,
1393 GLint internalformat,
1394 GLsizei width,
1395 GLsizei height,
1396 GLint border,
1397 GLenum format,
1398 GLenum type,
1399 const GLvoid *pixels )
1400 {
1401 // In full OpenGL The internalformat can be 1..4, to indicate how many components of the data are valid.
1402 // OpenGL ES requires the internalformat argument match the format for glTexImage2D.
1403
1404 glTexImage2D(target, level, format, width, height, border, format, type, pixels);
1405 }
1406
1407
1408 // Uncomment to enable manual MipMap generation
1409 #define USE_MANUAL_MIPMAP_GEN
1410
1411 // Uncomment one of the following:
1412
1413 // #define USE_16BPP_WITH_8888_ALPHA
1414 // #define USE_16BPP_WITH_5551_ALPHA // <--- This has bugs on the simulator and the device. (Device has all alpha images invisible.)
1415 #define USE_16BPP_WITH_4444_ALPHA // <--- This has bugs on the simulator, works in device
1416 // #define USE_32BPP
1417 // #define USE_32BPP_MANUAL_MIPMAP_GEN
1418
1419 #ifdef USE_MANUAL_MIPMAP_GEN
1420
average4(unsigned int a,unsigned int b,unsigned int c,unsigned int d,unsigned int shift,unsigned int mask)1421 inline unsigned int average4(unsigned int a, unsigned int b,
1422 unsigned int c, unsigned int d,
1423 unsigned int shift, unsigned int mask) {
1424 unsigned int aElem = (a >> shift) & mask;
1425 unsigned int bElem = (b >> shift) & mask;
1426 unsigned int cElem = (c >> shift) & mask;
1427 unsigned int dElem = (d >> shift) & mask;
1428 unsigned int avgElem = ((aElem + bElem + cElem + dElem) >> 2) & mask;
1429 return avgElem << shift;
1430 }
1431
average2(unsigned int a,unsigned int b,unsigned int shift,unsigned int mask)1432 inline unsigned int average2(unsigned int a, unsigned int b,
1433 unsigned int shift, unsigned int mask) {
1434 unsigned int aElem = (a >> shift) & mask;
1435 unsigned int bElem = (b >> shift) & mask;
1436 unsigned int avgElem = ((aElem + bElem) >> 1) & mask;
1437 return avgElem << shift;
1438 }
1439
average4444(unsigned int a,unsigned int b)1440 inline unsigned int average4444(unsigned int a, unsigned int b) {
1441 return
1442 average2(a,b,0,0xf) |
1443 average2(a,b,4,0xf) |
1444 average2(a,b,8,0xf) |
1445 average2(a,b,12,0xf);
1446 }
1447
average565(unsigned int a,unsigned int b)1448 inline unsigned int average565(unsigned int a, unsigned int b) {
1449 return
1450 average2(a,b,0,0x1f) |
1451 average2(a,b,5,0x3f) |
1452 average2(a,b,11,0x1f);
1453 }
1454
average2_8888(unsigned int a,unsigned int b)1455 inline unsigned int average2_8888(unsigned int a, unsigned int b) {
1456 return
1457 average2(a,b,0,0xff) |
1458 average2(a,b,8,0xff) |
1459 average2(a,b,16,0xff) |
1460 average2(a,b,24,0xff);
1461 }
1462
average4_8888(unsigned int a,unsigned int b,unsigned int c,unsigned int d)1463 inline unsigned int average4_8888(unsigned int a, unsigned int b,
1464 unsigned int c, unsigned int d) {
1465 return
1466 average4(a,b,c,d,0,0xff) |
1467 average4(a,b,c,d,8,0xff) |
1468 average4(a,b,c,d,16,0xff) |
1469 average4(a,b,c,d,24,0xff);
1470 }
1471
1472 #endif
1473
1474 // pData is 8 bpp 32-bit color
1475
1476
sendTexture(int mipLevel,int width,int height,unsigned int * pData,qboolean alpha)1477 void sendTexture(int mipLevel, int width, int height, unsigned int* pData, qboolean alpha) {
1478 if (alpha) {
1479 #if defined(USE_16BPP_WITH_8888_ALPHA)
1480 // 8888
1481 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1482 #elif defined(USE_16BPP_WITH_5551_ALPHA)
1483 // 5551
1484 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0);
1485 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1486 #else
1487 // 4444
1488 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
1489 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1490 #endif
1491 }
1492 else {
1493 #if 0
1494 // 8888
1495 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
1496 #else
1497 // 565
1498 static unsigned short scaled[1024*512]; // [512*256];
1499 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
1500 // Some OpenGL ES implementations do not have to be able to convert from GL_RGBA to GL_RGB format, so
1501 // we must do it manually here:
1502 unsigned char* pSrc = (unsigned char*) pData;
1503 unsigned short* pDest = scaled;
1504 for (int y = 0; y < height; y++) {
1505 for (int x = 0; x < width; x++) {
1506 *pDest++ = ((pSrc[0] >> 3) << 11) |
1507 ((pSrc[1] >> 2) << 5) |
1508 (pSrc[2] >> 3);
1509 pSrc += 4;
1510 }
1511 }
1512 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, scaled);
1513 #endif
1514 }
1515 }
1516
1517 /*
1518 ===============
1519 GL_Upload32
1520 ===============
1521 */
GL_Upload32(unsigned * data,int width,int height,qboolean mipmap,qboolean alpha)1522 void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha)
1523 {
1524 int samples;
1525 int scaled_width, scaled_height;
1526 static unsigned scaled[1024*512]; // [512*256];
1527
1528 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1529 ;
1530 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1531 ;
1532
1533 scaled_width >>= (int)gl_picmip.value;
1534 scaled_height >>= (int)gl_picmip.value;
1535
1536 if (scaled_width > gl_max_size.value)
1537 scaled_width = (int) gl_max_size.value;
1538 if (scaled_height > gl_max_size.value)
1539 scaled_height = (int) gl_max_size.value;
1540
1541 if (scaled_width * scaled_height > (int) sizeof(scaled)/4)
1542 Sys_Error ("GL_LoadTexture: too big");
1543
1544 samples = alpha ? gl_alpha_format : gl_solid_format;
1545
1546 texels += scaled_width * scaled_height;
1547
1548 if (scaled_width == width && scaled_height == height)
1549 {
1550 #if 0 // Disable this optimization, we want to be able to easily switch texture formats
1551 if (!mipmap)
1552 {
1553 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
1554 goto done;
1555 }
1556 #endif
1557 memcpy (scaled, data, width*height*4);
1558 }
1559 else
1560 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
1561
1562 #if defined(USE_16BPP_WITH_8888_ALPHA) || defined(USE_16BPP_WITH_5551_ALPHA) || defined(USE_16BPP_WITH_4444_ALPHA)
1563 // Upload as 16 bpp
1564
1565 #ifdef USE_MANUAL_MIPMAP_GEN
1566 #else
1567 // Use automatic MIPMAP generation
1568 if (mipmap)
1569 {
1570 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
1571 }
1572 #endif
1573
1574 sendTexture(0, scaled_width, scaled_height, scaled, alpha);
1575
1576 #ifdef USE_MANUAL_MIPMAP_GEN
1577 if (mipmap) {
1578 // Compute mip levels
1579 int mipWidth = scaled_width;
1580 int mipHeight = scaled_height;
1581 int mipLevel = 1;
1582 while (mipWidth > 1 || mipHeight > 1) {
1583 if (mipWidth > 1 && mipHeight > 1) {
1584 // Scale horizontally and vertically
1585 int srcWidth = mipWidth;
1586 mipWidth >>= 1;
1587 mipHeight >>= 1;
1588 const unsigned int* pIn = (const unsigned int*) scaled;
1589 unsigned int* pOut = (unsigned int*) scaled;
1590 for(int y = 0; y < mipHeight; y++) {
1591 for (int x = 0; x < mipWidth; x++) {
1592 *pOut++ = average4_8888(pIn[0], pIn[1],
1593 pIn[srcWidth], pIn[srcWidth+1]);
1594 pIn += 2;
1595 }
1596 pIn += srcWidth;
1597 }
1598 }
1599 else {
1600 // Scale horizontally:
1601 if (mipWidth > 1) {
1602 mipWidth >>= 1;
1603 const unsigned int* pIn = (const unsigned int*) scaled;
1604 unsigned int* pOut = (unsigned int*) scaled;
1605 unsigned int numTexels = mipHeight * mipWidth;
1606 for(unsigned int i = 0; i < numTexels; i++) {
1607 *pOut++ = average2_8888(pIn[0], pIn[1]);
1608 pIn += 2;
1609 }
1610 }
1611 // Scale vertically:
1612 if (mipHeight > 1) {
1613 mipHeight >>= 1;
1614 const unsigned int* pIn = (const unsigned int*) scaled;
1615 unsigned int* pOut = (unsigned int*) scaled;
1616 for(int y = 0; y < mipHeight; y++) {
1617 for (int x = 0; x < mipWidth; x++) {
1618 *pOut++ = average2_8888(pIn[0], pIn[mipWidth]);
1619 pIn += 1;
1620 }
1621 pIn += mipWidth;
1622 }
1623 }
1624 }
1625
1626 sendTexture(mipLevel, mipWidth, mipHeight, scaled, alpha);
1627 mipLevel++;
1628 }
1629 }
1630
1631 #else
1632 if (mipmap)
1633 {
1634 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0);
1635 }
1636 #endif
1637
1638 #elif defined(USE_32BPP)
1639 // 8888
1640 // Use automatic MIPMAP generation
1641 if (mipmap)
1642 {
1643 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
1644 }
1645 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1646 if (mipmap)
1647 {
1648 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0);
1649 }
1650 #else
1651 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1652 if (mipmap)
1653 {
1654 int miplevel;
1655
1656 miplevel = 0;
1657 while (scaled_width > 1 || scaled_height > 1)
1658 {
1659 GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
1660 scaled_width >>= 1;
1661 scaled_height >>= 1;
1662 if (scaled_width < 1)
1663 scaled_width = 1;
1664 if (scaled_height < 1)
1665 scaled_height = 1;
1666 miplevel++;
1667 glTexImage2DHelper (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
1668 }
1669 }
1670 #endif
1671 done: ;
1672
1673 if (mipmap)
1674 {
1675 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1676 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1677 }
1678 else
1679 {
1680 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1681 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1682 }
1683 }
1684
1685 #ifdef USE_OPENGLES
1686
GL_Upload8_EXT(byte * data,int width,int height,qboolean mipmap,qboolean alpha)1687 void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
1688 {
1689 int i, s, bytesUsed;
1690 qboolean noalpha;
1691 int p;
1692 static unsigned j;
1693 static unsigned char compressedTextureBuffer[1024*512]; // [512*256];
1694 unsigned char* pTex = compressedTextureBuffer;
1695 int scaled_width, scaled_height;
1696 int miplevel = 0;
1697
1698 int originalScaledWidth;
1699 int originalScaledHeight;
1700
1701 s = width*height;
1702 // if there are no transparent pixels, make it a 3 component
1703 // texture even if it was specified as otherwise
1704 if (alpha)
1705 {
1706 noalpha = true;
1707 for (i=0 ; i<s ; i++)
1708 {
1709 if (data[i] == 255)
1710 noalpha = false;
1711 }
1712
1713 if (alpha && noalpha)
1714 alpha = false;
1715 }
1716 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1717 ;
1718 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1719 ;
1720
1721 scaled_width >>= (int)gl_picmip.value;
1722 scaled_height >>= (int)gl_picmip.value;
1723
1724 if (scaled_width > gl_max_size.value)
1725 scaled_width = (int) gl_max_size.value;
1726 if (scaled_height > gl_max_size.value)
1727 scaled_height = (int) gl_max_size.value;
1728
1729 if (scaled_width * scaled_height > ((int) (sizeof(compressedTextureBuffer) * 3 / 4)))
1730 Sys_Error ("GL_LoadTexture: too big");
1731
1732 // Copy the palette
1733
1734 int entrySize = alpha ? 4 : 3;
1735 int paletteSize = entrySize * 256;
1736 {
1737 byte* pDest = compressedTextureBuffer;
1738 const byte* pSrc = host_basepal;
1739 if(alpha)
1740 {
1741 for(int i = 0; i< 255; i++)
1742 {
1743 *pDest++ = *pSrc++;
1744 *pDest++ = *pSrc++;
1745 *pDest++ = *pSrc++;
1746 *pDest++ = 0xff;
1747 }
1748 // Entry 255 is transparent
1749 *pDest++ = 0x00;
1750 *pDest++ = 0x00;
1751 *pDest++ = 0x00;
1752 *pDest++ = 0x00;
1753 }
1754 else
1755 {
1756 memcpy(pDest, pSrc, paletteSize);
1757 }
1758 }
1759
1760 bytesUsed = paletteSize;
1761 pTex += paletteSize;
1762
1763 texels += scaled_width * scaled_height;
1764
1765 if (scaled_width == width && scaled_height == height)
1766 {
1767 memcpy (pTex, data, scaled_width*scaled_height);
1768 }
1769 else
1770 GL_Resample8BitTexture (data, width, height, pTex, scaled_width, scaled_height);
1771
1772 bytesUsed += scaled_width * scaled_height;
1773
1774 miplevel = 0;
1775
1776 originalScaledWidth = scaled_width;
1777 originalScaledHeight = scaled_height;
1778
1779 if (mipmap)
1780 {
1781 #ifdef SUPPORT_8BIT_MIPMAPGENERATION
1782 miplevel = 1;
1783 while (scaled_width > 1 || scaled_height > 1)
1784 {
1785 byte* pDest = (byte*) pTex + scaled_width * scaled_height;
1786 GL_MipMap8Bit ((byte *)pTex, pDest, scaled_width, scaled_height);
1787 pTex = pDest;
1788 scaled_width >>= 1;
1789 scaled_height >>= 1;
1790 if (scaled_width < 1)
1791 scaled_width = 1;
1792 if (scaled_height < 1)
1793 scaled_height = 1;
1794 bytesUsed += scaled_width * scaled_height;
1795 miplevel++;
1796 }
1797 #else
1798 Sys_Error("Unsupported attempt to generate 8 bit mip mapped texture. #define SUPPORT_8BIT_MIPMAPGENERATION");
1799 #endif
1800 }
1801
1802 GLint internalFormat = alpha ? GL_PALETTE8_RGBA8_OES : GL_PALETTE8_RGB8_OES;
1803 glCompressedTexImage2D (GL_TEXTURE_2D, -miplevel, internalFormat,
1804 originalScaledWidth, originalScaledHeight,
1805 0, bytesUsed, compressedTextureBuffer);
1806
1807 if (mipmap)
1808 {
1809 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1810 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1811 }
1812 else
1813 {
1814 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1815 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1816 }
1817 }
1818
1819 #else
1820
GL_Upload8_EXT(byte * data,int width,int height,qboolean mipmap,qboolean alpha)1821 void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
1822 {
1823 int i, s;
1824 qboolean noalpha;
1825 int p;
1826 static unsigned j;
1827 int samples;
1828 static unsigned char scaled[1024*512]; // [512*256];
1829 int scaled_width, scaled_height;
1830
1831 s = width*height;
1832 // if there are no transparent pixels, make it a 3 component
1833 // texture even if it was specified as otherwise
1834 if (alpha)
1835 {
1836 noalpha = true;
1837 for (i=0 ; i<s ; i++)
1838 {
1839 if (data[i] == 255)
1840 noalpha = false;
1841 }
1842
1843 if (alpha && noalpha)
1844 alpha = false;
1845 }
1846 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
1847 ;
1848 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
1849 ;
1850
1851 scaled_width >>= (int)gl_picmip.value;
1852 scaled_height >>= (int)gl_picmip.value;
1853
1854 if (scaled_width > gl_max_size.value)
1855 scaled_width = gl_max_size.value;
1856 if (scaled_height > gl_max_size.value)
1857 scaled_height = gl_max_size.value;
1858
1859 if (scaled_width * scaled_height > (int) sizeof(scaled))
1860 Sys_Error ("GL_LoadTexture: too big");
1861
1862 samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
1863
1864 texels += scaled_width * scaled_height;
1865
1866 if (scaled_width == width && scaled_height == height)
1867 {
1868 if (!mipmap)
1869 {
1870 glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
1871 goto done;
1872 }
1873 memcpy (scaled, data, width*height);
1874 }
1875 else
1876 GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
1877
1878 glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled);
1879 if (mipmap)
1880 {
1881 #ifdef SUPPORT_8BIT_MIPMAPGENERATION
1882 int miplevel;
1883
1884 miplevel = 0;
1885 while (scaled_width > 1 || scaled_height > 1)
1886 {
1887 GL_MipMap8Bit ((byte *)scaled, (byte*) scaled, scaled_width, scaled_height);
1888 scaled_width >>= 1;
1889 scaled_height >>= 1;
1890 if (scaled_width < 1)
1891 scaled_width = 1;
1892 if (scaled_height < 1)
1893 scaled_height = 1;
1894 miplevel++;
1895 glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
1896 }
1897 #else
1898 Sys_Error("Unsupported attept to generate 8 bit mip mapped texture.");
1899 #endif
1900 }
1901 done: ;
1902
1903
1904 if (mipmap)
1905 {
1906 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
1907 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1908 }
1909 else
1910 {
1911 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
1912 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
1913 }
1914 }
1915
1916 #endif // ! OPENGL_ES
1917
1918 /*
1919 ===============
1920 GL_Upload8
1921 ===============
1922 */
GL_Upload8(byte * data,int width,int height,qboolean mipmap,qboolean alpha)1923 void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
1924 {
1925 static unsigned trans[640*480]; // FIXME, temporary
1926 int i, s;
1927 qboolean noalpha;
1928 int p;
1929
1930 s = width*height;
1931 // if there are no transparent pixels, make it a 3 component
1932 // texture even if it was specified as otherwise
1933 if (alpha)
1934 {
1935 noalpha = true;
1936 for (i=0 ; i<s ; i++)
1937 {
1938 p = data[i];
1939 if (p == 255)
1940 noalpha = false;
1941 trans[i] = d_8to24table[p];
1942 }
1943
1944 if (alpha && noalpha)
1945 alpha = false;
1946 }
1947 else
1948 {
1949 if (s&3)
1950 Sys_Error ("GL_Upload8: s&3");
1951 for (i=0 ; i<s ; i+=4)
1952 {
1953 trans[i] = d_8to24table[data[i]];
1954 trans[i+1] = d_8to24table[data[i+1]];
1955 trans[i+2] = d_8to24table[data[i+2]];
1956 trans[i+3] = d_8to24table[data[i+3]];
1957 }
1958 }
1959
1960 if (VID_Is8bit() && (data!=scrap_texels[0])
1961 #if !defined(USE_OPENGLES)
1962 && !alpha
1963 #endif
1964 ) {
1965 GL_Upload8_EXT (data, width, height, mipmap, alpha);
1966 return;
1967 }
1968 GL_Upload32 (trans, width, height, mipmap, alpha);
1969 }
1970
1971 /*
1972 ================
1973 GL_LoadTexture
1974 ================
1975 */
GL_LoadTexture(const char * identifier,int width,int height,byte * data,qboolean mipmap,qboolean alpha)1976 int GL_LoadTexture (const char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha)
1977 {
1978 qboolean noalpha;
1979 int i, p, s;
1980 gltexture_t *glt;
1981
1982 // see if the texture is allready present
1983 if (identifier[0])
1984 {
1985 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
1986 {
1987 if (!strcmp (identifier, glt->identifier))
1988 {
1989 if (width != glt->width || height != glt->height)
1990 Sys_Error ("GL_LoadTexture: cache mismatch");
1991 return gltextures[i].texnum;
1992 }
1993 }
1994 #ifdef USE_OPENGLES
1995 // Surely we want to remember this new texture.
1996 // Doing this costs 1% fps per timedemo on a DX7 PC,
1997 // probably because of the linear search through the
1998 // texture cache, but it saves 10 MB of VM growth per
1999 // level load. It also makes the GL_TEXTUREMODE
2000 // console command work correctly.
2001 numgltextures++;
2002 #endif
2003 }
2004 else {
2005 glt = &gltextures[numgltextures];
2006 numgltextures++;
2007 }
2008
2009 strcpy (glt->identifier, identifier);
2010 glt->texnum = texture_extension_number;
2011 glt->width = width;
2012 glt->height = height;
2013 glt->mipmap = mipmap;
2014
2015 GL_Bind(texture_extension_number);
2016
2017 #ifdef USE_TEXTURE_STORE
2018
2019 textureStore::get()->create(width, height, data, mipmap, alpha);
2020
2021 #else
2022
2023 GL_Upload8 (data, width, height, mipmap, alpha);
2024
2025 #endif
2026
2027 texture_extension_number++;
2028 return texture_extension_number-1;
2029 }
2030
2031
2032 /****************************************/
2033
2034 static GLenum oldtarget = TEXTURE0_SGIS;
2035
GL_SelectTexture(GLenum target)2036 void GL_SelectTexture (GLenum target)
2037 {
2038 if (!gl_mtexable)
2039 return;
2040 #ifdef USE_OPENGLES
2041 glActiveTexture(target);
2042 #else
2043 qglSelectTextureSGIS(target);
2044 #endif
2045 if (target == oldtarget)
2046 return;
2047 cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture;
2048 currenttexture = cnttextures[target-TEXTURE0_SGIS];
2049 oldtarget = target;
2050 }
2051
2052 // OpenGL ES compatible DrawQuad utility
2053
2054 #define BEGIN_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
2055 #define END_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
2056
DrawQuad_NoTex(float x,float y,float w,float h)2057 void DrawQuad_NoTex(float x, float y, float w, float h)
2058 {
2059 BEGIN_QUAD
2060
2061 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
2062 short index[4] = {0, 1, 2, 3};
2063 glVertexPointer( 2, GL_FLOAT, 0, vertex);
2064 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2065 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
2066 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2067
2068 END_QUAD
2069 }
2070
DrawQuad(float x,float y,float w,float h,float u,float v,float uw,float vh)2071 void DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh)
2072 {
2073 BEGIN_QUAD
2074
2075 float texcoord[2*4] = {u, v, u + uw, v, u + uw, v + vh, u, v + vh};
2076 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h};
2077 unsigned short index[4] = {0, 1, 2, 3};
2078 glTexCoordPointer( 2, GL_FLOAT, 0, texcoord);
2079 glVertexPointer( 2, GL_FLOAT, 0, vertex);
2080 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index);
2081
2082 END_QUAD
2083 }
2084
2085 #ifdef USE_OPENGLES
2086
2087 // Reimplementation of OpenGL functions that are missing in OpenGL ES
2088
glColor3f(GLfloat r,GLfloat g,GLfloat b)2089 void glColor3f(GLfloat r, GLfloat g, GLfloat b)
2090 {
2091 glColor4f(r, g, b, 1.0f);
2092 }
2093
glColor4fv(GLfloat * pColor)2094 void glColor4fv(GLfloat* pColor)
2095 {
2096 glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]);
2097 }
2098
2099 float gVertexBuffer[VERTEXARRAYSIZE];
2100 float gColorBuffer[VERTEXARRAYSIZE];
2101 float gTexCoordBuffer[VERTEXARRAYSIZE];
2102
2103 // Called when we've lost the OpenGL context and have to recreate it.
2104 extern void GL_Init();
2105 extern void R_InitParticleTexture2();
2106 extern void GL_UploadLightmaps();
2107 extern void R_ReloadSky();
2108
GL_ReInit()2109 void GL_ReInit() {
2110 GL_Init();
2111 textureStore::get()->rebindAll();
2112 scrap_dirty = true;
2113 R_InitParticleTexture2();
2114 GL_UploadLightmaps();
2115 R_ReloadSky();
2116 }
2117
2118 #endif
2119
2120 #ifdef DEBUG_OPENGL_CALLS
checkGLImp(const char * state,const char * file,int line)2121 void checkGLImp(const char* state, const char* file, int line) {
2122 GLenum error = glGetError();
2123 if (error != GL_NO_ERROR) {
2124 Sys_Error("%s: error 0x%04X at %s:%d\n", state, error, file, line);
2125 }
2126 }
2127
2128 #endif
2129