• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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