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     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 */
    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 
    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 */
    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 */
    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 */
    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 */
    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 */
    905 void Draw_DebugChar (char num)
    906 {
    907 }
    908 
    909 /*
    910 =============
    911 Draw_AlphaPic
    912 =============
    913 */
    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 */
    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 */
    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 */
   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 */
   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 
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 */
   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 
   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 
   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 */
   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 */
   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 
   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 
   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 
   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 
   2089 void glColor3f(GLfloat r, GLfloat g, GLfloat b)
   2090 {
   2091   glColor4f(r, g, b, 1.0f);
   2092 }
   2093 
   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 
   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
   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