Home | History | Annotate | Download | only in WinQuake
      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 
    142         entry() {
    143             next = 0;
    144             prev = 0;
    145             real_texnum = UNUSED;
    146             pData = 0;
    147         }
    148 
    149 
    150         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 
    161         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 
    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 
    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 
    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 
    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.
    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 
    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 
    317     ~textureStore() {
    318         munmap(mBase, mCapacity);
    319         COM_CloseFile(mFileId);
    320     }
    321 
    322     void grabMagicTextureIds() {
    323         // reserve these two texture ids.
    324         glBindTexture(GL_TEXTURE_2D, UNUSED);
    325         glBindTexture(GL_TEXTURE_2D, PAGED_OUT);
    326     }
    327 
    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 
    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 
    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 
    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
    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 
    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 */
    514 int GL_LoadPicTexture (qpic_t *pic)
    515 {
    516   return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
    517 }
    518 
    519 
    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 */
    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 
    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 */
    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 */
    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 */
    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 */
    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 */
    903 void Draw_DebugChar (char num)
    904 {
    905 }
    906 
    907 /*
    908 =============
    909 Draw_AlphaPic
    910 =============
    911 */
    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 */
    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 */
    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 */
   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 */
   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 
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 */
   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 
   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 
   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 */
   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 */
   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 
   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 
   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 
   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 
   2087 void glColor3f(GLfloat r, GLfloat g, GLfloat b)
   2088 {
   2089   glColor4f(r, g, b, 1.0f);
   2090 }
   2091 
   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 
   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
   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