1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
29cvar_t		gl_nobind = CVAR2("gl_nobind", "0");
30cvar_t		gl_max_size = CVAR2("gl_max_size", "1024");
31cvar_t		gl_picmip = CVAR2("gl_picmip", "0");
32
33byte		*draw_chars;				// 8*8 graphic characters
34qpic_t		*draw_disc;
35qpic_t		*draw_backtile;
36
37int			translate_texture;
38int			char_texture;
39
40typedef struct
41{
42  int		texnum;
43  float	sl, tl, sh, th;
44} glpic_t;
45
46typedef 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
58typedef union
59{
60    byte buffer[sizeof(qpic_t) + sizeof(glpic_t)];
61    packedGlpic_t pics;
62} conback_t;
63
64conback_t conbackUnion;
65
66#define		conback_buffer (conbackUnion.buffer)
67packedGlpic_t *conback = &conbackUnion.pics;
68
69int		gl_lightmap_format = 4;
70int		gl_solid_format = 3;
71int		gl_alpha_format = 4;
72
73#if 1 // Standard defaults
74int		gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
75int		gl_filter_max = GL_LINEAR;
76#else
77int		gl_filter_min = GL_NEAREST_MIPMAP_NEAREST;
78int		gl_filter_max = GL_NEAREST;
79#endif
80
81int		texels;
82
83typedef 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
92gltexture_t	gltextures[MAX_GLTEXTURES];
93int			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
124class textureStore {
125
126private:
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
177public:
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
277private:
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
385textureStore* textureStore::g_pTextureCache;
386
387#endif
388
389
390void 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
426int			scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
427byte		scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];
428qboolean	scrap_dirty;
429int			scrap_texnum;
430
431// returns a texture number and the position inside it
432int 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
474int	scrap_uploads;
475
476void 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
492typedef 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
500cachepic_t	menu_cachepics[MAX_CACHED_PICS];
501int			menu_numcachepics;
502
503byte		menuplyr_pixels[4096];
504
505int		pic_texels;
506int		pic_count;
507
508
509/*
510================
511GL_LoadPicTexture
512================
513*/
514int GL_LoadPicTexture (qpic_t *pic)
515{
516  return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
517}
518
519
520qpic_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================
566Draw_CachePic
567================
568*/
569qpic_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
616void 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
640typedef struct
641{
642  const char *name;
643  int	minimize, maximize;
644} glmode_t;
645
646glmode_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===============
657Draw_TextureMode_f
658===============
659*/
660void 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===============
705Draw_Init
706===============
707*/
708void 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================
830Draw_Character
831
832Draws one 8*8 graphics character with 0 being transparent.
833It can be clipped to the top of the screen to allow the console to be
834smoothly scrolled off.
835================
836*/
837void 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================
881Draw_String
882================
883*/
884void 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================
896Draw_DebugChar
897
898Draws a single character directly to the upper right corner of the screen.
899This is for debugging lockups by drawing different chars in different parts
900of the code.
901================
902*/
903void Draw_DebugChar (char num)
904{
905}
906
907/*
908=============
909Draw_AlphaPic
910=============
911*/
912void 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=============
950Draw_Pic
951=============
952*/
953void 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=============
986Draw_TransPic
987=============
988*/
989void 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=============
1007Draw_TransPicTranslate
1008
1009Only used for the player color selection menu
1010=============
1011*/
1012void 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================
1062Draw_ConsoleBackground
1063
1064================
1065*/
1066void 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=============
1079Draw_TileClear
1080
1081This repeats a 64*64 tile graphic to fill the screen around a sized down
1082refresh window.
1083=============
1084*/
1085
1086typedef union ByteToInt_t {
1087    byte b[4];
1088    int i;
1089} ByteToInt;
1090
1091void 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=============
1116Draw_Fill
1117
1118Fills a box of pixels with a single color
1119=============
1120*/
1121void 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================
1147Draw_FadeScreen
1148
1149================
1150*/
1151void 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================
1179Draw_BeginDisc
1180
1181Draws the little blue disc in the corner of the screen.
1182Call before beginning any disc IO.
1183================
1184*/
1185void 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================
1201Draw_EndDisc
1202
1203Erases the disc icon.
1204Call after completing any disc IO
1205================
1206*/
1207void Draw_EndDisc (void)
1208{
1209}
1210
1211/*
1212================
1213GL_Set2D
1214
1215Setup as if the screen was 320*200
1216================
1217*/
1218void 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================
1246GL_FindTexture
1247================
1248*/
1249int 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================
1265GL_ResampleTexture
1266================
1267*/
1268void 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================
1295GL_Resample8BitTexture -- JACK
1296================
1297*/
1298void 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================
1326GL_MipMap
1327
1328Operates in place, quartering the size of the texture
1329================
1330*/
1331void 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================
1354GL_MipMap8Bit
1355
1356Mipping for 8 bit textures
1357
1358The "in" and "out" arguments can point to the same buffer if desired
1359================
1360*/
1361void 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
1389void 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
1419inline 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
1430inline 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
1438inline 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
1446inline 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
1453inline 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
1461inline 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
1475void 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===============
1517GL_Upload32
1518===============
1519*/
1520void 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
1669done: ;
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
1685void 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
1819void 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  }
1899done: ;
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===============
1918GL_Upload8
1919===============
1920*/
1921void GL_Upload8 (byte *data, int width, int height,  qboolean mipmap, qboolean alpha)
1922{
1923static	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================
1971GL_LoadTexture
1972================
1973*/
1974int 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
2032static GLenum oldtarget = TEXTURE0_SGIS;
2033
2034void 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
2055void 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
2069void 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
2087void glColor3f(GLfloat r, GLfloat g, GLfloat b)
2088{
2089  glColor4f(r, g, b, 1.0f);
2090}
2091
2092void glColor4fv(GLfloat* pColor)
2093{
2094  glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]);
2095}
2096
2097float gVertexBuffer[VERTEXARRAYSIZE];
2098float gColorBuffer[VERTEXARRAYSIZE];
2099float gTexCoordBuffer[VERTEXARRAYSIZE];
2100
2101// Called when we've lost the OpenGL context and have to recreate it.
2102extern void GL_Init();
2103extern void R_InitParticleTexture2();
2104extern void GL_UploadLightmaps();
2105extern void R_ReloadSky();
2106
2107void 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
2119void 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