1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20 21// draw.c -- this is the only file outside the refresh that touches the 22// vid buffer 23 24#include "quakedef.h" 25 26extern unsigned char d_15to8table[65536]; 27extern cvar_t crosshair, cl_crossx, cl_crossy, crosshaircolor; 28 29cvar_t gl_nobind = CVAR2("gl_nobind", "0"); 30cvar_t gl_max_size = CVAR2("gl_max_size", "1024"); 31cvar_t gl_picmip = CVAR2("gl_picmip", "0"); 32 33byte *draw_chars; // 8*8 graphic characters 34qpic_t *draw_disc; 35qpic_t *draw_backtile; 36 37int translate_texture; 38int char_texture; 39int cs_texture; // crosshair texture 40 41static byte cs_data[64] = { 42 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 44 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 45 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 46 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 47 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 48 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 49 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 50}; 51 52 53typedef struct 54{ 55 int texnum; 56 float sl, tl, sh, th; 57} glpic_t; 58 59byte conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)]; 60qpic_t *conback = (qpic_t *)&conback_buffer; 61 62int gl_lightmap_format = 4; 63int gl_solid_format = 3; 64int gl_alpha_format = 4; 65 66int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; 67int gl_filter_max = GL_LINEAR; 68 69 70int texels; 71 72typedef struct 73{ 74 int texnum; 75 char identifier[64]; 76 int width, height; 77 qboolean mipmap; 78} gltexture_t; 79 80#define MAX_GLTEXTURES 1024 81gltexture_t gltextures[MAX_GLTEXTURES]; 82int numgltextures; 83 84void GL_Bind (int texnum) 85{ 86 if (gl_nobind.value) 87 texnum = char_texture; 88 if (currenttexture == texnum) 89 return; 90 currenttexture = texnum; 91#ifdef _WIN32 92 bindTexFunc (GL_TEXTURE_2D, texnum); 93#else 94 glBindTexture (GL_TEXTURE_2D, texnum); 95#endif 96} 97 98 99/* 100============================================================================= 101 102 scrap allocation 103 104 Allocate all the little status bar obejcts into a single texture 105 to crutch up stupid hardware / drivers 106 107============================================================================= 108*/ 109 110#define MAX_SCRAPS 1 111#define BLOCK_WIDTH 256 112#define BLOCK_HEIGHT 256 113 114int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; 115byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4]; 116qboolean scrap_dirty; 117int scrap_texnum; 118 119// returns a texture number and the position inside it 120int Scrap_AllocBlock (int w, int h, int *x, int *y) 121{ 122 int i, j; 123 int best, best2; 124 int texnum; 125 126 for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) 127 { 128 best = BLOCK_HEIGHT; 129 130 for (i=0 ; i<BLOCK_WIDTH-w ; i++) 131 { 132 best2 = 0; 133 134 for (j=0 ; j<w ; j++) 135 { 136 if (scrap_allocated[texnum][i+j] >= best) 137 break; 138 if (scrap_allocated[texnum][i+j] > best2) 139 best2 = scrap_allocated[texnum][i+j]; 140 } 141 if (j == w) 142 { // this is a valid spot 143 *x = i; 144 *y = best = best2; 145 } 146 } 147 148 if (best + h > BLOCK_HEIGHT) 149 continue; 150 151 for (i=0 ; i<w ; i++) 152 scrap_allocated[texnum][*x + i] = best + h; 153 154 return texnum; 155 } 156 157 Sys_Error ("Scrap_AllocBlock: full"); 158 return 0; 159} 160 161int scrap_uploads; 162 163void Scrap_Upload (void) 164{ 165 scrap_uploads++; 166 GL_Bind(scrap_texnum); 167 GL_Upload8 (scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, true); 168 scrap_dirty = false; 169} 170 171//============================================================================= 172/* Support Routines */ 173 174typedef struct cachepic_s 175{ 176 char name[MAX_QPATH]; 177 qpic_t pic; 178 byte padding[32]; // for appended glpic 179} cachepic_t; 180 181#define MAX_CACHED_PICS 128 182cachepic_t menu_cachepics[MAX_CACHED_PICS]; 183int menu_numcachepics; 184 185byte menuplyr_pixels[4096]; 186 187int pic_texels; 188int pic_count; 189 190qpic_t *Draw_PicFromWad (char *name) 191{ 192 qpic_t *p; 193 glpic_t *gl; 194 195 p = W_GetLumpName (name); 196 gl = (glpic_t *)p->data; 197 198 // load little ones into the scrap 199 if (p->width < 64 && p->height < 64) 200 { 201 int x, y; 202 int i, j, k; 203 int texnum; 204 205 texnum = Scrap_AllocBlock (p->width, p->height, &x, &y); 206 scrap_dirty = true; 207 k = 0; 208 for (i=0 ; i<p->height ; i++) 209 for (j=0 ; j<p->width ; j++, k++) 210 scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k]; 211 texnum += scrap_texnum; 212 gl->texnum = texnum; 213 gl->sl = (x+0.01)/(float)BLOCK_WIDTH; 214 gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH; 215 gl->tl = (y+0.01)/(float)BLOCK_WIDTH; 216 gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH; 217 218 pic_count++; 219 pic_texels += p->width*p->height; 220 } 221 else 222 { 223 gl->texnum = GL_LoadPicTexture (p); 224 gl->sl = 0; 225 gl->sh = 1; 226 gl->tl = 0; 227 gl->th = 1; 228 } 229 return p; 230} 231 232 233/* 234================ 235Draw_CachePic 236================ 237*/ 238qpic_t *Draw_CachePic (char *path) 239{ 240 cachepic_t *pic; 241 int i; 242 qpic_t *dat; 243 glpic_t *gl; 244 245 for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++) 246 if (!strcmp (path, pic->name)) 247 return &pic->pic; 248 249 if (menu_numcachepics == MAX_CACHED_PICS) 250 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); 251 menu_numcachepics++; 252 strcpy (pic->name, path); 253 254// 255// load the pic from disk 256// 257 dat = (qpic_t *)COM_LoadTempFile (path); 258 if (!dat) 259 Sys_Error ("Draw_CachePic: failed to load %s", path); 260 SwapPic (dat); 261 262 // HACK HACK HACK --- we need to keep the bytes for 263 // the translatable player picture just for the menu 264 // configuration dialog 265 if (!strcmp (path, "gfx/menuplyr.lmp")) 266 memcpy (menuplyr_pixels, dat->data, dat->width*dat->height); 267 268 pic->pic.width = dat->width; 269 pic->pic.height = dat->height; 270 271 gl = (glpic_t *)pic->pic.data; 272 gl->texnum = GL_LoadPicTexture (dat); 273 gl->sl = 0; 274 gl->sh = 1; 275 gl->tl = 0; 276 gl->th = 1; 277 278 return &pic->pic; 279} 280 281 282void Draw_CharToConback (int num, byte *dest) 283{ 284 int row, col; 285 byte *source; 286 int drawline; 287 int x; 288 289 row = num>>4; 290 col = num&15; 291 source = draw_chars + (row<<10) + (col<<3); 292 293 drawline = 8; 294 295 while (drawline--) 296 { 297 for (x=0 ; x<8 ; x++) 298 if (source[x] != 255) 299 dest[x] = 0x60 + source[x]; 300 source += 128; 301 dest += 320; 302 } 303 304} 305 306typedef struct 307{ 308 char *name; 309 int minimize, maximize; 310} glmode_t; 311 312glmode_t modes[] = { 313 {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, 314 {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, 315 {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, 316 {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, 317 {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, 318 {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} 319}; 320 321/* 322=============== 323Draw_TextureMode_f 324=============== 325*/ 326void Draw_TextureMode_f (void) 327{ 328 int i; 329 gltexture_t *glt; 330 331 if (Cmd_Argc() == 1) 332 { 333 for (i=0 ; i< 6 ; i++) 334 if (gl_filter_min == modes[i].minimize) 335 { 336 Con_Printf ("%s\n", modes[i].name); 337 return; 338 } 339 Con_Printf ("current filter is unknown???\n"); 340 return; 341 } 342 343 for (i=0 ; i< 6 ; i++) 344 { 345 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) ) 346 break; 347 } 348 if (i == 6) 349 { 350 Con_Printf ("bad filter name\n"); 351 return; 352 } 353 354 gl_filter_min = modes[i].minimize; 355 gl_filter_max = modes[i].maximize; 356 357 // change all the existing mipmap texture objects 358 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++) 359 { 360 if (glt->mipmap) 361 { 362 GL_Bind (glt->texnum); 363 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 364 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 365 } 366 } 367} 368 369/* 370=============== 371Draw_Init 372=============== 373*/ 374void Draw_Init (void) 375{ 376 int i; 377 qpic_t *cb; 378 byte *dest; 379 int x; 380 char ver[40]; 381 glpic_t *gl; 382 int start; 383 byte *ncdata; 384 385 Cvar_RegisterVariable (&gl_nobind); 386 Cvar_RegisterVariable (&gl_max_size); 387 Cvar_RegisterVariable (&gl_picmip); 388 389 // 3dfx can only handle 256 wide textures 390 if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || 391 !Q_strncasecmp ((char *)gl_renderer, "Mesa",4)) 392 Cvar_Set ("gl_max_size", "256"); 393 394 Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f); 395 396 // load the console background and the charset 397 // by hand, because we need to write the version 398 // string into the background before turning 399 // it into a texture 400 draw_chars = W_GetLumpName ("conchars"); 401 for (i=0 ; i<256*64 ; i++) 402 if (draw_chars[i] == 0) 403 draw_chars[i] = 255; // proper transparent color 404 405 // now turn them into textures 406 char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true); 407// Draw_CrosshairAdjust(); 408 cs_texture = GL_LoadTexture ("crosshair", 8, 8, cs_data, false, true); 409 410 start = Hunk_LowMark (); 411 412 cb = (qpic_t *)COM_LoadHunkFile ("gfx/conback.lmp"); 413 if (!cb) 414 Sys_Error ("Couldn't load gfx/conback.lmp"); 415 SwapPic (cb); 416 417 sprintf (ver, "%4.2f", VERSION); 418 dest = cb->data + 320 + 320*186 - 11 - 8*strlen(ver); 419 for (x=0 ; x< (int) strlen(ver) ; x++) 420 Draw_CharToConback (ver[x], dest+(x<<3)); 421 422#if 0 423 conback->width = vid.conwidth; 424 conback->height = vid.conheight; 425 426 // scale console to vid size 427 dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback"); 428 429 for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth) 430 { 431 src = cb->data + cb->width * (y*cb->height/vid.conheight); 432 if (vid.conwidth == cb->width) 433 memcpy (dest, src, vid.conwidth); 434 else 435 { 436 f = 0; 437 fstep = cb->width*0x10000/vid.conwidth; 438 for (x=0 ; x<vid.conwidth ; x+=4) 439 { 440 dest[x] = src[f>>16]; 441 f += fstep; 442 dest[x+1] = src[f>>16]; 443 f += fstep; 444 dest[x+2] = src[f>>16]; 445 f += fstep; 446 dest[x+3] = src[f>>16]; 447 f += fstep; 448 } 449 } 450 } 451#else 452 conback->width = cb->width; 453 conback->height = cb->height; 454 ncdata = cb->data; 455#endif 456 457 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 458 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 459 460 gl = (glpic_t *)conback->data; 461 gl->texnum = GL_LoadTexture ("conback", conback->width, conback->height, ncdata, false, false); 462 gl->sl = 0; 463 gl->sh = 1; 464 gl->tl = 0; 465 gl->th = 1; 466 conback->width = vid.conwidth; 467 conback->height = vid.conheight; 468 469 // free loaded console 470 Hunk_FreeToLowMark (start); 471 472 // save a texture slot for translated picture 473 translate_texture = texture_extension_number++; 474 475 // save slots for scraps 476 scrap_texnum = texture_extension_number; 477 texture_extension_number += MAX_SCRAPS; 478 479 // 480 // get the other pics we need 481 // 482 draw_disc = Draw_PicFromWad ("disc"); 483 draw_backtile = Draw_PicFromWad ("backtile"); 484} 485 486 487 488/* 489================ 490Draw_Character 491 492Draws one 8*8 graphics character with 0 being transparent. 493It can be clipped to the top of the screen to allow the console to be 494smoothly scrolled off. 495================ 496*/ 497void Draw_Character (int x, int y, int num) 498{ 499 int row, col; 500 float frow, fcol, size; 501 502 if (num == 32) 503 return; // space 504 505 num &= 255; 506 507 if (y <= -8) 508 return; // totally off screen 509 510 row = num>>4; 511 col = num&15; 512 513 frow = row*0.0625; 514 fcol = col*0.0625; 515 size = 0.0625; 516 517 GL_Bind (char_texture); 518 519#ifdef USE_OPENGLES 520 DrawQuad(x, y, 8, 8, fcol, frow, size, size); 521#else 522 glBegin (GL_QUADS); 523 glTexCoord2f (fcol, frow); 524 glVertex2f (x, y); 525 glTexCoord2f (fcol + size, frow); 526 glVertex2f (x+8, y); 527 glTexCoord2f (fcol + size, frow + size); 528 glVertex2f (x+8, y+8); 529 glTexCoord2f (fcol, frow + size); 530 glVertex2f (x, y+8); 531 glEnd (); 532#endif 533} 534 535/* 536================ 537Draw_String 538================ 539*/ 540void Draw_String (int x, int y, char *str) 541{ 542 while (*str) 543 { 544 Draw_Character (x, y, *str); 545 str++; 546 x += 8; 547 } 548} 549 550/* 551================ 552Draw_Alt_String 553================ 554*/ 555void Draw_Alt_String (int x, int y, char *str) 556{ 557 while (*str) 558 { 559 Draw_Character (x, y, (*str) | 0x80); 560 str++; 561 x += 8; 562 } 563} 564 565void Draw_Crosshair(void) 566{ 567 int x, y; 568 extern vrect_t scr_vrect; 569 unsigned char *pColor; 570 571 if (crosshair.value == 2) { 572 x = scr_vrect.x + scr_vrect.width/2 - 3 + cl_crossx.value; 573 y = scr_vrect.y + scr_vrect.height/2 - 3 + cl_crossy.value; 574 575 glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); 576 pColor = (unsigned char *) &d_8to24table[(byte) crosshaircolor.value]; 577 glColor4ubv ( pColor ); 578 GL_Bind (cs_texture); 579 580#ifdef USE_OPENGLES 581 DrawQuad(x - 4, y - 4, 16, 16, 0, 0, 1, 1); 582#else 583 glBegin (GL_QUADS); 584 glTexCoord2f (0, 0); 585 glVertex2f (x - 4, y - 4); 586 glTexCoord2f (1, 0); 587 glVertex2f (x+12, y-4); 588 glTexCoord2f (1, 1); 589 glVertex2f (x+12, y+12); 590 glTexCoord2f (0, 1); 591 glVertex2f (x - 4, y+12); 592 glEnd (); 593#endif 594 595 glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); 596 } else if (crosshair.value) 597 Draw_Character (scr_vrect.x + scr_vrect.width/2-4 + cl_crossx.value, 598 scr_vrect.y + scr_vrect.height/2-4 + cl_crossy.value, 599 '+'); 600} 601 602 603/* 604================ 605Draw_DebugChar 606 607Draws a single character directly to the upper right corner of the screen. 608This is for debugging lockups by drawing different chars in different parts 609of the code. 610================ 611*/ 612void Draw_DebugChar (char num) 613{ 614} 615 616/* 617============= 618Draw_Pic 619============= 620*/ 621void Draw_Pic (int x, int y, qpic_t *pic) 622{ 623 glpic_t *gl; 624 625 if (scrap_dirty) 626 Scrap_Upload (); 627 gl = (glpic_t *)pic->data; 628 glColor4f (1,1,1,1); 629 GL_Bind (gl->texnum); 630#ifdef USE_OPENGLES 631 DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl); 632#else 633 glBegin (GL_QUADS); 634 glTexCoord2f (gl->sl, gl->tl); 635 glVertex2f (x, y); 636 glTexCoord2f (gl->sh, gl->tl); 637 glVertex2f (x+pic->width, y); 638 glTexCoord2f (gl->sh, gl->th); 639 glVertex2f (x+pic->width, y+pic->height); 640 glTexCoord2f (gl->sl, gl->th); 641 glVertex2f (x, y+pic->height); 642 glEnd (); 643#endif 644} 645 646/* 647============= 648Draw_AlphaPic 649============= 650*/ 651void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha) 652{ 653 glpic_t *gl; 654 655 if (scrap_dirty) 656 Scrap_Upload (); 657 gl = (glpic_t *)pic->data; 658 glDisable(GL_ALPHA_TEST); 659 glEnable (GL_BLEND); 660// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 661 glCullFace(GL_FRONT); 662 glColor4f (1,1,1,alpha); 663 GL_Bind (gl->texnum); 664#ifdef USE_OPENGLES 665 DrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl); 666#else 667 glBegin (GL_QUADS); 668 glTexCoord2f (gl->sl, gl->tl); 669 glVertex2f (x, y); 670 glTexCoord2f (gl->sh, gl->tl); 671 glVertex2f (x+pic->width, y); 672 glTexCoord2f (gl->sh, gl->th); 673 glVertex2f (x+pic->width, y+pic->height); 674 glTexCoord2f (gl->sl, gl->th); 675 glVertex2f (x, y+pic->height); 676 glEnd (); 677#endif 678 glColor4f (1,1,1,1); 679 glEnable(GL_ALPHA_TEST); 680 glDisable (GL_BLEND); 681} 682 683void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height) 684{ 685 glpic_t *gl; 686 float newsl, newtl, newsh, newth; 687 float oldglwidth, oldglheight; 688 689 if (scrap_dirty) 690 Scrap_Upload (); 691 gl = (glpic_t *)pic->data; 692 693 oldglwidth = gl->sh - gl->sl; 694 oldglheight = gl->th - gl->tl; 695 696 newsl = gl->sl + (srcx*oldglwidth)/pic->width; 697 newsh = newsl + (width*oldglwidth)/pic->width; 698 699 newtl = gl->tl + (srcy*oldglheight)/pic->height; 700 newth = newtl + (height*oldglheight)/pic->height; 701 702 glColor4f (1,1,1,1); 703 GL_Bind (gl->texnum); 704#ifdef USE_OPENGLES 705 DrawQuad(x, y, width, height, newsl, newtl, newsh - newsl, newth - newtl); 706#else 707 glBegin (GL_QUADS); 708 glTexCoord2f (newsl, newtl); 709 glVertex2f (x, y); 710 glTexCoord2f (newsh, newtl); 711 glVertex2f (x+width, y); 712 glTexCoord2f (newsh, newth); 713 glVertex2f (x+width, y+height); 714 glTexCoord2f (newsl, newth); 715 glVertex2f (x, y+height); 716 glEnd (); 717#endif 718} 719 720/* 721============= 722Draw_TransPic 723============= 724*/ 725void Draw_TransPic (int x, int y, qpic_t *pic) 726{ 727 728 if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || 729 (unsigned)(y + pic->height) > vid.height) 730 { 731 Sys_Error ("Draw_TransPic: bad coordinates"); 732 } 733 734 Draw_Pic (x, y, pic); 735} 736 737 738/* 739============= 740Draw_TransPicTranslate 741 742Only used for the player color selection menu 743============= 744*/ 745void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation) 746{ 747 int v, u, c; 748 unsigned trans[64*64], *dest; 749 byte *src; 750 int p; 751 752 GL_Bind (translate_texture); 753 754 c = pic->width * pic->height; 755 756 dest = trans; 757 for (v=0 ; v<64 ; v++, dest += 64) 758 { 759 src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width]; 760 for (u=0 ; u<64 ; u++) 761 { 762 p = src[(u*pic->width)>>6]; 763 if (p == 255) 764 dest[u] = p; 765 else 766 dest[u] = d_8to24table[translation[p]]; 767 } 768 } 769 770 glTexImage2DHelper (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); 771 772 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 773 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 774 775 glColor3f (1,1,1); 776#ifdef USE_OPENGLES 777 DrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1); 778#else 779 glBegin (GL_QUADS); 780 glTexCoord2f (0, 0); 781 glVertex2f (x, y); 782 glTexCoord2f (1, 0); 783 glVertex2f (x+pic->width, y); 784 glTexCoord2f (1, 1); 785 glVertex2f (x+pic->width, y+pic->height); 786 glTexCoord2f (0, 1); 787 glVertex2f (x, y+pic->height); 788 glEnd (); 789#endif 790} 791 792 793/* 794================ 795Draw_ConsoleBackground 796 797================ 798*/ 799void Draw_ConsoleBackground (int lines) 800{ 801 char ver[80]; 802 int x, i; 803 int y; 804 805 y = (vid.height * 3) >> 2; 806 if (lines > y) 807 Draw_Pic(0, lines-vid.height, conback); 808 else 809 Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y); 810 811 // hack the version number directly into the pic 812// y = lines-186; 813 y = lines-14; 814 if (!cls.download) { 815#ifdef __linux__ 816 sprintf (ver, "LinuxGL (%4.2f) QuakeWorld", LINUX_VERSION); 817#else 818 sprintf (ver, "GL (%4.2f) QuakeWorld", GLQUAKE_VERSION); 819#endif 820 x = vid.conwidth - (strlen(ver)*8 + 11) - (vid.conwidth*8/320)*7; 821 for (i=0 ; i< (int) strlen(ver) ; i++) 822 Draw_Character (x + i * 8, y, ver[i] | 0x80); 823 } 824} 825 826 827/* 828============= 829Draw_TileClear 830 831This repeats a 64*64 tile graphic to fill the screen around a sized down 832refresh window. 833============= 834*/ 835void Draw_TileClear (int x, int y, int w, int h) 836{ 837 glColor3f (1,1,1); 838 GL_Bind (*(int *)draw_backtile->data); 839#ifdef USE_OPENGLES 840 DrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0); 841#else 842 glBegin (GL_QUADS); 843 glTexCoord2f (x/64.0, y/64.0); 844 glVertex2f (x, y); 845 glTexCoord2f ( (x+w)/64.0, y/64.0); 846 glVertex2f (x+w, y); 847 glTexCoord2f ( (x+w)/64.0, (y+h)/64.0); 848 glVertex2f (x+w, y+h); 849 glTexCoord2f ( x/64.0, (y+h)/64.0 ); 850 glVertex2f (x, y+h); 851 glEnd (); 852#endif 853} 854 855 856/* 857============= 858Draw_Fill 859 860Fills a box of pixels with a single color 861============= 862*/ 863void Draw_Fill (int x, int y, int w, int h, int c) 864{ 865 glDisable (GL_TEXTURE_2D); 866 glColor3f (host_basepal[c*3]/255.0, 867 host_basepal[c*3+1]/255.0, 868 host_basepal[c*3+2]/255.0); 869 870#ifdef USE_OPENGLES 871 DrawQuad_NoTex(x, y, w, h); 872#else 873 glBegin (GL_QUADS); 874 875 glVertex2f (x,y); 876 glVertex2f (x+w, y); 877 glVertex2f (x+w, y+h); 878 glVertex2f (x, y+h); 879 880 glEnd (); 881#endif 882 glColor3f (1,1,1); 883 glEnable (GL_TEXTURE_2D); 884} 885//============================================================================= 886 887/* 888================ 889Draw_FadeScreen 890 891================ 892*/ 893void Draw_FadeScreen (void) 894{ 895 glEnable (GL_BLEND); 896 glDisable (GL_TEXTURE_2D); 897 glColor4f (0, 0, 0, 0.8); 898 899#ifdef USE_OPENGLES 900 DrawQuad_NoTex(0, 0, vid.width, vid.height); 901#else 902 glBegin (GL_QUADS); 903 904 glVertex2f (0,0); 905 glVertex2f (vid.width, 0); 906 glVertex2f (vid.width, vid.height); 907 glVertex2f (0, vid.height); 908 909 glEnd (); 910#endif 911 glColor4f (1,1,1,1); 912 glEnable (GL_TEXTURE_2D); 913 glDisable (GL_BLEND); 914 915 Sbar_Changed(); 916} 917 918//============================================================================= 919 920/* 921================ 922Draw_BeginDisc 923 924Draws the little blue disc in the corner of the screen. 925Call before beginning any disc IO. 926================ 927*/ 928void Draw_BeginDisc (void) 929{ 930 if (!draw_disc) 931 return; 932#ifdef USE_OPENGLES 933 // !!! Implement this 934#else 935 glDrawBuffer (GL_FRONT); 936 Draw_Pic (vid.width - 24, 0, draw_disc); 937 glDrawBuffer (GL_BACK); 938#endif 939} 940 941 942/* 943================ 944Draw_EndDisc 945 946Erases the disc icon. 947Call after completing any disc IO 948================ 949*/ 950void Draw_EndDisc (void) 951{ 952} 953 954/* 955================ 956GL_Set2D 957 958Setup as if the screen was 320*200 959================ 960*/ 961void GL_Set2D (void) 962{ 963 glViewport (glx, gly, glwidth, glheight); 964 965 glMatrixMode(GL_PROJECTION); 966 glLoadIdentity (); 967#ifdef USE_OPENGLES 968 glOrthof (0, vid.width, vid.height, 0, -99999, 99999); 969#else 970 glOrtho (0, vid.width, vid.height, 0, -99999, 99999); 971#endif 972 973 glMatrixMode(GL_MODELVIEW); 974 glLoadIdentity (); 975 976 glDisable (GL_DEPTH_TEST); 977 glDisable (GL_CULL_FACE); 978 glDisable (GL_BLEND); 979 glEnable (GL_ALPHA_TEST); 980// glDisable (GL_ALPHA_TEST); 981 982 glColor4f (1,1,1,1); 983} 984 985//==================================================================== 986 987/* 988================ 989GL_FindTexture 990================ 991*/ 992int GL_FindTexture (char *identifier) 993{ 994 int i; 995 gltexture_t *glt; 996 997 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++) 998 { 999 if (!strcmp (identifier, glt->identifier)) 1000 return gltextures[i].texnum; 1001 } 1002 1003 return -1; 1004} 1005 1006/* 1007================ 1008GL_ResampleTexture 1009================ 1010*/ 1011void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) 1012{ 1013 int i, j; 1014 unsigned *inrow; 1015 unsigned frac, fracstep; 1016 1017 fracstep = inwidth*0x10000/outwidth; 1018 for (i=0 ; i<outheight ; i++, out += outwidth) 1019 { 1020 inrow = in + inwidth*(i*inheight/outheight); 1021 frac = fracstep >> 1; 1022 for (j=0 ; j<outwidth ; j+=4) 1023 { 1024 out[j] = inrow[frac>>16]; 1025 frac += fracstep; 1026 out[j+1] = inrow[frac>>16]; 1027 frac += fracstep; 1028 out[j+2] = inrow[frac>>16]; 1029 frac += fracstep; 1030 out[j+3] = inrow[frac>>16]; 1031 frac += fracstep; 1032 } 1033 } 1034} 1035 1036/* 1037================ 1038GL_Resample8BitTexture -- JACK 1039================ 1040*/ 1041void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight) 1042{ 1043 int i, j; 1044 unsigned char *inrow; 1045 unsigned frac, fracstep; 1046 1047 fracstep = inwidth*0x10000/outwidth; 1048 for (i=0 ; i<outheight ; i++, out += outwidth) 1049 { 1050 inrow = in + inwidth*(i*inheight/outheight); 1051 frac = fracstep >> 1; 1052 for (j=0 ; j<outwidth ; j+=4) 1053 { 1054 out[j] = inrow[frac>>16]; 1055 frac += fracstep; 1056 out[j+1] = inrow[frac>>16]; 1057 frac += fracstep; 1058 out[j+2] = inrow[frac>>16]; 1059 frac += fracstep; 1060 out[j+3] = inrow[frac>>16]; 1061 frac += fracstep; 1062 } 1063 } 1064} 1065 1066/* 1067================ 1068GL_MipMap 1069 1070Operates in place, quartering the size of the texture 1071================ 1072*/ 1073void GL_MipMap (byte *in, int width, int height) 1074{ 1075 int i, j; 1076 byte *out; 1077 1078 width <<=2; 1079 height >>= 1; 1080 out = in; 1081 for (i=0 ; i<height ; i++, in+=width) 1082 { 1083 for (j=0 ; j<width ; j+=8, out+=4, in+=8) 1084 { 1085 out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2; 1086 out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; 1087 out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; 1088 out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; 1089 } 1090 } 1091} 1092 1093/* 1094================ 1095GL_MipMap8Bit 1096 1097Mipping for 8 bit textures 1098================ 1099*/ 1100void GL_MipMap8Bit (byte *in, int width, int height) 1101{ 1102 int i, j; 1103 byte *out; 1104 unsigned short r,g,b; 1105 byte *at1, *at2, *at3, *at4; 1106 1107 height >>= 1; 1108 out = in; 1109 for (i=0 ; i<height ; i++, in+=width) 1110 for (j=0 ; j<width ; j+=2, out+=1, in+=2) 1111 { 1112 at1 = (byte *) &d_8to24table[in[0]]; 1113 at2 = (byte *) &d_8to24table[in[1]]; 1114 at3 = (byte *) &d_8to24table[in[width+0]]; 1115 at4 = (byte *) &d_8to24table[in[width+1]]; 1116 1117 r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5; 1118 g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5; 1119 b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5; 1120 1121 out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)]; 1122 } 1123} 1124 1125void glTexImage2DHelper( GLenum target, 1126 GLint level, 1127 GLint internalformat, 1128 GLsizei width, 1129 GLsizei height, 1130 GLint border, 1131 GLenum format, 1132 GLenum type, 1133 const GLvoid *pixels ) 1134{ 1135 // In full OpenGL The internalformat can be 1..4, to indicate how many components of the data are valid. 1136 // OpenGL ES requires the internalformat argument match the format for glTexImage2D. 1137 1138 glTexImage2D(target, level, format, width, height, border, format, type, pixels); 1139} 1140 1141/* 1142=============== 1143GL_Upload32 1144=============== 1145*/ 1146void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha) 1147{ 1148 int samples; 1149static unsigned scaled[1024*512]; // [512*256]; 1150 int scaled_width, scaled_height; 1151 1152 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) 1153 ; 1154 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) 1155 ; 1156 1157 scaled_width >>= (int)gl_picmip.value; 1158 scaled_height >>= (int)gl_picmip.value; 1159 1160 if (scaled_width > (int) gl_max_size.value) 1161 scaled_width = gl_max_size.value; 1162 if (scaled_height > (int) gl_max_size.value) 1163 scaled_height = gl_max_size.value; 1164 1165 if (scaled_width * scaled_height > (int) sizeof(scaled)/4) 1166 Sys_Error ("GL_LoadTexture: too big"); 1167 1168 samples = alpha ? gl_alpha_format : gl_solid_format; 1169 1170#if 0 1171 if (mipmap) 1172 gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, trans); 1173 else if (scaled_width == width && scaled_height == height) 1174 glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); 1175 else 1176 { 1177 gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, trans, 1178 scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled); 1179 glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); 1180 } 1181#else 1182texels += scaled_width * scaled_height; 1183 1184 if (scaled_width == width && scaled_height == height) 1185 { 1186 if (!mipmap) 1187 { 1188 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 1189 goto done; 1190 } 1191 memcpy (scaled, data, width*height*4); 1192 } 1193 else 1194 GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); 1195 1196 glTexImage2DHelper (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); 1197 if (mipmap) 1198 { 1199 int miplevel; 1200 1201 miplevel = 0; 1202 while (scaled_width > 1 || scaled_height > 1) 1203 { 1204 GL_MipMap ((byte *)scaled, scaled_width, scaled_height); 1205 scaled_width >>= 1; 1206 scaled_height >>= 1; 1207 if (scaled_width < 1) 1208 scaled_width = 1; 1209 if (scaled_height < 1) 1210 scaled_height = 1; 1211 miplevel++; 1212 glTexImage2DHelper (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); 1213 } 1214 } 1215done: ; 1216#endif 1217 1218 1219 if (mipmap) 1220 { 1221 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 1222 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1223 } 1224 else 1225 { 1226 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); 1227 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1228 } 1229} 1230 1231void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha) 1232{ 1233 int i, s; 1234 qboolean noalpha; 1235 int samples; 1236 static unsigned char scaled[1024*512]; // [512*256]; 1237 int scaled_width, scaled_height; 1238 1239 s = width*height; 1240 // if there are no transparent pixels, make it a 3 component 1241 // texture even if it was specified as otherwise 1242 if (alpha) 1243 { 1244 noalpha = true; 1245 for (i=0 ; i<s ; i++) 1246 { 1247 if (data[i] == 255) 1248 noalpha = false; 1249 } 1250 1251 if (alpha && noalpha) 1252 alpha = false; 1253 } 1254 for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) 1255 ; 1256 for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) 1257 ; 1258 1259 scaled_width >>= (int)gl_picmip.value; 1260 scaled_height >>= (int)gl_picmip.value; 1261 1262 if (scaled_width > gl_max_size.value) 1263 scaled_width = gl_max_size.value; 1264 if (scaled_height > gl_max_size.value) 1265 scaled_height = gl_max_size.value; 1266 1267 if (scaled_width * scaled_height > (int) sizeof(scaled)) 1268 Sys_Error ("GL_LoadTexture: too big"); 1269 1270 samples = 1; // alpha ? gl_alpha_format : gl_solid_format; 1271 1272 texels += scaled_width * scaled_height; 1273 1274 if (scaled_width == width && scaled_height == height) 1275 { 1276 if (!mipmap) 1277 { 1278#ifdef USE_OPENGLES 1279 glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, data); 1280#else 1281 glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data); 1282#endif 1283 goto done; 1284 } 1285 memcpy (scaled, data, width*height); 1286 } 1287 else 1288 GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height); 1289 1290#ifdef USE_OPENGLES 1291 glCompressedTexImage2D (GL_TEXTURE_2D, 0, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled); 1292#else 1293 glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); 1294#endif 1295 1296 if (mipmap) 1297 { 1298 int miplevel; 1299 1300 miplevel = 0; 1301 while (scaled_width > 1 || scaled_height > 1) 1302 { 1303 GL_MipMap8Bit ((byte *)scaled, scaled_width, scaled_height); 1304 scaled_width >>= 1; 1305 scaled_height >>= 1; 1306 if (scaled_width < 1) 1307 scaled_width = 1; 1308 if (scaled_height < 1) 1309 scaled_height = 1; 1310 miplevel++; 1311#ifdef USE_OPENGLES 1312 glCompressedTexImage2D (GL_TEXTURE_2D, miplevel, GL_PALETTE8_RGB8_OES, scaled_width, scaled_height, 0, s, scaled); 1313#else 1314 glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); 1315#endif 1316 } 1317 } 1318done: ; 1319 1320 if (mipmap) 1321 { 1322 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); 1323 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1324 } 1325 else 1326 { 1327 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); 1328 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); 1329 } 1330} 1331 1332extern qboolean VID_Is8bit(); 1333 1334/* 1335=============== 1336GL_Upload8 1337=============== 1338*/ 1339void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha) 1340{ 1341static unsigned trans[640*480]; // FIXME, temporary 1342 int i, s; 1343 qboolean noalpha; 1344 int p; 1345 1346 s = width*height; 1347 // if there are no transparent pixels, make it a 3 component 1348 // texture even if it was specified as otherwise 1349 if (alpha) 1350 { 1351 noalpha = true; 1352 for (i=0 ; i<s ; i++) 1353 { 1354 p = data[i]; 1355 if (p == 255) 1356 noalpha = false; 1357 trans[i] = d_8to24table[p]; 1358 } 1359 1360 if (alpha && noalpha) 1361 alpha = false; 1362 } 1363 else 1364 { 1365 if (s&3) 1366 Sys_Error ("GL_Upload8: s&3"); 1367 for (i=0 ; i<s ; i+=4) 1368 { 1369 trans[i] = d_8to24table[data[i]]; 1370 trans[i+1] = d_8to24table[data[i+1]]; 1371 trans[i+2] = d_8to24table[data[i+2]]; 1372 trans[i+3] = d_8to24table[data[i+3]]; 1373 } 1374 } 1375 1376 if (VID_Is8bit() && !alpha && (data!=scrap_texels[0])) { 1377 GL_Upload8_EXT (data, width, height, mipmap, alpha); 1378 return; 1379 } 1380 1381 GL_Upload32 (trans, width, height, mipmap, alpha); 1382} 1383 1384/* 1385================ 1386GL_LoadTexture 1387================ 1388*/ 1389int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha) 1390{ 1391 int i; 1392 gltexture_t *glt; 1393 1394 // see if the texture is allready present 1395 if (identifier[0]) 1396 { 1397 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++) 1398 { 1399 if (!strcmp (identifier, glt->identifier)) 1400 { 1401 if (width != glt->width || height != glt->height) 1402 Sys_Error ("GL_LoadTexture: cache mismatch"); 1403 return gltextures[i].texnum; 1404 } 1405 } 1406 } 1407 else 1408 glt = &gltextures[numgltextures]; 1409 numgltextures++; 1410 1411 strcpy (glt->identifier, identifier); 1412 glt->texnum = texture_extension_number; 1413 glt->width = width; 1414 glt->height = height; 1415 glt->mipmap = mipmap; 1416 1417 GL_Bind(texture_extension_number ); 1418 1419 GL_Upload8 (data, width, height, mipmap, alpha); 1420 1421 texture_extension_number++; 1422 1423 return texture_extension_number-1; 1424} 1425 1426/* 1427================ 1428GL_LoadPicTexture 1429================ 1430*/ 1431int GL_LoadPicTexture (qpic_t *pic) 1432{ 1433 return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true); 1434} 1435 1436/****************************************/ 1437 1438static GLenum oldtarget = TEXTURE0_SGIS; 1439 1440void GL_SelectTexture (GLenum target) 1441{ 1442 if (!gl_mtexable) 1443 return; 1444#ifdef USE_OPENGLES 1445 // !!! Implement this. 1446#else 1447#ifndef __linux__ // no multitexture under Linux yet 1448 qglSelectTextureSGIS(target); 1449#endif 1450#endif 1451 if (target == oldtarget) 1452 return; 1453 cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture; 1454 currenttexture = cnttextures[target-TEXTURE0_SGIS]; 1455 oldtarget = target; 1456} 1457 1458 1459// OpenGL ES compatible DrawQuad utility 1460 1461void DrawQuad_NoTex(float x, float y, float w, float h) 1462{ 1463 glEnableClientState(GL_VERTEX_ARRAY); 1464 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 1465 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h}; 1466 short index[4] = {0, 1, 2, 3}; 1467 glVertexPointer( 2, GL_FLOAT, 0, vertex); 1468 glDrawElements(GL_TRIANGLE_FAN, 4, GL_SHORT, index); 1469} 1470 1471void DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh) 1472{ 1473 glEnableClientState(GL_VERTEX_ARRAY); 1474 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 1475 float texcoord[2*4] = {u, v, u + uw, v, u + uw, v + vh, u, v + vh}; 1476 float vertex[2*4] = {x,y,x+w,y, x+w, y+h, x, y+h}; 1477 unsigned short index[4] = {0, 1, 2, 3}; 1478 glTexCoordPointer( 2, GL_FLOAT, 0, texcoord); 1479 glVertexPointer( 2, GL_FLOAT, 0, vertex); 1480 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, index); 1481} 1482 1483#ifdef USE_OPENGLES 1484 1485// Reimplementation of OpenGL functions that are missing in OpenGL ES 1486 1487void glColor3f(GLfloat r, GLfloat g, GLfloat b) 1488{ 1489 glColor4f(r, g, b, 1.0f); 1490} 1491 1492void glColor4fv(GLfloat* pColor) 1493{ 1494 glColor4f(pColor[0], pColor[1], pColor[2], pColor[3]); 1495} 1496 1497void glColor4ubv(unsigned char* pColor) 1498{ 1499 glColor4f(pColor[0] / 255.0f, pColor[1] / 255.0f, pColor[2] / 255.0f, pColor[3] / 255.0f); 1500} 1501 1502#endif 1503