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