• 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     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