1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 21 // draw.c -- this is the only file outside the refresh that touches the 22 // vid buffer 23 24 #include "quakedef.h" 25 26 #define GL_COLOR_INDEX8_EXT 0x80E5 27 28 29 cvar_t gl_nobind = CVAR2("gl_nobind", "0"); 30 cvar_t gl_max_size = CVAR2("gl_max_size", "1024"); 31 cvar_t gl_picmip = CVAR2("gl_picmip", "0"); 32 33 byte *draw_chars; // 8*8 graphic characters 34 qpic_t *draw_disc; 35 qpic_t *draw_backtile; 36 37 int translate_texture; 38 int char_texture; 39 40 typedef struct 41 { 42 int texnum; 43 float sl, tl, sh, th; 44 } glpic_t; 45 46 typedef union 47 { 48 qpic_t qpic; 49 struct { 50 // First part is from qpic 51 int width; 52 int height; 53 54 glpic_t glpic; 55 } g; 56 } packedGlpic_t; 57 58 typedef union 59 { 60 byte buffer[sizeof(qpic_t) + sizeof(glpic_t)]; 61 packedGlpic_t pics; 62 } conback_t; 63 64 conback_t conbackUnion; 65 66 #define conback_buffer (conbackUnion.buffer) 67 packedGlpic_t *conback = &conbackUnion.pics; 68 69 int gl_lightmap_format = 4; 70 int gl_solid_format = 3; 71 int gl_alpha_format = 4; 72 73 #if 1 // Standard defaults 74 int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; 75 int gl_filter_max = GL_LINEAR; 76 #else 77 int gl_filter_min = GL_NEAREST_MIPMAP_NEAREST; 78 int gl_filter_max = GL_NEAREST; 79 #endif 80 81 int texels; 82 83 typedef struct 84 { 85 int texnum; 86 char identifier[64]; 87 int width, height; 88 qboolean mipmap; 89 } gltexture_t; 90 91 #define MAX_GLTEXTURES 1024 92 gltexture_t gltextures[MAX_GLTEXTURES]; 93 int numgltextures; 94 95 // GlQuake creates textures, but never deletes them. This approach works fine on 96 // computers with lots of RAM and/or swap, but not so well on our swapless 97 // RAM-constrained system. 98 // 99 // We work around this problem by adding a level of indirection. We 100 // hook GL_LoadTexture to store enough information to recreate a texture. 101 // Then we hook GL_BindTexture to consult a table to see whether a texture 102 // is currently in memory or not. If it isn't, we throw out some other 103 // texture and bring the required texture back into memory. In this way 104 // we can limit the working set of textures. 105 // 106 // The texture data is stored in a memory-mapped file that is backed by 107 // a file on the sd card. It is recreated each time the game is run. We 108 // don't bother deleting it. 109 110 #define USE_TEXTURE_STORE 111 112 #ifdef USE_TEXTURE_STORE 113 114 #include <unistd.h> 115 #include <sys/types.h> 116 #include <sys/mman.h> 117 #include <fcntl.h> 118 #include <errno.h> 119 120 // Allow named textures to be evicted from memory. 121 122 #define TEXTURE_STORE_NAME "glquake/texture.store" 123 124 class textureStore { 125 126 private: 127 static const GLuint UNUSED = (GLuint) -2; 128 static const GLuint PAGED_OUT = (GLuint) -1; 129 130 struct entry 131 { 132 entry* next; 133 entry* prev; 134 GLuint real_texnum; // UNUSED, PAGED_OUT 135 byte* pData; // 0 ==> not created by us. 136 size_t size; 137 qboolean alpha; 138 int width; 139 int height; 140 qboolean mipmap; 141 142 entry() { 143 next = 0; 144 prev = 0; 145 real_texnum = UNUSED; 146 pData = 0; 147 } 148 149 150 void unlink() { 151 if (next) { 152 next->prev = prev; 153 } 154 if (prev) { 155 prev->next = next; 156 } 157 next = 0; 158 prev = 0; 159 } 160 161 void insertBefore(entry* e){ 162 if (e) { 163 prev = e->prev; 164 if ( prev ) { 165 prev->next = this; 166 } 167 next = e; 168 e->prev = this; 169 } 170 else { 171 prev = 0; 172 next = 0; 173 } 174 } 175 }; 176 177 public: 178 179 static textureStore* get() { 180 if (g_pTextureCache == 0) { 181 g_pTextureCache = new textureStore(); 182 } 183 return g_pTextureCache; 184 } 185 186 // Equivalent of glBindTexture, but uses the virtual texture table 187 188 void bind(int virtTexNum) { 189 if ( (unsigned int) virtTexNum >= TEXTURE_STORE_NUM_TEXTURES) { 190 Sys_Error("not in the range we're managing"); 191 } 192 mBoundTextureID = virtTexNum; 193 entry* e = &mTextures[virtTexNum]; 194 195 if ( e->real_texnum == UNUSED) { 196 glGenTextures( 1, &e->real_texnum); 197 } 198 199 if ( e->pData == 0) { 200 glBindTexture(GL_TEXTURE_2D, e->real_texnum); 201 return; 202 } 203 204 update(e); 205 } 206 207 void update(entry* e) 208 { 209 // Update the "LRU" part of the cache 210 unlink(e); 211 e->insertBefore(mFirst); 212 mFirst = e; 213 if (! mLast) { 214 mLast = e; 215 } 216 217 if (e->real_texnum == PAGED_OUT ) { 218 // Create a real texture 219 // Make sure there is enough room for this texture 220 ensure(e->size); 221 222 glGenTextures( 1, &e->real_texnum); 223 224 glBindTexture(GL_TEXTURE_2D, e->real_texnum); 225 GL_Upload8 (e->pData, e->width, e->height, e->mipmap, 226 e->alpha); 227 } 228 else { 229 glBindTexture(GL_TEXTURE_2D, e->real_texnum); 230 } 231 } 232 233 // Create a texture, and remember the data so we can create 234 // it again later. 235 236 void create(int width, int height, byte* data, qboolean mipmap, 237 qboolean alpha) { 238 int size = width * height; 239 if (size + mLength > mCapacity) { 240 Sys_Error("Ran out of virtual texture space. %d", size); 241 }; 242 entry* e = &mTextures[mBoundTextureID]; 243 244 // Call evict in case the currently bound texture id is already 245 // in use. (Shouldn't happen in Quake.) 246 // To Do: reclaim the old texture memory from the virtual memory. 247 248 evict(e); 249 250 e->alpha = alpha; 251 e->pData = mBase + mLength; 252 memcpy(e->pData, data, size); 253 e->size = size; 254 e->width = width; 255 e->height = height; 256 e->mipmap = mipmap; 257 e->real_texnum = PAGED_OUT; 258 mLength += size; 259 260 update(e); 261 } 262 263 // Re-upload the current textures because we've been reset. 264 void rebindAll() { 265 grabMagicTextureIds(); 266 for (entry* e = mFirst; e; e = e->next ) { 267 if (! (e->real_texnum == UNUSED || e->real_texnum == PAGED_OUT)) { 268 glBindTexture(GL_TEXTURE_2D, e->real_texnum); 269 if (e->pData) { 270 GL_Upload8 (e->pData, e->width, e->height, e->mipmap, 271 e->alpha); 272 } 273 } 274 } 275 } 276 277 private: 278 279 textureStore() { 280 grabMagicTextureIds(); 281 mFirst = 0; 282 mLast = 0; 283 mTextureCount = 0; 284 285 char fullpath[MAX_OSPATH]; 286 sprintf(fullpath, "%s/%s", com_gamedir, TEXTURE_STORE_NAME); 287 288 mFileId = open(fullpath, O_RDWR | O_CREAT, 0666); 289 if ( mFileId == -1 ) { 290 Sys_Error("Could not open texture store file %s: %d", fullpath, 291 errno); 292 } 293 294 if (-1 == lseek(mFileId, TEXTURE_STORE_SIZE-1, SEEK_SET)) { 295 Sys_Error("Could not extend the texture store file size. %d", 296 errno); 297 } 298 char end; 299 end = 0; 300 if (-1 == write(mFileId, &end, 1)) { 301 Sys_Error("Could not write last byte of the texture store file. %d", 302 errno); 303 } 304 305 mBase = (byte*) mmap((caddr_t)0, TEXTURE_STORE_SIZE, 306 PROT_READ | PROT_WRITE, MAP_PRIVATE, mFileId, 0); 307 308 if (mBase == (byte*) -1) { 309 Sys_Error("Could not mmap file %s: %d", fullpath, errno); 310 } 311 mLength = 0; 312 mCapacity = TEXTURE_STORE_SIZE; 313 mRamUsed = 0; 314 mRamSize = LIVE_TEXTURE_LIMIT; 315 } 316 317 ~textureStore() { 318 munmap(mBase, mCapacity); 319 COM_CloseFile(mFileId); 320 } 321 322 void grabMagicTextureIds() { 323 // reserve these two texture ids. 324 glBindTexture(GL_TEXTURE_2D, UNUSED); 325 glBindTexture(GL_TEXTURE_2D, PAGED_OUT); 326 } 327 328 void unlink(entry* e) { 329 if (e == mFirst) { 330 mFirst = e->next; 331 } 332 if (e == mLast) { 333 mLast = e->prev; 334 } 335 e->unlink(); 336 } 337 338 void ensure(int size) { 339 while ( mRamSize - mRamUsed < (unsigned int) size) { 340 entry* e = mLast; 341 if(! e) { 342 Sys_Error("Ran out of entries"); 343 return; 344 } 345 evict(e); 346 } 347 mRamUsed += size; 348 } 349 350 void evict(entry* e) { 351 unlink(e); 352 if ( e->pData ) { 353 glDeleteTextures(1, &e->real_texnum); 354 e->real_texnum = PAGED_OUT; 355 mRamUsed -= e->size; 356 } 357 } 358 359 static const size_t TEXTURE_STORE_SIZE = 16 * 1024 * 1024; 360 static const size_t LIVE_TEXTURE_LIMIT = 1 * 1024 * 1024; 361 static const size_t TEXTURE_STORE_NUM_TEXTURES = 512; 362 363 int mFileId; 364 byte* mBase; // Base address of the memory mapped file 365 size_t mLength; // How much of the mm file we are currently using 366 size_t mCapacity; // Total size of the memory mapped file 367 368 // Keep track of texture RAM. 369 size_t mRamUsed; 370 size_t mRamSize; 371 372 // The virtual textures 373 374 375 entry mTextures[MAX_GLTEXTURES]; 376 entry* mFirst; // LRU queue 377 entry* mLast; 378 size_t mTextureCount; // How many virtual textures have been allocated 379 380 static textureStore* g_pTextureCache; 381 382 int mBoundTextureID; 383 }; 384 385 textureStore* textureStore::g_pTextureCache; 386 387 #endif 388 389 390 void GL_Bind (int texnum) 391 { 392 if (gl_nobind.value) 393 texnum = char_texture; 394 if (currenttexture == texnum) 395 return; 396 currenttexture = texnum; 397 #ifdef _WIN32 398 bindTexFunc (GL_TEXTURE_2D, texnum); 399 #else 400 401 #ifdef USE_TEXTURE_STORE 402 textureStore::get()->bind(texnum); 403 #else 404 glBindTexture(GL_TEXTURE_2D, texnum); 405 #endif 406 407 #endif 408 } 409 410 411 /* 412 ============================================================================= 413 414 scrap allocation 415 416 Allocate all the little status bar obejcts into a single texture 417 to crutch up stupid hardware / drivers 418 419 ============================================================================= 420 */ 421 422 #define MAX_SCRAPS 2 423 #define BLOCK_WIDTH 256 424 #define BLOCK_HEIGHT 256 425 426 int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; 427 byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4]; 428 qboolean scrap_dirty; 429 int scrap_texnum; 430 431 // returns a texture number and the position inside it 432 int Scrap_AllocBlock (int w, int h, int *x, int *y) 433 { 434 int i, j; 435 int best, best2; 436 int bestx; 437 int texnum; 438 439 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) 440 { 441 best = BLOCK_HEIGHT; 442 443 for (i=0 ; i<BLOCK_WIDTH-w ; i++) 444 { 445 best2 = 0; 446 447 for (j=0 ; j<w ; j++) 448 { 449 if (scrap_allocated[texnum][i+j] >= best) 450 break; 451 if (scrap_allocated[texnum][i+j] > best2) 452 best2 = scrap_allocated[texnum][i+j]; 453 } 454 if (j == w) 455 { // this is a valid spot 456 *x = i; 457 *y = best = best2; 458 } 459 } 460 461 if (best + h > BLOCK_HEIGHT) 462 continue; 463 464 for (i=0 ; i<w ; i++) 465 scrap_allocated[texnum][*x + i] = best + h; 466 467 return texnum; 468 } 469 470 Sys_Error ("Scrap_AllocBlock: full"); 471 return 0; 472 } 473 474 int scrap_uploads; 475 476 void Scrap_Upload (void) 477 { 478 int texnum; 479 480 scrap_uploads++; 481 482 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) { 483 GL_Bind(scrap_texnum + texnum); 484 GL_Upload8 (scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, true); 485 } 486 scrap_dirty = false; 487 } 488 489 //============================================================================= 490 /* Support Routines */ 491 492 typedef struct cachepic_s 493 { 494 char name[MAX_QPATH]; 495 qpic_t pic; 496 byte padding[32]; // for appended glpic 497 } cachepic_t; 498 499 #define MAX_CACHED_PICS 128 500 cachepic_t menu_cachepics[MAX_CACHED_PICS]; 501 int menu_numcachepics; 502 503 byte menuplyr_pixels[4096]; 504 505 int pic_texels; 506 int pic_count; 507 508 509 /* 510 ================ 511 GL_LoadPicTexture 512 ================ 513 */ 514 int GL_LoadPicTexture (qpic_t *pic) 515 { 516 return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true); 517 } 518 519 520 qpic_t *Draw_PicFromWad (const char *name) 521 { 522 packedGlpic_t *pp; 523 524 pp = (packedGlpic_t*) W_GetLumpName (name); 525 526 qpic_t* p = & pp->qpic; 527 glpic_t* gl = & pp->g.glpic; 528 529 // load little ones into the scrap 530 if (p->width < 64 && p->height < 64) 531 { 532 int x, y; 533 int i, j, k; 534 int texnum; 535 536 x = 0; 537 y = 0; 538 texnum = Scrap_AllocBlock (p->width, p->height, &x, &y); 539 scrap_dirty = true; 540 k = 0; 541 for (i=0 ; i<p->height ; i++) 542 for (j=0 ; j<p->width ; j++, k++) 543 scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k]; 544 texnum += scrap_texnum; 545 gl->texnum = texnum; 546 gl->sl = (x+0.01)/(float)BLOCK_WIDTH; 547 gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH; 548 gl->tl = (y+0.01)/(float)BLOCK_WIDTH; 549 gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH; 550 551 pic_count++; 552 pic_texels += p->width*p->height; 553 } 554 else 555 { 556 gl->texnum = GL_LoadPicTexture (p); 557 gl->sl = 0; 558 gl->sh = 1; 559 gl->tl = 0; 560 gl->th = 1; 561 } 562 return p; 563 } 564 565 566 /* 567 ================ 568 Draw_CachePic 569 ================ 570 */ 571 qpic_t *Draw_CachePic (const char *path) 572 { 573 cachepic_t *pic; 574 int i; 575 qpic_t *dat; 576 glpic_t *gl; 577 578 for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++) 579 if (!strcmp (path, pic->name)) 580 return &pic->pic; 581 582 if (menu_numcachepics == MAX_CACHED_PICS) 583 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); 584 menu_numcachepics++; 585 strcpy (pic->name, path); 586 587 // 588 // load the pic from disk 589 // 590 dat = (qpic_t *)COM_LoadTempFile (path); 591 if (!dat) 592 Sys_Error ("Draw_CachePic: failed to load %s", path); 593 SwapPic (dat); 594 595 // HACK HACK HACK --- we need to keep the bytes for 596 // the translatable player picture just for the menu 597 // configuration dialog 598 if (!strcmp (path, "gfx/menuplyr.lmp")) 599 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height); 600 601 pic->pic.width = dat->width; 602 pic->pic.height = dat->height; 603 604 glpic_t temp; 605 gl = &temp; 606 gl->texnum = GL_LoadPicTexture (dat); 607 gl->sl = 0; 608 gl->sh = 1; 609 gl->tl = 0; 610 gl->th = 1; 611 612 memcpy(pic->pic.data, &temp, sizeof(temp)); 613 614 return &pic->pic; 615 } 616 617 618 void Draw_CharToConback (int num, byte *dest) 619 { 620 int row, col; 621 byte *source; 622 int drawline; 623 int x; 624 625 row = num>>4; 626 col = num&15; 627 source = draw_chars + (row<<10) + (col<<3); 628 629 drawline = 8; 630 631 while (drawline--) 632 { 633 for (x=0 ; x<8 ; x++) 634 if (source[x] != 255) 635 dest[x] = 0x60 + source[x]; 636 source += 128; 637 dest += 320; 638 } 639 640 } 641 642 typedef struct 643 { 644 const char *name; 645 int minimize, maximize; 646 } glmode_t; 647 648 glmode_t modes[] = { 649 {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, 650 {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, 651 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, 652 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, 653 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, 654 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} 655 }; 656 657 /* 658 =============== 659 Draw_TextureMode_f 660 =============== 661 */ 662 void Draw_TextureMode_f (void) 663 { 664 int i; 665 gltexture_t *glt; 666 667 if (Cmd_Argc() == 1) 668 { 669 for (i=0 ; i< 6 ; i++) 670 if (gl_filter_min == modes[i].minimize) 671 { 672 Con_Printf ("%s\n", modes[i].name); 673 return; 674 } 675 Con_Printf ("current filter is unknown???\n"); 676 return; 677 } 678 679 for (i=0 ; i< 6 ; i++) 680 { 681 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) ) 682 break; 683 } 684 if (i == 6) 685 { 686 Con_Printf ("bad filter name\n"); 687 return; 688 } 689 690 gl_filter_min = modes[i].minimize; 691 gl_filter_max = modes[i].maximize; 692 693 // change all the existing mipmap texture objects 694 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++) 695 { 696 if (glt->mipmap) 697 { 698 GL_Bind (glt->texnum); 699 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 700 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 701 } 702 } 703 } 704 705 /* 706 =============== 707 Draw_Init 708 =============== 709 */ 710 void Draw_Init (void) 711 { 712 int i; 713 qpic_t *cb; 714 byte *dest, *src; 715 int x, y; 716 char ver[40]; 717 glpic_t *gl; 718 int start; 719 byte *ncdata; 720 int f, fstep; 721 722 723 Cvar_RegisterVariable (&gl_nobind); 724 Cvar_RegisterVariable (&gl_max_size); 725 Cvar_RegisterVariable (&gl_picmip); 726 727 // 3dfx can only handle 256 wide textures 728 if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || 729 strstr((char *)gl_renderer, "Glide")) 730 Cvar_Set ("gl_max_size", "256"); 731 732 Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f); 733 734 // load the console background and the charset 735 // by hand, because we need to write the version 736 // string into the background before turning 737 // it into a texture 738 draw_chars = (byte*) W_GetLumpName ("conchars"); 739 for (i=0 ; i<256*64 ; i++) 740 if (draw_chars[i] == 0) 741 draw_chars[i] = 255; // proper transparent color 742 743 // now turn them into textures 744 char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true); 745 746 start = Hunk_LowMark(); 747 748 cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp"); 749 if (!cb) 750 Sys_Error ("Couldn't load gfx/conback.lmp"); 751 SwapPic (cb); 752 753 // hack the version number directly into the pic 754 #if defined(__linux__) 755 sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION); 756 #else 757 sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION); 758 #endif 759 dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver); 760 y = strlen(ver); 761 for (x=0 ; x<y ; x++) 762 Draw_CharToConback (ver[x], dest+(x<<3)); 763 764 #if 0 765 conback->width = vid.conwidth; 766 conback->height = vid.conheight; 767 768 // scale console to vid size 769 dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback"); 770 771 for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth) 772 { 773 src = cb->data + cb->width * (y*cb->height/vid.conheight); 774 if (vid.conwidth == cb->width) 775 memcpy (dest, src, vid.conwidth); 776 else 777 { 778 f = 0; 779 fstep = cb->width*0x10000/vid.conwidth; 780 for (x=0 ; x<vid.conwidth ; x+=4) 781 { 782 dest[x] = src[f>>16]; 783 f += fstep; 784 dest[x+1] = src[f>>16]; 785 f += fstep; 786 dest[x+2] = src[f>>16]; 787 f += fstep; 788 dest[x+3] = src[f>>16]; 789 f += fstep; 790 } 791 } 792 } 793 #else 794 conback->g.width = cb->width; 795 conback->g.height = cb->height; 796 ncdata = cb->data; 797 #endif 798 799 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 800 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 801 802 gl = &conback->g.glpic; 803 gl->texnum = GL_LoadTexture ("conback", conback->g.width, conback->g.height, ncdata, false, false); 804 gl->sl = 0; 805 gl->sh = 1; 806 gl->tl = 0; 807 gl->th = 1; 808 conback->g.width = vid.width; 809 conback->g.height = vid.height; 810 811 // free loaded console 812 Hunk_FreeToLowMark(start); 813 814 // save a texture slot for translated picture 815 translate_texture = texture_extension_number++; 816 817 // save slots for scraps 818 scrap_texnum = texture_extension_number; 819 texture_extension_number += MAX_SCRAPS; 820 821 // 822 // get the other pics we need 823 // 824 draw_disc = Draw_PicFromWad ("disc"); 825 draw_backtile = Draw_PicFromWad ("backtile"); 826 } 827 828 829 830 /* 831 ================ 832 Draw_Character 833 834 Draws one 8*8 graphics character with 0 being transparent. 835 It can be clipped to the top of the screen to allow the console to be 836 smoothly scrolled off. 837 ================ 838 */ 839 void Draw_Character (int x, int y, int num) 840 { 841 byte *dest; 842 byte *source; 843 unsigned short *pusdest; 844 int drawline; 845 int row, col; 846 float frow, fcol, size; 847 848 if (num == 32) 849 return; // space 850 851 num &= 255; 852 853 if (y <= -8) 854 return; // totally off screen 855 856 row = num>>4; 857 col = num&15; 858 859 frow = row*0.0625; 860 fcol = col*0.0625; 861 size = 0.0625; 862 863 GL_Bind (char_texture); 864 865 #ifdef USE_OPENGLES 866 DrawQuad(x, y, 8, 8, fcol, frow, size, size); 867 #else 868 glBegin (GL_QUADS); 869 glTexCoord2f (fcol, frow); 870 glVertex2f (x, y); 871 glTexCoord2f (fcol + size, frow); 872 glVertex2f (x+8, y); 873 glTexCoord2f (fcol + size, frow + size); 874 glVertex2f (x+8, y+8); 875 glTexCoord2f (fcol, frow + size); 876 glVertex2f (x, y+8); 877 glEnd (); 878 #endif 879 } 880 881 /* 882 ================ 883 Draw_String 884 ================ 885 */ 886 void Draw_String (int x, int y, const char *str) 887 { 888 while (*str) 889 { 890 Draw_Character (x, y, *str); 891 str++; 892 x += 8; 893 } 894 } 895 896 /* 897 ================ 898 Draw_DebugChar 899 900 Draws a single character directly to the upper right corner of the screen. 901 This is for debugging lockups by drawing different chars in different parts 902 of the code. 903 ================ 904 */ 905 void Draw_DebugChar (char num) 906 { 907 } 908 909 /* 910 ============= 911 Draw_AlphaPic 912 ============= 913 */ 914 void Draw_AlphaPic (int x, int y, packedGlpic_t *ppic, float alpha) 915 { 916 byte *dest, *source; 917 unsigned short *pusdest; 918 int v, u; 919 glpic_t *gl; 920 921 if (scrap_dirty) 922 Scrap_Upload (); 923 gl = & ppic->g.glpic; 924 glDisable(GL_ALPHA_TEST); 925 glEnable (GL_BLEND); 926 // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 927 // glCullFace(GL_FRONT); 928 glColor4f (1,1,1,alpha); 929 GL_Bind (gl->texnum); 930 #ifdef USE_OPENGLES 931 DrawQuad(x, y, ppic->g.width, ppic->g.height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl); 932 #else 933 glBegin (GL_QUADS); 934 glTexCoord2f (gl->sl, gl->tl); 935 glVertex2f (x, y); 936 glTexCoord2f (gl->sh, gl->tl); 937 glVertex2f (x+pic->width, y); 938 glTexCoord2f (gl->sh, gl->th); 939 glVertex2f (x+pic->width, y+pic->height); 940 glTexCoord2f (gl->sl, gl->th); 941 glVertex2f (x, y+pic->height); 942 glEnd (); 943 #endif 944 glColor4f (1,1,1,1); 945 glEnable(GL_ALPHA_TEST); 946 glDisable (GL_BLEND); 947 } 948 949 950 /* 951 ============= 952 Draw_Pic 953 ============= 954 */ 955 void Draw_Pic (int x, int y, qpic_t *pic) 956 { 957 byte *dest, *source; 958 unsigned short *pusdest; 959 int v, u; 960 glpic_t *gl; 961 962 if (scrap_dirty) 963 Scrap_Upload (); 964 glpic_t temp; 965 memcpy(&temp, pic->data, sizeof(temp)); 966 gl = & temp; 967 glColor4f (1,1,1,1); 968 GL_Bind (gl->texnum); 969 #ifdef USE_OPENGLES 970 DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl); 971 #else 972 glBegin (GL_QUADS); 973 glTexCoord2f (gl->sl, gl->tl); 974 glVertex2f (x, y); 975 glTexCoord2f (gl->sh, gl->tl); 976 glVertex2f (x+pic->width, y); 977 glTexCoord2f (gl->sh, gl->th); 978 glVertex2f (x+pic->width, y+pic->height); 979 glTexCoord2f (gl->sl, gl->th); 980 glVertex2f (x, y+pic->height); 981 glEnd (); 982 #endif 983 } 984 985 986 /* 987 ============= 988 Draw_TransPic 989 ============= 990 */ 991 void Draw_TransPic (int x, int y, qpic_t *pic) 992 { 993 byte *dest, *source, tbyte; 994 unsigned short *pusdest; 995 int v, u; 996 997 if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || 998 (unsigned)(y + pic->height) > vid.height) 999 { 1000 Sys_Error ("Draw_TransPic: bad coordinates"); 1001 } 1002 1003 Draw_Pic (x, y, pic); 1004 } 1005 1006 1007 /* 1008 ============= 1009 Draw_TransPicTranslate 1010 1011 Only used for the player color selection menu 1012 ============= 1013 */ 1014 void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation) 1015 { 1016 int v, u, c; 1017 unsigned trans[64*64], *dest; 1018 byte *src; 1019 int p; 1020 1021 GL_Bind (translate_texture); 1022 1023 c = pic->width * pic->height; 1024 1025 dest = trans; 1026 for (v=0 ; v<64 ; v++, dest += 64) 1027 { 1028 src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width]; 1029 for (u=0 ; u<64 ; u++) 1030 { 1031 p = src[(u*pic->width)>>6]; 1032 if (p == 255) 1033 dest[u] = p; 1034 else 1035 dest[u] = d_8to24table[translation[p]]; 1036 } 1037 } 1038 1039 glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); 1040 1041 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1042 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1043 1044 glColor3f (1,1,1); 1045 #ifdef USE_OPENGLES 1046 DrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1); 1047 #else 1048 glBegin (GL_QUADS); 1049 glTexCoord2f (0, 0); 1050 glVertex2f (x, y); 1051 glTexCoord2f (1, 0); 1052 glVertex2f (x+pic->width, y); 1053 glTexCoord2f (1, 1); 1054 glVertex2f (x+pic->width, y+pic->height); 1055 glTexCoord2f (0, 1); 1056 glVertex2f (x, y+pic->height); 1057 glEnd (); 1058 #endif 1059 } 1060 1061 1062 /* 1063 ================ 1064 Draw_ConsoleBackground 1065 1066 ================ 1067 */ 1068 void Draw_ConsoleBackground (int lines) 1069 { 1070 int y = (vid.height * 3) >> 2; 1071 1072 if (lines > y) 1073 Draw_Pic(0, lines - vid.height, &conback->qpic); 1074 else 1075 Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y); 1076 } 1077 1078 1079 /* 1080 ============= 1081 Draw_TileClear 1082 1083 This repeats a 64*64 tile graphic to fill the screen around a sized down 1084 refresh window. 1085 ============= 1086 */ 1087 1088 typedef union ByteToInt_t { 1089 byte b[4]; 1090 int i; 1091 } ByteToInt; 1092 1093 void Draw_TileClear (int x, int y, int w, int h) 1094 { 1095 glColor3f (1,1,1); 1096 ByteToInt b; 1097 memcpy(b.b, draw_backtile->data, sizeof(b.b)); 1098 GL_Bind (b.i); 1099 #ifdef USE_OPENGLES 1100 DrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0); 1101 #else 1102 glBegin (GL_QUADS); 1103 glTexCoord2f (x/64.0, y/64.0); 1104 glVertex2f (x, y); 1105 glTexCoord2f ( (x+w)/64.0, y/64.0); 1106 glVertex2f (x+w, y); 1107 glTexCoord2f ( (x+w)/64.0, (y+h)/64.0); 1108 glVertex2f (x+w, y+h); 1109 glTexCoord2f ( x/64.0, (y+h)/64.0 ); 1110 glVertex2f (x, y+h); 1111 glEnd (); 1112 #endif 1113 } 1114 1115 1116 /* 1117 ============= 1118 Draw_Fill 1119 1120 Fills a box of pixels with a single color 1121 ============= 1122 */ 1123 void Draw_Fill (int x, int y, int w, int h, int c) 1124 { 1125 glDisable (GL_TEXTURE_2D); 1126 glColor3f (host_basepal[c*3]/255.0, 1127 host_basepal[c*3+1]/255.0, 1128 host_basepal[c*3+2]/255.0); 1129 1130 #ifdef USE_OPENGLES 1131 DrawQuad_NoTex(x, y, w, h); 1132 #else 1133 glBegin (GL_QUADS); 1134 1135 glVertex2f (x,y); 1136 glVertex2f (x+w, y); 1137 glVertex2f (x+w, y+h); 1138 glVertex2f (x, y+h); 1139 1140 glEnd (); 1141 #endif 1142 glColor3f (1,1,1); 1143 glEnable (GL_TEXTURE_2D); 1144 } 1145 //============================================================================= 1146 1147 /* 1148 ================ 1149 Draw_FadeScreen 1150 1151 ================ 1152 */ 1153 void Draw_FadeScreen (void) 1154 { 1155 glEnable (GL_BLEND); 1156 glDisable (GL_TEXTURE_2D); 1157 glColor4f (0, 0, 0, 0.8); 1158 #ifdef USE_OPENGLES 1159 DrawQuad_NoTex(0, 0, vid.width, vid.height); 1160 #else 1161 glBegin (GL_QUADS); 1162 1163 glVertex2f (0,0); 1164 glVertex2f (vid.width, 0); 1165 glVertex2f (vid.width, vid.height); 1166 glVertex2f (0, vid.height); 1167 1168 glEnd (); 1169 #endif 1170 glColor4f (1,1,1,1); 1171 glEnable (GL_TEXTURE_2D); 1172 glDisable (GL_BLEND); 1173 1174 Sbar_Changed(); 1175 } 1176 1177 //============================================================================= 1178 1179 /* 1180 ================ 1181 Draw_BeginDisc 1182 1183 Draws the little blue disc in the corner of the screen. 1184 Call before beginning any disc IO. 1185 ================ 1186 */ 1187 void Draw_BeginDisc (void) 1188 { 1189 if (!draw_disc) 1190 return; 1191 #ifdef USE_OPENGLES 1192 // !!! Implement this 1193 #else 1194 glDrawBuffer (GL_FRONT); 1195 Draw_Pic (vid.width - 24, 0, draw_disc); 1196 glDrawBuffer (GL_BACK); 1197 #endif 1198 } 1199 1200 1201 /* 1202 ================ 1203 Draw_EndDisc 1204 1205 Erases the disc icon. 1206 Call after completing any disc IO 1207 ================ 1208 */ 1209 void Draw_EndDisc (void) 1210 { 1211 } 1212 1213 /* 1214 ================ 1215 GL_Set2D 1216 1217 Setup as if the screen was 320*200 1218 ================ 1219 */ 1220 void GL_Set2D (void) 1221 { 1222 glViewport (glx, gly, glwidth, glheight); 1223 1224 glMatrixMode(GL_PROJECTION); 1225 glLoadIdentity (); 1226 #ifdef USE_OPENGLES 1227 glOrthof (0, vid.width, vid.height, 0, -99999, 99999); 1228 #else 1229 glOrtho (0, vid.width, vid.height, 0, -99999, 99999); 1230 #endif 1231 1232 glMatrixMode(GL_MODELVIEW); 1233 glLoadIdentity (); 1234 1235 glDisable (GL_DEPTH_TEST); 1236 glDisable (GL_CULL_FACE); 1237 glDisable (GL_BLEND); 1238 glEnable (GL_ALPHA_TEST); 1239 // glDisable (GL_ALPHA_TEST); 1240 1241 glColor4f (1,1,1,1); 1242 } 1243 1244 //==================================================================== 1245 1246 /* 1247 ================ 1248 GL_FindTexture 1249 ================ 1250 */ 1251 int GL_FindTexture (const char *identifier) 1252 { 1253 int i; 1254 gltexture_t *glt; 1255 1256 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++) 1257 { 1258 if (!strcmp (identifier, glt->identifier)) 1259 return gltextures[i].texnum; 1260 } 1261 1262 return -1; 1263 } 1264 1265 /* 1266 ================ 1267 GL_ResampleTexture 1268 ================ 1269 */ 1270 void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) 1271 { 1272 int i, j; 1273 unsigned *inrow; 1274 unsigned frac, fracstep; 1275 1276 fracstep = inwidth*0x10000/outwidth; 1277 for (i=0 ; i<outheight ; i++, out += outwidth) 1278 { 1279 inrow = in + inwidth*(i*inheight/outheight); 1280 frac = fracstep >> 1; 1281 for (j=0 ; j<outwidth ; j+=4) 1282 { 1283 out[j] = inrow[frac>>16]; 1284 frac += fracstep; 1285 out[j+1] = inrow[frac>>16]; 1286 frac += fracstep; 1287 out[j+2] = inrow[frac>>16]; 1288 frac += fracstep; 1289 out[j+3] = inrow[frac>>16]; 1290 frac += fracstep; 1291 } 1292 } 1293 } 1294 1295 /* 1296 ================ 1297 GL_Resample8BitTexture -- JACK 1298 ================ 1299 */ 1300 void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight) 1301 { 1302 int i, j; 1303 unsigned char *inrow; 1304 unsigned frac, fracstep; 1305 1306 fracstep = inwidth*0x10000/outwidth; 1307 for (i=0 ; i<outheight ; i++, out += outwidth) 1308 { 1309 inrow = in + inwidth*(i*inheight/outheight); 1310 frac = fracstep >> 1; 1311 for (j=0 ; j<outwidth ; j+=4) 1312 { 1313 out[j] = inrow[frac>>16]; 1314 frac += fracstep; 1315 out[j+1] = inrow[frac>>16]; 1316 frac += fracstep; 1317 out[j+2] = inrow[frac>>16]; 1318 frac += fracstep; 1319 out[j+3] = inrow[frac>>16]; 1320 frac += fracstep; 1321 } 1322 } 1323 } 1324 1325 1326 /* 1327 ================ 1328 GL_MipMap 1329 1330 Operates in place, quartering the size of the texture 1331 ================ 1332 */ 1333 void GL_MipMap (byte *in, int width, int height) 1334 { 1335 int i, j; 1336 byte *out; 1337 1338 width <<=2; 1339 height >>= 1; 1340 out = in; 1341 for (i=0 ; i<height ; i++, in+=width) 1342 { 1343 for (j=0 ; j<width ; j+=8, out+=4, in+=8) 1344 { 1345 out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2; 1346 out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; 1347 out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; 1348 out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; 1349 } 1350 } 1351 } 1352 1353 #ifdef SUPPORT_8BIT_MIPMAPGENERATION 1354 /* 1355 ================ 1356 GL_MipMap8Bit 1357 1358 Mipping for 8 bit textures 1359 1360 The "in" and "out" arguments can point to the same buffer if desired 1361 ================ 1362 */ 1363 void GL_MipMap8Bit (byte *in, byte* out, int width, int height) 1364 { 1365 int i, j; 1366 unsigned short r,g,b; 1367 byte *at1, *at2, *at3, *at4; 1368 1369 // width <<=2; 1370 height >>= 1; 1371 for (i=0 ; i<height ; i++, in+=width) 1372 { 1373 for (j=0 ; j<width ; j+=2, out+=1, in+=2) 1374 { 1375 at1 = (byte *) (d_8to24table + in[0]); 1376 at2 = (byte *) (d_8to24table + in[1]); 1377 at3 = (byte *) (d_8to24table + in[width+0]); 1378 at4 = (byte *) (d_8to24table + in[width+1]); 1379 1380 r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5; 1381 g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5; 1382 b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5; 1383 1384 out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)]; 1385 } 1386 } 1387 } 1388 1389 #endif // SUPPORT_8BIT_MIPMAPGENERATION 1390 1391 void glTexImage2DHelper( GLenum target, 1392 GLint level, 1393 GLint internalformat, 1394 GLsizei width, 1395 GLsizei height, 1396 GLint border, 1397 GLenum format, 1398 GLenum type, 1399 const GLvoid *pixels ) 1400 { 1401 // In full OpenGL The internalformat can be 1..4, to indicate how many components of the data are valid. 1402 // OpenGL ES requires the internalformat argument match the format for glTexImage2D. 1403 1404 glTexImage2D(target, level, format, width, height, border, format, type, pixels); 1405 } 1406 1407 1408 // Uncomment to enable manual MipMap generation 1409 #define USE_MANUAL_MIPMAP_GEN 1410 1411 // Uncomment one of the following: 1412 1413 // #define USE_16BPP_WITH_8888_ALPHA 1414 // #define USE_16BPP_WITH_5551_ALPHA // <--- This has bugs on the simulator and the device. (Device has all alpha images invisible.) 1415 #define USE_16BPP_WITH_4444_ALPHA // <--- This has bugs on the simulator, works in device 1416 // #define USE_32BPP 1417 // #define USE_32BPP_MANUAL_MIPMAP_GEN 1418 1419 #ifdef USE_MANUAL_MIPMAP_GEN 1420 1421 inline unsigned int average4(unsigned int a, unsigned int b, 1422 unsigned int c, unsigned int d, 1423 unsigned int shift, unsigned int mask) { 1424 unsigned int aElem = (a >> shift) & mask; 1425 unsigned int bElem = (b >> shift) & mask; 1426 unsigned int cElem = (c >> shift) & mask; 1427 unsigned int dElem = (d >> shift) & mask; 1428 unsigned int avgElem = ((aElem + bElem + cElem + dElem) >> 2) & mask; 1429 return avgElem << shift; 1430 } 1431 1432 inline unsigned int average2(unsigned int a, unsigned int b, 1433 unsigned int shift, unsigned int mask) { 1434 unsigned int aElem = (a >> shift) & mask; 1435 unsigned int bElem = (b >> shift) & mask; 1436 unsigned int avgElem = ((aElem + bElem) >> 1) & mask; 1437 return avgElem << shift; 1438 } 1439 1440 inline unsigned int average4444(unsigned int a, unsigned int b) { 1441 return 1442 average2(a,b,0,0xf) | 1443 average2(a,b,4,0xf) | 1444 average2(a,b,8,0xf) | 1445 average2(a,b,12,0xf); 1446 } 1447 1448 inline unsigned int average565(unsigned int a, unsigned int b) { 1449 return 1450 average2(a,b,0,0x1f) | 1451 average2(a,b,5,0x3f) | 1452 average2(a,b,11,0x1f); 1453 } 1454 1455 inline unsigned int average2_8888(unsigned int a, unsigned int b) { 1456 return 1457 average2(a,b,0,0xff) | 1458 average2(a,b,8,0xff) | 1459 average2(a,b,16,0xff) | 1460 average2(a,b,24,0xff); 1461 } 1462 1463 inline unsigned int average4_8888(unsigned int a, unsigned int b, 1464 unsigned int c, unsigned int d) { 1465 return 1466 average4(a,b,c,d,0,0xff) | 1467 average4(a,b,c,d,8,0xff) | 1468 average4(a,b,c,d,16,0xff) | 1469 average4(a,b,c,d,24,0xff); 1470 } 1471 1472 #endif 1473 1474 // pData is 8 bpp 32-bit color 1475 1476 1477 void sendTexture(int mipLevel, int width, int height, unsigned int* pData, qboolean alpha) { 1478 if (alpha) { 1479 #if defined(USE_16BPP_WITH_8888_ALPHA) 1480 // 8888 1481 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData); 1482 #elif defined(USE_16BPP_WITH_5551_ALPHA) 1483 // 5551 1484 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0); 1485 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData); 1486 #else 1487 // 4444 1488 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); 1489 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pData); 1490 #endif 1491 } 1492 else { 1493 #if 0 1494 // 8888 1495 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData); 1496 #else 1497 // 565 1498 static unsigned short scaled[1024*512]; // [512*256]; 1499 glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); 1500 // Some OpenGL ES implementations do not have to be able to convert from GL_RGBA to GL_RGB format, so 1501 // we must do it manually here: 1502 unsigned char* pSrc = (unsigned char*) pData; 1503 unsigned short* pDest = scaled; 1504 for (int y = 0; y < height; y++) { 1505 for (int x = 0; x < width; x++) { 1506 *pDest++ = ((pSrc[0] >> 3) << 11) | 1507 ((pSrc[1] >> 2) << 5) | 1508 (pSrc[2] >> 3); 1509 pSrc += 4; 1510 } 1511 } 1512 glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, scaled); 1513 #endif 1514 } 1515 } 1516 1517 /* 1518 =============== 1519 GL_Upload32 1520 =============== 1521 */ 1522 void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha) 1523 { 1524 int samples; 1525 int scaled_width, scaled_height; 1526 static unsigned scaled[1024*512]; // [512*256]; 1527 1528 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) 1529 ; 1530 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) 1531 ; 1532 1533 scaled_width >>= (int)gl_picmip.value; 1534 scaled_height >>= (int)gl_picmip.value; 1535 1536 if (scaled_width > gl_max_size.value) 1537 scaled_width = (int) gl_max_size.value; 1538 if (scaled_height > gl_max_size.value) 1539 scaled_height = (int) gl_max_size.value; 1540 1541 if (scaled_width * scaled_height > (int) sizeof(scaled)/4) 1542 Sys_Error ("GL_LoadTexture: too big"); 1543 1544 samples = alpha ? gl_alpha_format : gl_solid_format; 1545 1546 texels += scaled_width * scaled_height; 1547 1548 if (scaled_width == width && scaled_height == height) 1549 { 1550 #if 0 // Disable this optimization, we want to be able to easily switch texture formats 1551 if (!mipmap) 1552 { 1553 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 1554 goto done; 1555 } 1556 #endif 1557 memcpy (scaled, data, width*height*4); 1558 } 1559 else 1560 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); 1561 1562 #if defined(USE_16BPP_WITH_8888_ALPHA) || defined(USE_16BPP_WITH_5551_ALPHA) || defined(USE_16BPP_WITH_4444_ALPHA) 1563 // Upload as 16 bpp 1564 1565 #ifdef USE_MANUAL_MIPMAP_GEN 1566 #else 1567 // Use automatic MIPMAP generation 1568 if (mipmap) 1569 { 1570 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1); 1571 } 1572 #endif 1573 1574 sendTexture(0, scaled_width, scaled_height, scaled, alpha); 1575 1576 #ifdef USE_MANUAL_MIPMAP_GEN 1577 if (mipmap) { 1578 // Compute mip levels 1579 int mipWidth = scaled_width; 1580 int mipHeight = scaled_height; 1581 int mipLevel = 1; 1582 while (mipWidth > 1 || mipHeight > 1) { 1583 if (mipWidth > 1 && mipHeight > 1) { 1584 // Scale horizontally and vertically 1585 int srcWidth = mipWidth; 1586 mipWidth >>= 1; 1587 mipHeight >>= 1; 1588 const unsigned int* pIn = (const unsigned int*) scaled; 1589 unsigned int* pOut = (unsigned int*) scaled; 1590 for(int y = 0; y < mipHeight; y++) { 1591 for (int x = 0; x < mipWidth; x++) { 1592 *pOut++ = average4_8888(pIn[0], pIn[1], 1593 pIn[srcWidth], pIn[srcWidth+1]); 1594 pIn += 2; 1595 } 1596 pIn += srcWidth; 1597 } 1598 } 1599 else { 1600 // Scale horizontally: 1601 if (mipWidth > 1) { 1602 mipWidth >>= 1; 1603 const unsigned int* pIn = (const unsigned int*) scaled; 1604 unsigned int* pOut = (unsigned int*) scaled; 1605 unsigned int numTexels = mipHeight * mipWidth; 1606 for(unsigned int i = 0; i < numTexels; i++) { 1607 *pOut++ = average2_8888(pIn[0], pIn[1]); 1608 pIn += 2; 1609 } 1610 } 1611 // Scale vertically: 1612 if (mipHeight > 1) { 1613 mipHeight >>= 1; 1614 const unsigned int* pIn = (const unsigned int*) scaled; 1615 unsigned int* pOut = (unsigned int*) scaled; 1616 for(int y = 0; y < mipHeight; y++) { 1617 for (int x = 0; x < mipWidth; x++) { 1618 *pOut++ = average2_8888(pIn[0], pIn[mipWidth]); 1619 pIn += 1; 1620 } 1621 pIn += mipWidth; 1622 } 1623 } 1624 } 1625 1626 sendTexture(mipLevel, mipWidth, mipHeight, scaled, alpha); 1627 mipLevel++; 1628 } 1629 } 1630 1631 #else 1632 if (mipmap) 1633 { 1634 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0); 1635 } 1636 #endif 1637 1638 #elif defined(USE_32BPP) 1639 // 8888 1640 // Use automatic MIPMAP generation 1641 if (mipmap) 1642 { 1643 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1); 1644 } 1645 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); 1646 if (mipmap) 1647 { 1648 glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 0); 1649 } 1650 #else 1651 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); 1652 if (mipmap) 1653 { 1654 int miplevel; 1655 1656 miplevel = 0; 1657 while (scaled_width > 1 || scaled_height > 1) 1658 { 1659 GL_MipMap ((byte *)scaled, scaled_width, scaled_height); 1660 scaled_width >>= 1; 1661 scaled_height >>= 1; 1662 if (scaled_width < 1) 1663 scaled_width = 1; 1664 if (scaled_height < 1) 1665 scaled_height = 1; 1666 miplevel++; 1667 glTexImage2DHelper (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); 1668 } 1669 } 1670 #endif 1671 done: ; 1672 1673 if (mipmap) 1674 { 1675 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 1676 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1677 } 1678 else 1679 { 1680 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); 1681 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1682 } 1683 } 1684 1685 #ifdef USE_OPENGLES 1686 1687 void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha) 1688 { 1689 int i, s, bytesUsed; 1690 qboolean noalpha; 1691 int p; 1692 static unsigned j; 1693 static unsigned char compressedTextureBuffer[1024*512]; // [512*256]; 1694 unsigned char* pTex = compressedTextureBuffer; 1695 int scaled_width, scaled_height; 1696 int miplevel = 0; 1697 1698 int originalScaledWidth; 1699 int originalScaledHeight; 1700 1701 s = width*height; 1702 // if there are no transparent pixels, make it a 3 component 1703 // texture even if it was specified as otherwise 1704 if (alpha) 1705 { 1706 noalpha = true; 1707 for (i=0 ; i<s ; i++) 1708 { 1709 if (data[i] == 255) 1710 noalpha = false; 1711 } 1712 1713 if (alpha && noalpha) 1714 alpha = false; 1715 } 1716 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) 1717 ; 1718 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) 1719 ; 1720 1721 scaled_width >>= (int)gl_picmip.value; 1722 scaled_height >>= (int)gl_picmip.value; 1723 1724 if (scaled_width > gl_max_size.value) 1725 scaled_width = (int) gl_max_size.value; 1726 if (scaled_height > gl_max_size.value) 1727 scaled_height = (int) gl_max_size.value; 1728 1729 if (scaled_width * scaled_height > ((int) (sizeof(compressedTextureBuffer) * 3 / 4))) 1730 Sys_Error ("GL_LoadTexture: too big"); 1731 1732 // Copy the palette 1733 1734 int entrySize = alpha ? 4 : 3; 1735 int paletteSize = entrySize * 256; 1736 { 1737 byte* pDest = compressedTextureBuffer; 1738 const byte* pSrc = host_basepal; 1739 if(alpha) 1740 { 1741 for(int i = 0; i< 255; i++) 1742 { 1743 *pDest++ = *pSrc++; 1744 *pDest++ = *pSrc++; 1745 *pDest++ = *pSrc++; 1746 *pDest++ = 0xff; 1747 } 1748 // Entry 255 is transparent 1749 *pDest++ = 0x00; 1750 *pDest++ = 0x00; 1751 *pDest++ = 0x00; 1752 *pDest++ = 0x00; 1753 } 1754 else 1755 { 1756 memcpy(pDest, pSrc, paletteSize); 1757 } 1758 } 1759 1760 bytesUsed = paletteSize; 1761 pTex += paletteSize; 1762 1763 texels += scaled_width * scaled_height; 1764 1765 if (scaled_width == width && scaled_height == height) 1766 { 1767 memcpy (pTex, data, scaled_width*scaled_height); 1768 } 1769 else 1770 GL_Resample8BitTexture (data, width, height, pTex, scaled_width, scaled_height); 1771 1772 bytesUsed += scaled_width * scaled_height; 1773 1774 miplevel = 0; 1775 1776 originalScaledWidth = scaled_width; 1777 originalScaledHeight = scaled_height; 1778 1779 if (mipmap) 1780 { 1781 #ifdef SUPPORT_8BIT_MIPMAPGENERATION 1782 miplevel = 1; 1783 while (scaled_width > 1 || scaled_height > 1) 1784 { 1785 byte* pDest = (byte*) pTex + scaled_width * scaled_height; 1786 GL_MipMap8Bit ((byte *)pTex, pDest, scaled_width, scaled_height); 1787 pTex = pDest; 1788 scaled_width >>= 1; 1789 scaled_height >>= 1; 1790 if (scaled_width < 1) 1791 scaled_width = 1; 1792 if (scaled_height < 1) 1793 scaled_height = 1; 1794 bytesUsed += scaled_width * scaled_height; 1795 miplevel++; 1796 } 1797 #else 1798 Sys_Error("Unsupported attempt to generate 8 bit mip mapped texture. #define SUPPORT_8BIT_MIPMAPGENERATION"); 1799 #endif 1800 } 1801 1802 GLint internalFormat = alpha ? GL_PALETTE8_RGBA8_OES : GL_PALETTE8_RGB8_OES; 1803 glCompressedTexImage2D (GL_TEXTURE_2D, -miplevel, internalFormat, 1804 originalScaledWidth, originalScaledHeight, 1805 0, bytesUsed, compressedTextureBuffer); 1806 1807 if (mipmap) 1808 { 1809 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 1810 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1811 } 1812 else 1813 { 1814 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); 1815 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1816 } 1817 } 1818 1819 #else 1820 1821 void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha) 1822 { 1823 int i, s; 1824 qboolean noalpha; 1825 int p; 1826 static unsigned j; 1827 int samples; 1828 static unsigned char scaled[1024*512]; // [512*256]; 1829 int scaled_width, scaled_height; 1830 1831 s = width*height; 1832 // if there are no transparent pixels, make it a 3 component 1833 // texture even if it was specified as otherwise 1834 if (alpha) 1835 { 1836 noalpha = true; 1837 for (i=0 ; i<s ; i++) 1838 { 1839 if (data[i] == 255) 1840 noalpha = false; 1841 } 1842 1843 if (alpha && noalpha) 1844 alpha = false; 1845 } 1846 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) 1847 ; 1848 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) 1849 ; 1850 1851 scaled_width >>= (int)gl_picmip.value; 1852 scaled_height >>= (int)gl_picmip.value; 1853 1854 if (scaled_width > gl_max_size.value) 1855 scaled_width = gl_max_size.value; 1856 if (scaled_height > gl_max_size.value) 1857 scaled_height = gl_max_size.value; 1858 1859 if (scaled_width * scaled_height > (int) sizeof(scaled)) 1860 Sys_Error ("GL_LoadTexture: too big"); 1861 1862 samples = 1; // alpha ? gl_alpha_format : gl_solid_format; 1863 1864 texels += scaled_width * scaled_height; 1865 1866 if (scaled_width == width && scaled_height == height) 1867 { 1868 if (!mipmap) 1869 { 1870 glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data); 1871 goto done; 1872 } 1873 memcpy (scaled, data, width*height); 1874 } 1875 else 1876 GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height); 1877 1878 glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled); 1879 if (mipmap) 1880 { 1881 #ifdef SUPPORT_8BIT_MIPMAPGENERATION 1882 int miplevel; 1883 1884 miplevel = 0; 1885 while (scaled_width > 1 || scaled_height > 1) 1886 { 1887 GL_MipMap8Bit ((byte *)scaled, (byte*) scaled, scaled_width, scaled_height); 1888 scaled_width >>= 1; 1889 scaled_height >>= 1; 1890 if (scaled_width < 1) 1891 scaled_width = 1; 1892 if (scaled_height < 1) 1893 scaled_height = 1; 1894 miplevel++; 1895 glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); 1896 } 1897 #else 1898 Sys_Error("Unsupported attept to generate 8 bit mip mapped texture."); 1899 #endif 1900 } 1901 done: ; 1902 1903 1904 if (mipmap) 1905 { 1906 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 1907 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1908 } 1909 else 1910 { 1911 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); 1912 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1913 } 1914 } 1915 1916 #endif // ! OPENGL_ES 1917 1918 /* 1919 =============== 1920 GL_Upload8 1921 =============== 1922 */ 1923 void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha) 1924 { 1925 static unsigned trans[640*480]; // FIXME, temporary 1926 int i, s; 1927 qboolean noalpha; 1928 int p; 1929 1930 s = width*height; 1931 // if there are no transparent pixels, make it a 3 component 1932 // texture even if it was specified as otherwise 1933 if (alpha) 1934 { 1935 noalpha = true; 1936 for (i=0 ; i<s ; i++) 1937 { 1938 p = data[i]; 1939 if (p == 255) 1940 noalpha = false; 1941 trans[i] = d_8to24table[p]; 1942 } 1943 1944 if (alpha && noalpha) 1945 alpha = false; 1946 } 1947 else 1948 { 1949 if (s&3) 1950 Sys_Error ("GL_Upload8: s&3"); 1951 for (i=0 ; i<s ; i+=4) 1952 { 1953 trans[i] = d_8to24table[data[i]]; 1954 trans[i+1] = d_8to24table[data[i+1]]; 1955 trans[i+2] = d_8to24table[data[i+2]]; 1956 trans[i+3] = d_8to24table[data[i+3]]; 1957 } 1958 } 1959 1960 if (VID_Is8bit() && (data!=scrap_texels[0]) 1961 #if !defined(USE_OPENGLES) 1962 && !alpha 1963 #endif 1964 ) { 1965 GL_Upload8_EXT (data, width, height, mipmap, alpha); 1966 return; 1967 } 1968 GL_Upload32 (trans, width, height, mipmap, alpha); 1969 } 1970 1971 /* 1972 ================ 1973 GL_LoadTexture 1974 ================ 1975 */ 1976 int GL_LoadTexture (const char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha) 1977 { 1978 qboolean noalpha; 1979 int i, p, s; 1980 gltexture_t *glt; 1981 1982 // see if the texture is allready present 1983 if (identifier[0]) 1984 { 1985 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++) 1986 { 1987 if (!strcmp (identifier, glt->identifier)) 1988 { 1989 if (width != glt->width || height != glt->height) 1990 Sys_Error ("GL_LoadTexture: cache mismatch"); 1991 return gltextures[i].texnum; 1992 } 1993 } 1994 #ifdef USE_OPENGLES 1995 // Surely we want to remember this new texture. 1996 // Doing this costs 1% fps per timedemo on a DX7 PC, 1997 // probably because of the linear search through the 1998 // texture cache, but it saves 10 MB of VM growth per 1999 // level load. It also makes the GL_TEXTUREMODE 2000 // console command work correctly. 2001 numgltextures++; 2002 #endif 2003 } 2004 else { 2005 glt = &gltextures[numgltextures]; 2006 numgltextures++; 2007 } 2008 2009 strcpy (glt->identifier, identifier); 2010 glt->texnum = texture_extension_number; 2011 glt->width = width; 2012 glt->height = height; 2013 glt->mipmap = mipmap; 2014 2015 GL_Bind(texture_extension_number); 2016 2017 #ifdef USE_TEXTURE_STORE 2018 2019 textureStore::get()->create(width, height, data, mipmap, alpha); 2020 2021 #else 2022 2023 GL_Upload8 (data, width, height, mipmap, alpha); 2024 2025 #endif 2026 2027 texture_extension_number++; 2028 return texture_extension_number-1; 2029 } 2030 2031 2032 /****************************************/ 2033 2034 static GLenum oldtarget = TEXTURE0_SGIS; 2035 2036 void GL_SelectTexture (GLenum target) 2037 { 2038 if (!gl_mtexable) 2039 return; 2040 #ifdef USE_OPENGLES 2041 glActiveTexture(target); 2042 #else 2043 qglSelectTextureSGIS(target); 2044 #endif 2045 if (target == oldtarget) 2046 return; 2047 cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture; 2048 currenttexture = cnttextures[target-TEXTURE0_SGIS]; 2049 oldtarget = target; 2050 } 2051 2052 // OpenGL ES compatible DrawQuad utility 2053 2054 #define BEGIN_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); 2055 #define END_QUAD glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 2056 2057 void DrawQuad_NoTex(float x, float y, float w, float h) 2058 { 2059 BEGIN_QUAD 2060 2061 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h}; 2062 short index[4] = {0, 1, 2, 3}; 2063 glVertexPointer( 2, GL_FLOAT, 0, vertex); 2064 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 2065 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index); 2066 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 2067 2068 END_QUAD 2069 } 2070 2071 void DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh) 2072 { 2073 BEGIN_QUAD 2074 2075 float texcoord[2*4] = {u, v, u + uw, v, u + uw, v + vh, u, v + vh}; 2076 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h}; 2077 unsigned short index[4] = {0, 1, 2, 3}; 2078 glTexCoordPointer( 2, GL_FLOAT, 0, texcoord); 2079 glVertexPointer( 2, GL_FLOAT, 0, vertex); 2080 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index); 2081 2082 END_QUAD 2083 } 2084 2085 #ifdef USE_OPENGLES 2086 2087 // Reimplementation of OpenGL functions that are missing in OpenGL ES 2088 2089 void glColor3f(GLfloat r, GLfloat g, GLfloat b) 2090 { 2091 glColor4f(r, g, b, 1.0f); 2092 } 2093 2094 void glColor4fv(GLfloat* pColor) 2095 { 2096 glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]); 2097 } 2098 2099 float gVertexBuffer[VERTEXARRAYSIZE]; 2100 float gColorBuffer[VERTEXARRAYSIZE]; 2101 float gTexCoordBuffer[VERTEXARRAYSIZE]; 2102 2103 // Called when we've lost the OpenGL context and have to recreate it. 2104 extern void GL_Init(); 2105 extern void R_InitParticleTexture2(); 2106 extern void GL_UploadLightmaps(); 2107 extern void R_ReloadSky(); 2108 2109 void GL_ReInit() { 2110 GL_Init(); 2111 textureStore::get()->rebindAll(); 2112 scrap_dirty = true; 2113 R_InitParticleTexture2(); 2114 GL_UploadLightmaps(); 2115 R_ReloadSky(); 2116 } 2117 2118 #endif 2119 2120 #ifdef DEBUG_OPENGL_CALLS 2121 void checkGLImp(const char* state, const char* file, int line) { 2122 GLenum error = glGetError(); 2123 if (error != GL_NO_ERROR) { 2124 Sys_Error("%s: error 0x%04X at %s:%d\n", state, error, file, line); 2125 } 2126 } 2127 2128 #endif 2129