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 // r_main.c 21 22 #include "quakedef.h" 23 24 entity_t r_worldentity; 25 26 qboolean r_cache_thrash; // compatability 27 28 vec3_t modelorg, r_entorigin; 29 entity_t *currententity; 30 31 int r_visframecount; // bumped when going to a new PVS 32 int r_framecount; // used for dlight push checking 33 34 mplane_t frustum[4]; 35 36 int c_brush_polys, c_alias_polys; 37 38 qboolean envmap; // true during envmap command capture 39 40 int currenttexture = -1; // to avoid unnecessary texture sets 41 42 int cnttextures[2] = {-1, -1}; // cached 43 44 int particletexture; // little dot for particles 45 int playertextures; // up to 16 color translated skins 46 47 int mirrortexturenum; // quake texturenum, not gltexturenum 48 qboolean mirror; 49 mplane_t *mirror_plane; 50 51 // 52 // view origin 53 // 54 vec3_t vup; 55 vec3_t vpn; 56 vec3_t vright; 57 vec3_t r_origin; 58 59 float r_world_matrix[16]; 60 float r_base_world_matrix[16]; 61 62 // 63 // screen size info 64 // 65 refdef_t r_refdef; 66 67 mleaf_t *r_viewleaf, *r_oldviewleaf; 68 69 texture_t *r_notexture_mip; 70 71 int d_lightstylevalue[256]; // 8.8 fraction of base light value 72 73 74 void R_MarkLeaves (void); 75 76 cvar_t r_norefresh = CVAR2("r_norefresh","0"); 77 cvar_t r_drawentities = CVAR2("r_drawentities","1"); 78 cvar_t r_drawviewmodel = CVAR2("r_drawviewmodel","1"); 79 cvar_t r_speeds = CVAR2("r_speeds","0"); 80 cvar_t r_fullbright = CVAR2("r_fullbright","0"); 81 cvar_t r_lightmap = CVAR2("r_lightmap","0"); 82 cvar_t r_shadows = CVAR2("r_shadows","0"); 83 cvar_t r_mirroralpha = CVAR2("r_mirroralpha","1"); 84 cvar_t r_wateralpha = CVAR2("r_wateralpha","1"); 85 cvar_t r_dynamic = CVAR2("r_dynamic","1"); 86 cvar_t r_novis = CVAR2("r_novis","0"); 87 88 cvar_t gl_finish = CVAR2("gl_finish","0"); 89 cvar_t gl_clear = CVAR2("gl_clear","0"); 90 cvar_t gl_cull = CVAR2("gl_cull","1"); 91 cvar_t gl_texsort = CVAR2("gl_texsort","1"); 92 cvar_t gl_smoothmodels = CVAR2("gl_smoothmodels","1"); 93 cvar_t gl_affinemodels = CVAR2("gl_affinemodels","1"); 94 cvar_t gl_polyblend = CVAR2("gl_polyblend","1"); 95 cvar_t gl_flashblend = CVAR2("gl_flashblend","1"); 96 cvar_t gl_playermip = CVAR2("gl_playermip","0"); 97 cvar_t gl_nocolors = CVAR2("gl_nocolors","0"); 98 cvar_t gl_keeptjunctions = CVAR2("gl_keeptjunctions","1"); 99 cvar_t gl_reporttjunctions = CVAR2("gl_reporttjunctions","0"); 100 cvar_t gl_doubleeyes = CVAR2("gl_doubleeys", "1"); 101 102 extern cvar_t gl_ztrick; 103 104 /* 105 ================= 106 R_CullBox 107 108 Returns true if the box is completely outside the frustom 109 ================= 110 */ 111 qboolean R_CullBox (vec3_t mins, vec3_t maxs) 112 { 113 int i; 114 115 for (i=0 ; i<4 ; i++) 116 if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2) 117 return true; 118 return false; 119 } 120 121 122 void R_RotateForEntity (entity_t *e) 123 { 124 glTranslatef (e->origin[0], e->origin[1], e->origin[2]); 125 126 glRotatef (e->angles[1], 0, 0, 1); 127 glRotatef (-e->angles[0], 0, 1, 0); 128 glRotatef (e->angles[2], 1, 0, 0); 129 } 130 131 /* 132 ============================================================= 133 134 SPRITE MODELS 135 136 ============================================================= 137 */ 138 139 /* 140 ================ 141 R_GetSpriteFrame 142 ================ 143 */ 144 mspriteframe_t *R_GetSpriteFrame (entity_t *currententity) 145 { 146 msprite_t *psprite; 147 mspritegroup_t *pspritegroup; 148 mspriteframe_t *pspriteframe; 149 int i, numframes, frame; 150 float *pintervals, fullinterval, targettime, time; 151 152 psprite = (msprite_t*) currententity->model->cache.data; 153 frame = currententity->frame; 154 155 if ((frame >= psprite->numframes) || (frame < 0)) 156 { 157 Con_Printf ("R_DrawSprite: no such frame %d\n", frame); 158 frame = 0; 159 } 160 161 if (psprite->frames[frame].type == SPR_SINGLE) 162 { 163 pspriteframe = psprite->frames[frame].frameptr; 164 } 165 else 166 { 167 pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; 168 pintervals = pspritegroup->intervals; 169 numframes = pspritegroup->numframes; 170 fullinterval = pintervals[numframes-1]; 171 172 time = cl.time + currententity->syncbase; 173 174 // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values 175 // are positive, so we don't have to worry about division by 0 176 targettime = time - ((int)(time / fullinterval)) * fullinterval; 177 178 for (i=0 ; i<(numframes-1) ; i++) 179 { 180 if (pintervals[i] > targettime) 181 break; 182 } 183 184 pspriteframe = pspritegroup->frames[i]; 185 } 186 187 return pspriteframe; 188 } 189 190 191 /* 192 ================= 193 R_DrawSpriteModel 194 195 ================= 196 */ 197 void R_DrawSpriteModel (entity_t *e) 198 { 199 vec3_t point; 200 mspriteframe_t *frame; 201 float *up, *right; 202 vec3_t v_forward, v_right, v_up; 203 msprite_t *psprite; 204 205 // don't even bother culling, because it's just a single 206 // polygon without a surface cache 207 frame = R_GetSpriteFrame (e); 208 psprite = (msprite_t*) currententity->model->cache.data; 209 210 if (psprite->type == SPR_ORIENTED) 211 { // bullet marks on walls 212 AngleVectors (currententity->angles, v_forward, v_right, v_up); 213 up = v_up; 214 right = v_right; 215 } 216 else 217 { // normal sprite 218 up = vup; 219 right = vright; 220 } 221 222 glColor3f (1,1,1); 223 224 GL_DisableMultitexture(); 225 226 GL_Bind(frame->gl_texturenum); 227 228 glEnable (GL_ALPHA_TEST); 229 230 #ifdef USE_OPENGLES 231 232 { 233 float* pPoint = gVertexBuffer; 234 float texCoords[] = { 235 0, 1, 236 0, 0, 237 1, 0, 238 1, 1 239 }; 240 241 VectorMA (e->origin, frame->down, up, point); 242 VectorMA (point, frame->left, right, pPoint); 243 pPoint += 3; 244 245 VectorMA (e->origin, frame->up, up, point); 246 VectorMA (point, frame->left, right, pPoint); 247 pPoint += 3; 248 249 VectorMA (e->origin, frame->up, up, point); 250 VectorMA (point, frame->right, right, pPoint); 251 pPoint += 3; 252 253 VectorMA (e->origin, frame->down, up, point); 254 VectorMA (point, frame->right, right, pPoint); 255 256 glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer); 257 glTexCoordPointer(2, GL_FLOAT, 0, texCoords); 258 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 259 } 260 261 #else 262 glBegin (GL_QUADS); 263 264 glTexCoord2f (0, 1); 265 VectorMA (e->origin, frame->down, up, point); 266 VectorMA (point, frame->left, right, point); 267 glVertex3fv (point); 268 269 glTexCoord2f (0, 0); 270 VectorMA (e->origin, frame->up, up, point); 271 VectorMA (point, frame->left, right, point); 272 glVertex3fv (point); 273 274 glTexCoord2f (1, 0); 275 VectorMA (e->origin, frame->up, up, point); 276 VectorMA (point, frame->right, right, point); 277 glVertex3fv (point); 278 279 glTexCoord2f (1, 1); 280 VectorMA (e->origin, frame->down, up, point); 281 VectorMA (point, frame->right, right, point); 282 glVertex3fv (point); 283 284 glEnd (); 285 #endif 286 287 glDisable (GL_ALPHA_TEST); 288 } 289 290 /* 291 ============================================================= 292 293 ALIAS MODELS 294 295 ============================================================= 296 */ 297 298 299 #define NUMVERTEXNORMALS 162 300 301 float r_avertexnormals[NUMVERTEXNORMALS][3] = { 302 #include "anorms.h" 303 }; 304 305 vec3_t shadevector; 306 float shadelight, ambientlight; 307 308 // precalculated dot products for quantized angles 309 #define SHADEDOT_QUANT 16 310 float r_avertexnormal_dots[SHADEDOT_QUANT][256] = 311 #include "anorm_dots.h" 312 ; 313 314 float *shadedots = r_avertexnormal_dots[0]; 315 316 int lastposenum; 317 318 /* 319 ============= 320 GL_DrawAliasFrame 321 ============= 322 */ 323 void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum) 324 { 325 float s, t; 326 float l; 327 int i, j; 328 int index; 329 trivertx_t *v, *verts; 330 int list; 331 int *order; 332 vec3_t point; 333 float *normal; 334 int count; 335 336 #ifdef USE_OPENGLES 337 glEnableClientState(GL_COLOR_ARRAY); 338 #endif 339 340 lastposenum = posenum; 341 342 verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); 343 verts += posenum * paliashdr->poseverts; 344 order = (int *)((byte *)paliashdr + paliashdr->commands); 345 346 while (1) 347 { 348 // get the vertex count and primitive type 349 count = *order++; 350 if (!count) 351 break; // done 352 353 #ifdef USE_OPENGLES 354 { 355 int primType; 356 int c; 357 float* pColor; 358 float* pTexCoord; 359 float* pPos; 360 361 if (count < 0) 362 { 363 count = -count; 364 primType = GL_TRIANGLE_FAN; 365 } 366 else 367 primType = GL_TRIANGLE_STRIP; 368 369 // texture coordinates come from the draw list 370 glTexCoordPointer(2, GL_FLOAT, 0, gTexCoordBuffer); 371 glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer); 372 glColorPointer(4, GL_FLOAT, 0, gColorBuffer); 373 374 pColor = gColorBuffer; 375 pPos = gVertexBuffer; 376 pTexCoord = gTexCoordBuffer; 377 c = count; 378 do 379 { 380 // texture coordinates come from the draw list 381 *pTexCoord++ = ((float *)order)[0]; 382 *pTexCoord++ = ((float *)order)[1]; 383 order += 2; 384 385 // normals and vertexes come from the frame list 386 l = shadedots[verts->lightnormalindex] * shadelight; 387 *pColor++ = l; 388 *pColor++ = l; 389 *pColor++ = l; 390 *pColor++ = 1.0f; 391 *pPos++ = verts->v[0]; 392 *pPos++ = verts->v[1]; 393 *pPos++ = verts->v[2]; 394 verts++; 395 } while (--c); 396 397 glDrawArrays(primType, 0, count); 398 } 399 400 #else 401 if (count < 0) 402 { 403 count = -count; 404 glBegin (GL_TRIANGLE_FAN); 405 } 406 else 407 glBegin (GL_TRIANGLE_STRIP); 408 409 do 410 { 411 // texture coordinates come from the draw list 412 glTexCoord2f (((float *)order)[0], ((float *)order)[1]); 413 order += 2; 414 415 // normals and vertexes come from the frame list 416 l = shadedots[verts->lightnormalindex] * shadelight; 417 glColor3f (l, l, l); 418 glVertex3f (verts->v[0], verts->v[1], verts->v[2]); 419 verts++; 420 } while (--count); 421 422 glEnd (); 423 #endif 424 } 425 426 #ifdef USE_OPENGLES 427 glDisableClientState(GL_COLOR_ARRAY); 428 #endif 429 430 } 431 432 433 /* 434 ============= 435 GL_DrawAliasShadow 436 ============= 437 */ 438 extern vec3_t lightspot; 439 440 void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) 441 { 442 float s, t, l; 443 int i, j; 444 int index; 445 trivertx_t *v, *verts; 446 int list; 447 int *order; 448 vec3_t point; 449 float *normal; 450 float height, lheight; 451 int count; 452 453 lheight = currententity->origin[2] - lightspot[2]; 454 455 height = 0; 456 verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); 457 verts += posenum * paliashdr->poseverts; 458 order = (int *)((byte *)paliashdr + paliashdr->commands); 459 460 height = -lheight + 1.0; 461 462 while (1) 463 { 464 // get the vertex count and primitive type 465 count = *order++; 466 if (!count) 467 break; // done 468 469 #ifdef USE_OPENGLES 470 471 { 472 int primType; 473 int c; 474 float* pVertex; 475 476 if (count < 0) 477 { 478 count = -count; 479 primType = GL_TRIANGLE_FAN; 480 } 481 else 482 primType = GL_TRIANGLE_STRIP; 483 484 pVertex = gVertexBuffer; 485 for(c = 0; c < count; c++) 486 { 487 // texture coordinates come from the draw list 488 // (skipped for shadows) glTexCoord2fv ((float *)order); 489 order += 2; 490 491 // normals and vertexes come from the frame list 492 pVertex[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0]; 493 pVertex[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1]; 494 pVertex[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]; 495 496 pVertex[0] -= shadevector[0]*(pVertex[2]+lheight); 497 pVertex[1] -= shadevector[1]*(pVertex[2]+lheight); 498 pVertex[2] = height; 499 // height -= 0.001; 500 501 pVertex += 3; 502 verts++; 503 } 504 505 glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer); 506 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 507 glDrawArrays(primType, 0, count); 508 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 509 } 510 511 #else 512 513 if (count < 0) 514 { 515 count = -count; 516 glBegin (GL_TRIANGLE_FAN); 517 } 518 else 519 glBegin (GL_TRIANGLE_STRIP); 520 521 do 522 { 523 // texture coordinates come from the draw list 524 // (skipped for shadows) glTexCoord2fv ((float *)order); 525 order += 2; 526 527 // normals and vertexes come from the frame list 528 point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0]; 529 point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1]; 530 point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]; 531 532 point[0] -= shadevector[0]*(point[2]+lheight); 533 point[1] -= shadevector[1]*(point[2]+lheight); 534 point[2] = height; 535 // height -= 0.001; 536 glVertex3fv (point); 537 538 verts++; 539 } while (--count); 540 541 glEnd (); 542 543 #endif 544 545 } 546 } 547 548 549 550 /* 551 ================= 552 R_SetupAliasFrame 553 554 ================= 555 */ 556 void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr) 557 { 558 int pose, numposes; 559 float interval; 560 561 if ((frame >= paliashdr->numframes) || (frame < 0)) 562 { 563 Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); 564 frame = 0; 565 } 566 567 pose = paliashdr->frames[frame].firstpose; 568 numposes = paliashdr->frames[frame].numposes; 569 570 if (numposes > 1) 571 { 572 interval = paliashdr->frames[frame].interval; 573 pose += (int)(cl.time / interval) % numposes; 574 } 575 576 GL_DrawAliasFrame (paliashdr, pose); 577 } 578 579 580 581 /* 582 ================= 583 R_DrawAliasModel 584 585 ================= 586 */ 587 void R_DrawAliasModel (entity_t *e) 588 { 589 int i, j; 590 int lnum; 591 vec3_t dist; 592 float add; 593 model_t *clmodel; 594 vec3_t mins, maxs; 595 aliashdr_t *paliashdr; 596 trivertx_t *verts, *v; 597 int index; 598 float s, t, an; 599 int anim; 600 601 clmodel = currententity->model; 602 603 VectorAdd (currententity->origin, clmodel->mins, mins); 604 VectorAdd (currententity->origin, clmodel->maxs, maxs); 605 606 if (R_CullBox (mins, maxs)) 607 return; 608 609 610 VectorCopy (currententity->origin, r_entorigin); 611 VectorSubtract (r_origin, r_entorigin, modelorg); 612 613 // 614 // get lighting information 615 // 616 617 ambientlight = shadelight = R_LightPoint (currententity->origin); 618 619 // allways give the gun some light 620 if (e == &cl.viewent && ambientlight < 24) 621 ambientlight = shadelight = 24; 622 623 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 624 { 625 if (cl_dlights[lnum].die >= cl.time) 626 { 627 VectorSubtract (currententity->origin, 628 cl_dlights[lnum].origin, 629 dist); 630 add = cl_dlights[lnum].radius - Length(dist); 631 632 if (add > 0) { 633 ambientlight += add; 634 //ZOID models should be affected by dlights as well 635 shadelight += add; 636 } 637 } 638 } 639 640 // clamp lighting so it doesn't overbright as much 641 if (ambientlight > 128) 642 ambientlight = 128; 643 if (ambientlight + shadelight > 192) 644 shadelight = 192 - ambientlight; 645 646 // ZOID: never allow players to go totally black 647 i = currententity - cl_entities; 648 if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) 649 if (ambientlight < 8) 650 ambientlight = shadelight = 8; 651 652 // HACK HACK HACK -- no fullbright colors, so make torches full light 653 if (!strcmp (clmodel->name, "progs/flame2.mdl") 654 || !strcmp (clmodel->name, "progs/flame.mdl") ) 655 ambientlight = shadelight = 256; 656 657 shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; 658 shadelight = shadelight / 200.0; 659 660 an = e->angles[1]/180*M_PI; 661 shadevector[0] = cos(-an); 662 shadevector[1] = sin(-an); 663 shadevector[2] = 1; 664 VectorNormalize (shadevector); 665 666 // 667 // locate the proper data 668 // 669 paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); 670 671 c_alias_polys += paliashdr->numtris; 672 673 // 674 // draw all the triangles 675 // 676 677 GL_DisableMultitexture(); 678 679 glPushMatrix (); 680 R_RotateForEntity (e); 681 682 if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) { 683 glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); 684 // double size of eyes, since they are really hard to see in gl 685 glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); 686 } else { 687 glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); 688 glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); 689 } 690 691 anim = (int)(cl.time*10) & 3; 692 GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); 693 694 // we can't dynamically colormap textures, so they are cached 695 // seperately for the players. Heads are just uncolored. 696 if (currententity->colormap != vid.colormap && !gl_nocolors.value) 697 { 698 i = currententity - cl_entities; 699 if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) 700 GL_Bind(playertextures - 1 + i); 701 } 702 703 if (gl_smoothmodels.value) 704 glShadeModel (GL_SMOOTH); 705 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 706 707 if (gl_affinemodels.value) 708 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); 709 710 R_SetupAliasFrame (currententity->frame, paliashdr); 711 712 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 713 714 glShadeModel (GL_FLAT); 715 if (gl_affinemodels.value) 716 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 717 718 glPopMatrix (); 719 720 if (r_shadows.value) 721 { 722 glPushMatrix (); 723 R_RotateForEntity (e); 724 glDisable (GL_TEXTURE_2D); 725 glEnable (GL_BLEND); 726 glColor4f (0,0,0,0.5); 727 GL_DrawAliasShadow (paliashdr, lastposenum); 728 glEnable (GL_TEXTURE_2D); 729 glDisable (GL_BLEND); 730 glColor4f (1,1,1,1); 731 glPopMatrix (); 732 } 733 734 } 735 736 //================================================================================== 737 738 /* 739 ============= 740 R_DrawEntitiesOnList 741 ============= 742 */ 743 void R_DrawEntitiesOnList (void) 744 { 745 int i; 746 747 if (!r_drawentities.value) 748 return; 749 750 // draw sprites seperately, because of alpha blending 751 for (i=0 ; i<cl_numvisedicts ; i++) 752 { 753 currententity = cl_visedicts[i]; 754 755 switch (currententity->model->type) 756 { 757 case mod_alias: 758 R_DrawAliasModel (currententity); 759 break; 760 761 case mod_brush: 762 R_DrawBrushModel (currententity); 763 break; 764 765 default: 766 break; 767 } 768 } 769 770 for (i=0 ; i<cl_numvisedicts ; i++) 771 { 772 currententity = cl_visedicts[i]; 773 774 switch (currententity->model->type) 775 { 776 case mod_sprite: 777 R_DrawSpriteModel (currententity); 778 break; 779 780 default : 781 break; 782 } 783 } 784 } 785 786 /* 787 ============= 788 R_DrawViewModel 789 ============= 790 */ 791 void R_DrawViewModel (void) 792 { 793 float ambient[4], diffuse[4]; 794 int j; 795 int lnum; 796 vec3_t dist; 797 float add; 798 dlight_t *dl; 799 int ambientlight, shadelight; 800 801 if (!r_drawviewmodel.value) 802 return; 803 804 if (chase_active.value) 805 return; 806 807 if (envmap) 808 return; 809 810 if (!r_drawentities.value) 811 return; 812 813 if (cl.items & IT_INVISIBILITY) 814 return; 815 816 if (cl.stats[STAT_HEALTH] <= 0) 817 return; 818 819 currententity = &cl.viewent; 820 if (!currententity->model) 821 return; 822 823 j = R_LightPoint (currententity->origin); 824 825 if (j < 24) 826 j = 24; // allways give some light on gun 827 ambientlight = j; 828 shadelight = j; 829 830 // add dynamic lights 831 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 832 { 833 dl = &cl_dlights[lnum]; 834 if (!dl->radius) 835 continue; 836 if (!dl->radius) 837 continue; 838 if (dl->die < cl.time) 839 continue; 840 841 VectorSubtract (currententity->origin, dl->origin, dist); 842 add = dl->radius - Length(dist); 843 if (add > 0) 844 ambientlight += (int) add; 845 } 846 847 ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128; 848 diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128; 849 850 // hack the depth range to prevent view model from poking into walls 851 #ifdef USE_OPENGLES 852 glDepthRangef(gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin)); 853 R_DrawAliasModel (currententity); 854 glDepthRangef(gldepthmin, gldepthmax); 855 #else 856 glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); 857 R_DrawAliasModel (currententity); 858 glDepthRange (gldepthmin, gldepthmax); 859 #endif 860 } 861 862 863 /* 864 ============ 865 R_PolyBlend 866 ============ 867 */ 868 void R_PolyBlend (void) 869 { 870 if (!gl_polyblend.value) 871 return; 872 if (!v_blend[3]) 873 return; 874 875 GL_DisableMultitexture(); 876 877 glDisable (GL_ALPHA_TEST); 878 glEnable (GL_BLEND); 879 glDisable (GL_DEPTH_TEST); 880 glDisable (GL_TEXTURE_2D); 881 882 glLoadIdentity (); 883 884 glRotatef (-90, 1, 0, 0); // put Z going up 885 glRotatef (90, 0, 0, 1); // put Z going up 886 887 glColor4fv (v_blend); 888 889 #ifdef USE_OPENGLES 890 float vertex[3*4] = { 891 10, 100, 100, 892 10, -100, 100, 893 10, -100, -100, 894 10, 100, -100 895 }; 896 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 897 glVertexPointer( 3, GL_FLOAT, 0, vertex); 898 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 899 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 900 #else 901 glBegin (GL_QUADS); 902 903 glVertex3f (10, 100, 100); 904 glVertex3f (10, -100, 100); 905 glVertex3f (10, -100, -100); 906 glVertex3f (10, 100, -100); 907 glEnd (); 908 #endif 909 910 glDisable (GL_BLEND); 911 glEnable (GL_TEXTURE_2D); 912 glEnable (GL_ALPHA_TEST); 913 } 914 915 916 int SignbitsForPlane (mplane_t *out) 917 { 918 int bits, j; 919 920 // for fast box on planeside test 921 922 bits = 0; 923 for (j=0 ; j<3 ; j++) 924 { 925 if (out->normal[j] < 0) 926 bits |= 1<<j; 927 } 928 return bits; 929 } 930 931 932 void R_SetFrustum (void) 933 { 934 int i; 935 936 if (r_refdef.fov_x == 90) 937 { 938 // front side is visible 939 940 VectorAdd (vpn, vright, frustum[0].normal); 941 VectorSubtract (vpn, vright, frustum[1].normal); 942 943 VectorAdd (vpn, vup, frustum[2].normal); 944 VectorSubtract (vpn, vup, frustum[3].normal); 945 } 946 else 947 { 948 // rotate VPN right by FOV_X/2 degrees 949 RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) ); 950 // rotate VPN left by FOV_X/2 degrees 951 RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 ); 952 // rotate VPN up by FOV_X/2 degrees 953 RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 ); 954 // rotate VPN down by FOV_X/2 degrees 955 RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) ); 956 } 957 958 for (i=0 ; i<4 ; i++) 959 { 960 frustum[i].type = PLANE_ANYZ; 961 frustum[i].dist = DotProduct (r_origin, frustum[i].normal); 962 frustum[i].signbits = SignbitsForPlane (&frustum[i]); 963 } 964 } 965 966 967 968 /* 969 =============== 970 R_SetupFrame 971 =============== 972 */ 973 void R_SetupFrame (void) 974 { 975 int edgecount; 976 vrect_t vrect; 977 float w, h; 978 979 // don't allow cheats in multiplayer 980 if (cl.maxclients > 1) 981 Cvar_Set ("r_fullbright", "0"); 982 983 R_AnimateLight (); 984 985 r_framecount++; 986 987 // build the transformation matrix for the given view angles 988 VectorCopy (r_refdef.vieworg, r_origin); 989 990 AngleVectors (r_refdef.viewangles, vpn, vright, vup); 991 992 // current viewleaf 993 r_oldviewleaf = r_viewleaf; 994 r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); 995 996 V_SetContentsColor (r_viewleaf->contents); 997 V_CalcBlend (); 998 999 r_cache_thrash = false; 1000 1001 c_brush_polys = 0; 1002 c_alias_polys = 0; 1003 1004 } 1005 1006 #ifdef USE_OPENGLES 1007 1008 void MYgluPerspective( float fovy, float aspect, 1009 float zNear, float zFar ) 1010 { 1011 float xmin, xmax, ymin, ymax; 1012 1013 ymax = zNear * tan( fovy * M_PI / 360.0f ); 1014 ymin = -ymax; 1015 1016 xmin = ymin * aspect; 1017 xmax = ymax * aspect; 1018 1019 glFrustumf( xmin, xmax, ymin, ymax, zNear, zFar ); 1020 } 1021 1022 #else 1023 1024 void MYgluPerspective( GLdouble fovy, GLdouble aspect, 1025 GLdouble zNear, GLdouble zFar ) 1026 { 1027 GLdouble xmin, xmax, ymin, ymax; 1028 1029 ymax = zNear * tan( fovy * M_PI / 360.0 ); 1030 ymin = -ymax; 1031 1032 xmin = ymin * aspect; 1033 xmax = ymax * aspect; 1034 1035 glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); 1036 } 1037 #endif 1038 1039 #define DO_OWN_MATRIX_MATH 1040 #ifdef DO_OWN_MATRIX_MATH 1041 // We can't count on being able to read back the model view matrix, so calculate it ourselves. 1042 1043 #define I(_i, _j) ((_j)+ 4*(_i)) 1044 1045 void mulMM(float* r, const float* lhs, const float* rhs) 1046 { 1047 float const* const m = lhs; 1048 for (int i=0 ; i<4 ; i++) { 1049 register const float rhs_i0 = rhs[ I(i,0) ]; 1050 register float ri0 = m[ I(0,0) ] * rhs_i0; 1051 register float ri1 = m[ I(0,1) ] * rhs_i0; 1052 register float ri2 = m[ I(0,2) ] * rhs_i0; 1053 register float ri3 = m[ I(0,3) ] * rhs_i0; 1054 for (int j=1 ; j<4 ; j++) { 1055 register const float rhs_ij = rhs[ I(i,j) ]; 1056 ri0 += m[ I(j,0) ] * rhs_ij; 1057 ri1 += m[ I(j,1) ] * rhs_ij; 1058 ri2 += m[ I(j,2) ] * rhs_ij; 1059 ri3 += m[ I(j,3) ] * rhs_ij; 1060 } 1061 r[ I(i,0) ] = ri0; 1062 r[ I(i,1) ] = ri1; 1063 r[ I(i,2) ] = ri2; 1064 r[ I(i,3) ] = ri3; 1065 } 1066 } 1067 1068 static void setIdentityM(float* sm, int smOffset) { 1069 for (int i=0 ; i<16 ; i++) { 1070 sm[smOffset + i] = 0; 1071 } 1072 for(int i = 0; i < 16; i += 5) { 1073 sm[smOffset + i] = 1.0f; 1074 } 1075 } 1076 1077 static void translateM(float* m, int mOffset, 1078 float x, float y, float z) { 1079 for (int i=0 ; i<4 ; i++) { 1080 int mi = mOffset + i; 1081 m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z; 1082 } 1083 } 1084 1085 static float length(float x, float y, float z) { 1086 return (float) sqrtf(x * x + y * y + z * z); 1087 } 1088 1089 static void setRotateM(float* rm, int rmOffset, 1090 float a, float x, float y, float z) 1091 { 1092 rm[rmOffset + 3] = 0; 1093 rm[rmOffset + 7] = 0; 1094 rm[rmOffset + 11]= 0; 1095 rm[rmOffset + 12]= 0; 1096 rm[rmOffset + 13]= 0; 1097 rm[rmOffset + 14]= 0; 1098 rm[rmOffset + 15]= 1; 1099 a *= (float) (M_PI / 180.0f); 1100 float s = (float) sinf(a); 1101 float c = (float) cosf(a); 1102 if (1.0f == x && 0.0f == y && 0.0f == z) { 1103 rm[rmOffset + 5] = c; rm[rmOffset + 10]= c; 1104 rm[rmOffset + 6] = s; rm[rmOffset + 9] = -s; 1105 rm[rmOffset + 1] = 0; rm[rmOffset + 2] = 0; 1106 rm[rmOffset + 4] = 0; rm[rmOffset + 8] = 0; 1107 rm[rmOffset + 0] = 1; 1108 } else if (0.0f == x && 1.0f == y && 0.0f == z) { 1109 rm[rmOffset + 0] = c; rm[rmOffset + 10]= c; 1110 rm[rmOffset + 8] = s; rm[rmOffset + 2] = -s; 1111 rm[rmOffset + 1] = 0; rm[rmOffset + 4] = 0; 1112 rm[rmOffset + 6] = 0; rm[rmOffset + 9] = 0; 1113 rm[rmOffset + 5] = 1; 1114 } else if (0.0f == x && 0.0f == y && 1.0f == z) { 1115 rm[rmOffset + 0] = c; rm[rmOffset + 5] = c; 1116 rm[rmOffset + 1] = s; rm[rmOffset + 4] = -s; 1117 rm[rmOffset + 2] = 0; rm[rmOffset + 6] = 0; 1118 rm[rmOffset + 8] = 0; rm[rmOffset + 9] = 0; 1119 rm[rmOffset + 10]= 1; 1120 } else { 1121 float len = length(x, y, z); 1122 if (1.0f != len) { 1123 float recipLen = 1.0f / len; 1124 x *= recipLen; 1125 y *= recipLen; 1126 z *= recipLen; 1127 } 1128 float nc = 1.0f - c; 1129 float xy = x * y; 1130 float yz = y * z; 1131 float zx = z * x; 1132 float xs = x * s; 1133 float ys = y * s; 1134 float zs = z * s; 1135 rm[rmOffset + 0] = x*x*nc + c; 1136 rm[rmOffset + 4] = xy*nc - zs; 1137 rm[rmOffset + 8] = zx*nc + ys; 1138 rm[rmOffset + 1] = xy*nc + zs; 1139 rm[rmOffset + 5] = y*y*nc + c; 1140 rm[rmOffset + 9] = yz*nc - xs; 1141 rm[rmOffset + 2] = zx*nc - ys; 1142 rm[rmOffset + 6] = yz*nc + xs; 1143 rm[rmOffset + 10] = z*z*nc + c; 1144 } 1145 } 1146 1147 static void rotateM(float* m, 1148 float a, float x, float y, float z) { 1149 float temp[16]; 1150 float temp2[16]; 1151 setRotateM(temp, 0, a, x, y, z); 1152 mulMM(temp2, m, temp); 1153 memcpy(m, temp2, 16 * sizeof(float)); 1154 } 1155 1156 #undef I 1157 1158 #endif // DO_OWN_MATRIX_MATH 1159 1160 /* 1161 ============= 1162 R_SetupGL 1163 ============= 1164 */ 1165 void R_SetupGL (void) 1166 { 1167 float screenaspect; 1168 float yfov; 1169 int i; 1170 extern int glwidth, glheight; 1171 int x, x2, y2, y, w, h; 1172 1173 // 1174 // set up viewpoint 1175 // 1176 glMatrixMode(GL_PROJECTION); 1177 glLoadIdentity (); 1178 x = r_refdef.vrect.x * glwidth/vid.width; 1179 x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width; 1180 y = (vid.height-r_refdef.vrect.y) * glheight/vid.height; 1181 y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height; 1182 1183 // fudge around because of frac screen scale 1184 if (x > 0) 1185 x--; 1186 if (x2 < glwidth) 1187 x2++; 1188 if (y2 < 0) 1189 y2--; 1190 if (y < glheight) 1191 y++; 1192 1193 w = x2 - x; 1194 h = y - y2; 1195 1196 if (envmap) 1197 { 1198 x = y2 = 0; 1199 w = h = 256; 1200 } 1201 1202 glViewport (glx + x, gly + y2, w, h); 1203 screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; 1204 // yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI; 1205 MYgluPerspective (r_refdef.fov_y, screenaspect, 4, 4096); 1206 1207 if (mirror) 1208 { 1209 if (mirror_plane->normal[2]) 1210 glScalef (1, -1, 1); 1211 else 1212 glScalef (-1, 1, 1); 1213 glCullFace(GL_BACK); 1214 } 1215 else 1216 glCullFace(GL_FRONT); 1217 1218 glMatrixMode(GL_MODELVIEW); 1219 1220 #ifdef DO_OWN_MATRIX_MATH 1221 1222 float mv[16]; 1223 setIdentityM(mv, 0); 1224 1225 rotateM(mv, -90, 1, 0, 0); // put Z going up 1226 rotateM(mv, 90, 0, 0, 1); // put Z going up 1227 rotateM(mv, -r_refdef.viewangles[2], 1, 0, 0); 1228 rotateM(mv, -r_refdef.viewangles[0], 0, 1, 0); 1229 rotateM(mv, -r_refdef.viewangles[1], 0, 0, 1); 1230 translateM(mv, 0, -r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); 1231 1232 glLoadMatrixf(mv); 1233 1234 memcpy(r_world_matrix, mv, sizeof(r_world_matrix)); 1235 1236 #else 1237 glLoadIdentity (); 1238 1239 glRotatef (-90, 1, 0, 0); // put Z going up 1240 glRotatef (90, 0, 0, 1); // put Z going up 1241 glRotatef (-r_refdef.viewangles[2], 1, 0, 0); 1242 glRotatef (-r_refdef.viewangles[0], 0, 1, 0); 1243 glRotatef (-r_refdef.viewangles[1], 0, 0, 1); 1244 glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); 1245 1246 #ifdef USE_OPENGLES 1247 1248 static qboolean initialized; 1249 static qboolean haveGL_OES_matrix_get; 1250 static qboolean haveGL_OES_query_matrix; 1251 1252 #if 0 1253 if (! initialized) { 1254 const char* extensions = (const char*) glGetString(GL_EXTENSIONS); 1255 haveGL_OES_matrix_get = 1256 strstr(extensions, "GL_OES_matrix_get") != NULL; 1257 haveGL_OES_query_matrix = 1258 strstr(extensions, "GL_OES_query_matrix") != NULL; 1259 initialized = true; 1260 } 1261 if (haveGL_OES_query_matrix) { 1262 GLfixed mantissa[16]; 1263 GLint exponent[16]; 1264 glQueryMatrixxOES( mantissa, exponent ); 1265 for(int i = 0; i < 16; i++) { 1266 r_world_matrix[i] = scalbnf(mantissa[i], exponent[i]-16); 1267 } 1268 } 1269 else if (haveGL_OES_matrix_get) { 1270 glGetIntegerv (MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, 1271 (GLint*) r_world_matrix); 1272 } 1273 else 1274 #endif 1275 { 1276 // No way to get the world matix, set to identity 1277 memset(r_world_matrix, 0, sizeof(r_world_matrix)); 1278 for(i = 0; i < 16; i += 5) { 1279 r_world_matrix[i] = 1.0f; 1280 } 1281 } 1282 #else 1283 glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); 1284 #endif 1285 #endif // DO_OWN_MATRIX_MATH 1286 // 1287 // set drawing parms 1288 // 1289 if (gl_cull.value) 1290 glEnable(GL_CULL_FACE); 1291 else 1292 glDisable(GL_CULL_FACE); 1293 1294 glDisable(GL_BLEND); 1295 glDisable(GL_ALPHA_TEST); 1296 glEnable(GL_DEPTH_TEST); 1297 } 1298 1299 /* 1300 ================ 1301 R_RenderScene 1302 1303 r_refdef must be set before the first call 1304 ================ 1305 */ 1306 void R_RenderScene (void) 1307 { 1308 R_SetupFrame (); 1309 1310 R_SetFrustum (); 1311 1312 R_SetupGL (); 1313 1314 R_MarkLeaves (); // done here so we know if we're in water 1315 1316 R_DrawWorld (); // adds static entities to the list 1317 1318 S_ExtraUpdate (); // don't let sound get messed up if going slow 1319 1320 R_DrawEntitiesOnList (); 1321 1322 GL_DisableMultitexture(); 1323 1324 R_RenderDlights (); 1325 1326 R_DrawParticles (); 1327 1328 #ifdef GLTEST 1329 Test_Draw (); 1330 #endif 1331 1332 } 1333 1334 1335 /* 1336 ============= 1337 R_Clear 1338 ============= 1339 */ 1340 void R_Clear (void) 1341 { 1342 if (r_mirroralpha.value != 1.0) 1343 { 1344 if (gl_clear.value) 1345 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1346 else 1347 glClear (GL_DEPTH_BUFFER_BIT); 1348 gldepthmin = 0; 1349 gldepthmax = 0.5; 1350 glDepthFunc (GL_LEQUAL); 1351 } 1352 else if (gl_ztrick.value) 1353 { 1354 static int trickframe; 1355 1356 if (gl_clear.value) 1357 glClear (GL_COLOR_BUFFER_BIT); 1358 1359 trickframe++; 1360 if (trickframe & 1) 1361 { 1362 gldepthmin = 0; 1363 gldepthmax = 0.49999; 1364 glDepthFunc (GL_LEQUAL); 1365 } 1366 else 1367 { 1368 gldepthmin = 1; 1369 gldepthmax = 0.5; 1370 glDepthFunc (GL_GEQUAL); 1371 } 1372 } 1373 else 1374 { 1375 if (gl_clear.value) 1376 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1377 else 1378 glClear (GL_DEPTH_BUFFER_BIT); 1379 gldepthmin = 0; 1380 gldepthmax = 1; 1381 glDepthFunc (GL_LEQUAL); 1382 } 1383 1384 #ifdef USE_OPENGLES 1385 glDepthRangef (gldepthmin, gldepthmax); 1386 #else 1387 glDepthRange (gldepthmin, gldepthmax); 1388 #endif 1389 } 1390 1391 /* 1392 ============= 1393 R_Mirror 1394 ============= 1395 */ 1396 void R_Mirror (void) 1397 { 1398 float d; 1399 msurface_t *s; 1400 entity_t *ent; 1401 1402 if (!mirror) 1403 return; 1404 1405 memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix)); 1406 1407 d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist; 1408 VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg); 1409 1410 d = DotProduct (vpn, mirror_plane->normal); 1411 VectorMA (vpn, -2*d, mirror_plane->normal, vpn); 1412 1413 r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180; 1414 r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180; 1415 r_refdef.viewangles[2] = -r_refdef.viewangles[2]; 1416 1417 ent = &cl_entities[cl.viewentity]; 1418 if (cl_numvisedicts < MAX_VISEDICTS) 1419 { 1420 cl_visedicts[cl_numvisedicts] = ent; 1421 cl_numvisedicts++; 1422 } 1423 1424 gldepthmin = 0.5; 1425 gldepthmax = 1; 1426 #ifdef USE_OPENGLES 1427 glDepthRangef (gldepthmin, gldepthmax); 1428 #else 1429 glDepthRange (gldepthmin, gldepthmax); 1430 #endif 1431 glDepthFunc (GL_LEQUAL); 1432 1433 R_RenderScene (); 1434 R_DrawWaterSurfaces (); 1435 1436 gldepthmin = 0; 1437 gldepthmax = 0.5; 1438 #ifdef USE_OPENGLES 1439 glDepthRangef (gldepthmin, gldepthmax); 1440 #else 1441 glDepthRange (gldepthmin, gldepthmax); 1442 #endif 1443 glDepthFunc (GL_LEQUAL); 1444 1445 // blend on top 1446 glEnable (GL_BLEND); 1447 glMatrixMode(GL_PROJECTION); 1448 if (mirror_plane->normal[2]) 1449 glScalef (1,-1,1); 1450 else 1451 glScalef (-1,1,1); 1452 glCullFace(GL_FRONT); 1453 glMatrixMode(GL_MODELVIEW); 1454 1455 glLoadMatrixf (r_base_world_matrix); 1456 1457 glColor4f (1,1,1,r_mirroralpha.value); 1458 s = cl.worldmodel->textures[mirrortexturenum]->texturechain; 1459 for ( ; s ; s=s->texturechain) 1460 R_RenderBrushPoly (s); 1461 cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL; 1462 glDisable (GL_BLEND); 1463 glColor4f (1,1,1,1); 1464 } 1465 1466 /* 1467 ================ 1468 R_RenderView 1469 1470 r_refdef must be set before the first call 1471 ================ 1472 */ 1473 void R_RenderView (void) 1474 { 1475 double time1 = 0.0; 1476 double time2; 1477 GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20}; 1478 1479 if (r_norefresh.value) 1480 return; 1481 1482 if (!r_worldentity.model || !cl.worldmodel) 1483 Sys_Error ("R_RenderView: NULL worldmodel"); 1484 1485 if (r_speeds.value) 1486 { 1487 glFinish (); 1488 time1 = Sys_FloatTime (); 1489 c_brush_polys = 0; 1490 c_alias_polys = 0; 1491 } 1492 1493 mirror = false; 1494 1495 if (gl_finish.value) 1496 glFinish (); 1497 1498 R_Clear (); 1499 1500 // render normal view 1501 1502 /***** Experimental silly looking fog ****** 1503 ****** Use r_fullbright if you enable ****** 1504 glFogi(GL_FOG_MODE, GL_LINEAR); 1505 glFogfv(GL_FOG_COLOR, colors); 1506 glFogf(GL_FOG_END, 512.0); 1507 glEnable(GL_FOG); 1508 ********************************************/ 1509 1510 R_RenderScene (); 1511 R_DrawViewModel (); 1512 R_DrawWaterSurfaces (); 1513 1514 // More fog right here :) 1515 // glDisable(GL_FOG); 1516 // End of all fog code... 1517 1518 // render mirror view 1519 R_Mirror (); 1520 1521 R_PolyBlend (); 1522 1523 if (r_speeds.value) 1524 { 1525 // glFinish (); 1526 time2 = Sys_FloatTime (); 1527 Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); 1528 } 1529 } 1530