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