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// r_main.c 21 22#include "quakedef.h" 23 24entity_t r_worldentity; 25 26qboolean r_cache_thrash; // compatability 27 28vec3_t modelorg, r_entorigin; 29entity_t *currententity; 30 31int r_visframecount; // bumped when going to a new PVS 32int r_framecount; // used for dlight push checking 33 34mplane_t frustum[4]; 35 36int c_brush_polys, c_alias_polys; 37 38qboolean envmap; // true during envmap command capture 39 40int currenttexture = -1; // to avoid unnecessary texture sets 41 42int cnttextures[2] = {-1, -1}; // cached 43 44int particletexture; // little dot for particles 45int playertextures; // up to 16 color translated skins 46 47int mirrortexturenum; // quake texturenum, not gltexturenum 48qboolean mirror; 49mplane_t *mirror_plane; 50 51// 52// view origin 53// 54vec3_t vup; 55vec3_t vpn; 56vec3_t vright; 57vec3_t r_origin; 58 59float r_world_matrix[16]; 60float r_base_world_matrix[16]; 61 62// 63// screen size info 64// 65refdef_t r_refdef; 66 67mleaf_t *r_viewleaf, *r_oldviewleaf; 68 69texture_t *r_notexture_mip; 70 71int d_lightstylevalue[256]; // 8.8 fraction of base light value 72 73 74void R_MarkLeaves (void); 75 76cvar_t r_norefresh = CVAR2("r_norefresh","0"); 77cvar_t r_drawentities = CVAR2("r_drawentities","1"); 78cvar_t r_drawviewmodel = CVAR2("r_drawviewmodel","1"); 79cvar_t r_speeds = CVAR2("r_speeds","0"); 80cvar_t r_fullbright = CVAR2("r_fullbright","0"); 81cvar_t r_lightmap = CVAR2("r_lightmap","0"); 82cvar_t r_shadows = CVAR2("r_shadows","0"); 83cvar_t r_mirroralpha = CVAR2("r_mirroralpha","1"); 84cvar_t r_wateralpha = CVAR2("r_wateralpha","1"); 85cvar_t r_dynamic = CVAR2("r_dynamic","1"); 86cvar_t r_novis = CVAR2("r_novis","0"); 87cvar_t r_netgraph = CVAR2("r_netgraph","0"); 88 89cvar_t gl_clear = CVAR2("gl_clear","0"); 90cvar_t gl_cull = CVAR2("gl_cull","1"); 91cvar_t gl_texsort = CVAR2("gl_texsort","1"); 92cvar_t gl_smoothmodels = CVAR2("gl_smoothmodels","1"); 93cvar_t gl_affinemodels = CVAR2("gl_affinemodels","0"); 94cvar_t gl_polyblend = CVAR2("gl_polyblend","1"); 95cvar_t gl_flashblend = CVAR2("gl_flashblend","1"); 96cvar_t gl_playermip = CVAR2("gl_playermip","0"); 97cvar_t gl_nocolors = CVAR2("gl_nocolors","0"); 98cvar_t gl_keeptjunctions = CVAR2("gl_keeptjunctions","1"); 99cvar_t gl_reporttjunctions = CVAR2("gl_reporttjunctions","0"); 100cvar_t gl_finish = CVAR2("gl_finish","0"); 101 102extern cvar_t gl_ztrick; 103extern cvar_t scr_fov; 104/* 105================= 106R_CullBox 107 108Returns true if the box is completely outside the frustom 109================= 110*/ 111qboolean 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 122void 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 //ZOID: fixed z angle 129 glRotatef (e->angles[2], 1, 0, 0); 130} 131 132/* 133============================================================= 134 135 SPRITE MODELS 136 137============================================================= 138*/ 139 140/* 141================ 142R_GetSpriteFrame 143================ 144*/ 145mspriteframe_t *R_GetSpriteFrame (entity_t *currententity) 146{ 147 msprite_t *psprite; 148 mspritegroup_t *pspritegroup; 149 mspriteframe_t *pspriteframe; 150 int i, numframes, frame; 151 float *pintervals, fullinterval, targettime, time; 152 153 psprite = currententity->model->cache.data; 154 frame = currententity->frame; 155 156 if ((frame >= psprite->numframes) || (frame < 0)) 157 { 158 Con_Printf ("R_DrawSprite: no such frame %d\n", frame); 159 frame = 0; 160 } 161 162 if (psprite->frames[frame].type == SPR_SINGLE) 163 { 164 pspriteframe = psprite->frames[frame].frameptr; 165 } 166 else 167 { 168 pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; 169 pintervals = pspritegroup->intervals; 170 numframes = pspritegroup->numframes; 171 fullinterval = pintervals[numframes-1]; 172 173 time = cl.time + currententity->syncbase; 174 175 // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values 176 // are positive, so we don't have to worry about division by 0 177 targettime = time - ((int)(time / fullinterval)) * fullinterval; 178 179 for (i=0 ; i<(numframes-1) ; i++) 180 { 181 if (pintervals[i] > targettime) 182 break; 183 } 184 185 pspriteframe = pspritegroup->frames[i]; 186 } 187 188 return pspriteframe; 189} 190 191 192/* 193================= 194R_DrawSpriteModel 195 196================= 197*/ 198void R_DrawSpriteModel (entity_t *e) 199{ 200 vec3_t point; 201 mspriteframe_t *frame; 202 float *up, *right; 203 vec3_t v_forward, v_right, v_up; 204 msprite_t *psprite; 205 206 // don't even bother culling, because it's just a single 207 // polygon without a surface cache 208 frame = R_GetSpriteFrame (e); 209 psprite = currententity->model->cache.data; 210 211 if (psprite->type == SPR_ORIENTED) 212 { // bullet marks on walls 213 AngleVectors (currententity->angles, v_forward, v_right, v_up); 214 up = v_up; 215 right = v_right; 216 } 217 else 218 { // normal sprite 219 up = vup; 220 right = vright; 221 } 222 223 glColor3f (1,1,1); 224 225 GL_DisableMultitexture(); 226 227 GL_Bind(frame->gl_texturenum); 228 229 glEnable (GL_ALPHA_TEST); 230 231#ifdef USE_OPENGLES 232 // !!! Need to implement this !!! 233 234#else 235 glBegin (GL_QUADS); 236 237 glTexCoord2f (0, 1); 238 VectorMA (e->origin, frame->down, up, point); 239 VectorMA (point, frame->left, right, point); 240 glVertex3fv (point); 241 242 glTexCoord2f (0, 0); 243 VectorMA (e->origin, frame->up, up, point); 244 VectorMA (point, frame->left, right, point); 245 glVertex3fv (point); 246 247 glTexCoord2f (1, 0); 248 VectorMA (e->origin, frame->up, up, point); 249 VectorMA (point, frame->right, right, point); 250 glVertex3fv (point); 251 252 glTexCoord2f (1, 1); 253 VectorMA (e->origin, frame->down, up, point); 254 VectorMA (point, frame->right, right, point); 255 glVertex3fv (point); 256 257 glEnd (); 258#endif 259 260 glDisable (GL_ALPHA_TEST); 261} 262 263/* 264============================================================= 265 266 ALIAS MODELS 267 268============================================================= 269*/ 270 271 272#define NUMVERTEXNORMALS 162 273 274float r_avertexnormals[NUMVERTEXNORMALS][3] = { 275#include "anorms.h" 276}; 277 278vec3_t shadevector; 279float shadelight, ambientlight; 280 281// precalculated dot products for quantized angles 282#define SHADEDOT_QUANT 16 283float r_avertexnormal_dots[SHADEDOT_QUANT][256] = 284#include "anorm_dots.h" 285; 286 287float *shadedots = r_avertexnormal_dots[0]; 288 289int lastposenum; 290 291/* 292============= 293GL_DrawAliasFrame 294============= 295*/ 296void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum) 297{ 298 float l; 299 trivertx_t *verts; 300 int *order; 301 int count; 302 303lastposenum = posenum; 304 305 verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); 306 verts += posenum * paliashdr->poseverts; 307 order = (int *)((byte *)paliashdr + paliashdr->commands); 308 309 while (1) 310 { 311 // get the vertex count and primitive type 312 count = *order++; 313 if (!count) 314 break; // done 315 316#ifdef USE_OPENGLES 317 { 318 int primType; 319 float color[3*256]; 320 float vertex[3*256]; 321 int c; 322 float* pColor; 323 float* pVertex; 324 325 if (count < 0) 326 { 327 count = -count; 328 primType = GL_TRIANGLE_FAN; 329 } 330 else 331 primType = GL_TRIANGLE_STRIP; 332 333 // texture coordinates come from the draw list 334 glTexCoordPointer(2, GL_FLOAT, 0, order); 335 336 pColor = color; 337 pVertex = vertex; 338 for(c = 0; c < count; c++) 339 { 340 // normals and vertexes come from the frame list 341 l = shadedots[verts->lightnormalindex] * shadelight; 342 *pColor++ = l; 343 *pColor++ = l; 344 *pColor++ = l; 345 *pVertex++ = verts->v[0]; 346 *pVertex++ = verts->v[1]; 347 *pVertex++ = verts->v[2]; 348 verts++; 349 } 350 351 glColorPointer(3, GL_FLOAT, 0, color); 352 glVertexPointer(3, GL_FLOAT, 0, vertex); 353 354 glDrawArrays(primType, 0, count); 355 356 order += 2 * count; 357 } 358 359#else 360 if (count < 0) 361 { 362 count = -count; 363 glBegin (GL_TRIANGLE_FAN); 364 } 365 else 366 glBegin (GL_TRIANGLE_STRIP); 367 368 do 369 { 370 // texture coordinates come from the draw list 371 glTexCoord2f (((float *)order)[0], ((float *)order)[1]); 372 order += 2; 373 374 // normals and vertexes come from the frame list 375 l = shadedots[verts->lightnormalindex] * shadelight; 376 glColor3f (l, l, l); 377 glVertex3f (verts->v[0], verts->v[1], verts->v[2]); 378 verts++; 379 } while (--count); 380 381 glEnd (); 382#endif 383 } 384} 385 386 387/* 388============= 389GL_DrawAliasShadow 390============= 391*/ 392extern vec3_t lightspot; 393 394void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) 395{ 396 trivertx_t *verts; 397 int *order; 398 vec3_t point; 399 float height, lheight; 400 int count; 401 402 lheight = currententity->origin[2] - lightspot[2]; 403 404 height = 0; 405 verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); 406 verts += posenum * paliashdr->poseverts; 407 order = (int *)((byte *)paliashdr + paliashdr->commands); 408 409 height = -lheight + 1.0; 410 411 while (1) 412 { 413 // get the vertex count and primitive type 414 count = *order++; 415 if (!count) 416 break; // done 417 418#ifdef USE_OPENGLES 419 420 // !!! Implement this (based on GL_DrawAlias) 421 break; 422#else 423 424 if (count < 0) 425 { 426 count = -count; 427 glBegin (GL_TRIANGLE_FAN); 428 } 429 else 430 glBegin (GL_TRIANGLE_STRIP); 431 432 do 433 { 434 // texture coordinates come from the draw list 435 // (skipped for shadows) glTexCoord2fv ((float *)order); 436 order += 2; 437 438 // normals and vertexes come from the frame list 439 point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0]; 440 point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1]; 441 point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]; 442 443 point[0] -= shadevector[0]*(point[2]+lheight); 444 point[1] -= shadevector[1]*(point[2]+lheight); 445 point[2] = height; 446// height -= 0.001; 447 glVertex3fv (point); 448 449 verts++; 450 } while (--count); 451 452 glEnd (); 453 454#endif 455 456 } 457} 458 459 460 461/* 462================= 463R_SetupAliasFrame 464 465================= 466*/ 467void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr) 468{ 469 int pose, numposes; 470 float interval; 471 472 if ((frame >= paliashdr->numframes) || (frame < 0)) 473 { 474 Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); 475 frame = 0; 476 } 477 478 pose = paliashdr->frames[frame].firstpose; 479 numposes = paliashdr->frames[frame].numposes; 480 481 if (numposes > 1) 482 { 483 interval = paliashdr->frames[frame].interval; 484 pose += (int)(cl.time / interval) % numposes; 485 } 486 487 GL_DrawAliasFrame (paliashdr, pose); 488} 489 490 491 492/* 493================= 494R_DrawAliasModel 495 496================= 497*/ 498void R_DrawAliasModel (entity_t *e) 499{ 500 int i; 501 int lnum; 502 vec3_t dist; 503 float add; 504 model_t *clmodel; 505 vec3_t mins, maxs; 506 aliashdr_t *paliashdr; 507 float an; 508 int anim; 509 510 clmodel = currententity->model; 511 512 VectorAdd (currententity->origin, clmodel->mins, mins); 513 VectorAdd (currententity->origin, clmodel->maxs, maxs); 514 515 if (R_CullBox (mins, maxs)) 516 return; 517 518 519 VectorCopy (currententity->origin, r_entorigin); 520 VectorSubtract (r_origin, r_entorigin, modelorg); 521 522 // 523 // get lighting information 524 // 525 526 ambientlight = shadelight = R_LightPoint (currententity->origin); 527 528 // allways give the gun some light 529 if (e == &cl.viewent && ambientlight < 24) 530 ambientlight = shadelight = 24; 531 532 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 533 { 534 if (cl_dlights[lnum].die >= cl.time) 535 { 536 VectorSubtract (currententity->origin, 537 cl_dlights[lnum].origin, 538 dist); 539 add = cl_dlights[lnum].radius - Length(dist); 540 541 if (add > 0) { 542 ambientlight += add; 543 //ZOID models should be affected by dlights as well 544 shadelight += add; 545 } 546 } 547 } 548 549 // clamp lighting so it doesn't overbright as much 550 if (ambientlight > 128) 551 ambientlight = 128; 552 if (ambientlight + shadelight > 192) 553 shadelight = 192 - ambientlight; 554 555 // ZOID: never allow players to go totally black 556 if (!strcmp(clmodel->name, "progs/player.mdl")) { 557 if (ambientlight < 8) 558 ambientlight = shadelight = 8; 559 560 } else if (!strcmp (clmodel->name, "progs/flame2.mdl") 561 || !strcmp (clmodel->name, "progs/flame.mdl") ) 562 // HACK HACK HACK -- no fullbright colors, so make torches full light 563 ambientlight = shadelight = 256; 564 565 shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; 566 shadelight = shadelight / 200.0; 567 568 an = e->angles[1]/180*M_PI; 569 shadevector[0] = cos(-an); 570 shadevector[1] = sin(-an); 571 shadevector[2] = 1; 572 VectorNormalize (shadevector); 573 574 // 575 // locate the proper data 576 // 577 paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); 578 579 c_alias_polys += paliashdr->numtris; 580 581 // 582 // draw all the triangles 583 // 584 585 GL_DisableMultitexture(); 586 587 glPushMatrix (); 588 R_RotateForEntity (e); 589 590 if (!strcmp (clmodel->name, "progs/eyes.mdl") ) { 591 glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); 592 // double size of eyes, since they are really hard to see in gl 593 glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); 594 } else { 595 glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); 596 glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); 597 } 598 599 anim = (int)(cl.time*10) & 3; 600 GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); 601 602 // we can't dynamically colormap textures, so they are cached 603 // seperately for the players. Heads are just uncolored. 604 if (currententity->scoreboard && !gl_nocolors.value) 605 { 606 i = currententity->scoreboard - cl.players; 607 if (!currententity->scoreboard->skin) { 608 Skin_Find(currententity->scoreboard); 609 R_TranslatePlayerSkin(i); 610 } 611 if (i >= 0 && i<MAX_CLIENTS) 612 GL_Bind(playertextures + i); 613 } 614 615 if (gl_smoothmodels.value) 616 glShadeModel (GL_SMOOTH); 617 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 618 619 if (gl_affinemodels.value) 620 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); 621 622 R_SetupAliasFrame (currententity->frame, paliashdr); 623 624 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 625 626 glShadeModel (GL_FLAT); 627 if (gl_affinemodels.value) 628 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 629 630 glPopMatrix (); 631 632 if (r_shadows.value) 633 { 634 glPushMatrix (); 635 R_RotateForEntity (e); 636 glDisable (GL_TEXTURE_2D); 637 glEnable (GL_BLEND); 638 glColor4f (0,0,0,0.5); 639 GL_DrawAliasShadow (paliashdr, lastposenum); 640 glEnable (GL_TEXTURE_2D); 641 glDisable (GL_BLEND); 642 glColor4f (1,1,1,1); 643 glPopMatrix (); 644 } 645 646} 647 648//================================================================================== 649 650/* 651============= 652R_DrawEntitiesOnList 653============= 654*/ 655void R_DrawEntitiesOnList (void) 656{ 657 int i; 658 659 if (!r_drawentities.value) 660 return; 661 662 // draw sprites seperately, because of alpha blending 663 for (i=0 ; i<cl_numvisedicts ; i++) 664 { 665 currententity = &cl_visedicts[i]; 666 667 switch (currententity->model->type) 668 { 669 case mod_alias: 670 R_DrawAliasModel (currententity); 671 break; 672 673 case mod_brush: 674 R_DrawBrushModel (currententity); 675 break; 676 677 default: 678 break; 679 } 680 } 681 682 for (i=0 ; i<cl_numvisedicts ; i++) 683 { 684 currententity = &cl_visedicts[i]; 685 686 switch (currententity->model->type) 687 { 688 case mod_sprite: 689 R_DrawSpriteModel (currententity); 690 break; 691 692 default : 693 break; 694 } 695 } 696} 697 698/* 699============= 700R_DrawViewModel 701============= 702*/ 703void R_DrawViewModel (void) 704{ 705 float ambient[4], diffuse[4]; 706 int j; 707 int lnum; 708 vec3_t dist; 709 float add; 710 dlight_t *dl; 711 int ambientlight, shadelight; 712 713 if (!r_drawviewmodel.value || !Cam_DrawViewModel()) 714 return; 715 716 if (envmap) 717 return; 718 719 if (!r_drawentities.value) 720 return; 721 722 if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) 723 return; 724 725 if (cl.stats[STAT_HEALTH] <= 0) 726 return; 727 728 currententity = &cl.viewent; 729 if (!currententity->model) 730 return; 731 732 j = R_LightPoint (currententity->origin); 733 734 if (j < 24) 735 j = 24; // allways give some light on gun 736 ambientlight = j; 737 shadelight = j; 738 739// add dynamic lights 740 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 741 { 742 dl = &cl_dlights[lnum]; 743 if (!dl->radius) 744 continue; 745 if (!dl->radius) 746 continue; 747 if (dl->die < cl.time) 748 continue; 749 750 VectorSubtract (currententity->origin, dl->origin, dist); 751 add = dl->radius - Length(dist); 752 if (add > 0) 753 ambientlight += add; 754 } 755 756 ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128; 757 diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128; 758 759 // hack the depth range to prevent view model from poking into walls 760#ifdef USE_OPENGLES 761 glDepthRangef(gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin)); 762 R_DrawAliasModel (currententity); 763 glDepthRangef(gldepthmin, gldepthmax); 764#else 765 glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); 766 R_DrawAliasModel (currententity); 767 glDepthRange (gldepthmin, gldepthmax); 768#endif 769} 770 771 772/* 773============ 774R_PolyBlend 775============ 776*/ 777void R_PolyBlend (void) 778{ 779 if (!gl_polyblend.value) 780 return; 781 if (!v_blend[3]) 782 return; 783 784//Con_Printf("R_PolyBlend(): %4.2f %4.2f %4.2f %4.2f\n",v_blend[0], v_blend[1], v_blend[2], v_blend[3]); 785 786 GL_DisableMultitexture(); 787 788 glDisable (GL_ALPHA_TEST); 789 glEnable (GL_BLEND); 790 glDisable (GL_DEPTH_TEST); 791 glDisable (GL_TEXTURE_2D); 792 793 glLoadIdentity (); 794 795 glRotatef (-90, 1, 0, 0); // put Z going up 796 glRotatef (90, 0, 0, 1); // put Z going up 797 798 glColor4fv (v_blend); 799 800#ifdef USE_OPENGLES 801 // !!! Implement this 802#else 803 glBegin (GL_QUADS); 804 805 glVertex3f (10, 100, 100); 806 glVertex3f (10, -100, 100); 807 glVertex3f (10, -100, -100); 808 glVertex3f (10, 100, -100); 809 glEnd (); 810#endif 811 812 glDisable (GL_BLEND); 813 glEnable (GL_TEXTURE_2D); 814 glEnable (GL_ALPHA_TEST); 815} 816 817 818int SignbitsForPlane (mplane_t *out) 819{ 820 int bits, j; 821 822 // for fast box on planeside test 823 824 bits = 0; 825 for (j=0 ; j<3 ; j++) 826 { 827 if (out->normal[j] < 0) 828 bits |= 1<<j; 829 } 830 return bits; 831} 832 833 834void R_SetFrustum (void) 835{ 836 int i; 837 838 if (r_refdef.fov_x == 90) 839 { 840 // front side is visible 841 842 VectorAdd (vpn, vright, frustum[0].normal); 843 VectorSubtract (vpn, vright, frustum[1].normal); 844 845 VectorAdd (vpn, vup, frustum[2].normal); 846 VectorSubtract (vpn, vup, frustum[3].normal); 847 } 848 else 849 { 850 851 // rotate VPN right by FOV_X/2 degrees 852 RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) ); 853 // rotate VPN left by FOV_X/2 degrees 854 RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 ); 855 // rotate VPN up by FOV_X/2 degrees 856 RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 ); 857 // rotate VPN down by FOV_X/2 degrees 858 RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) ); 859 } 860 861 for (i=0 ; i<4 ; i++) 862 { 863 frustum[i].type = PLANE_ANYZ; 864 frustum[i].dist = DotProduct (r_origin, frustum[i].normal); 865 frustum[i].signbits = SignbitsForPlane (&frustum[i]); 866 } 867} 868 869 870 871/* 872=============== 873R_SetupFrame 874=============== 875*/ 876void R_SetupFrame (void) 877{ 878// don't allow cheats in multiplayer 879 r_fullbright.value = 0; 880 r_lightmap.value = 0; 881 if (!atoi(Info_ValueForKey(cl.serverinfo, "watervis"))) 882 r_wateralpha.value = 1; 883 884 R_AnimateLight (); 885 886 r_framecount++; 887 888// build the transformation matrix for the given view angles 889 VectorCopy (r_refdef.vieworg, r_origin); 890 891 AngleVectors (r_refdef.viewangles, vpn, vright, vup); 892 893// current viewleaf 894 r_oldviewleaf = r_viewleaf; 895 r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); 896 897 V_SetContentsColor (r_viewleaf->contents); 898 V_CalcBlend (); 899 900 r_cache_thrash = false; 901 902 c_brush_polys = 0; 903 c_alias_polys = 0; 904 905} 906 907#ifdef USE_OPENGLES 908 909void MYgluPerspective( float fovy, float aspect, 910 float zNear, float zFar ) 911{ 912 float xmin, xmax, ymin, ymax; 913 914 ymax = zNear * tan( fovy * M_PI / 360.0f ); 915 ymin = -ymax; 916 917 xmin = ymin * aspect; 918 xmax = ymax * aspect; 919 920 glFrustumf( xmin, xmax, ymin, ymax, zNear, zFar ); 921} 922 923#else 924 925void MYgluPerspective( GLdouble fovy, GLdouble aspect, 926 GLdouble zNear, GLdouble zFar ) 927{ 928 GLdouble xmin, xmax, ymin, ymax; 929 930 ymax = zNear * tan( fovy * M_PI / 360.0 ); 931 ymin = -ymax; 932 933 xmin = ymin * aspect; 934 xmax = ymax * aspect; 935 936 glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); 937} 938#endif 939 940/* 941============= 942R_SetupGL 943============= 944*/ 945void R_SetupGL (void) 946{ 947 float screenaspect; 948 extern int glwidth, glheight; 949 int x, x2, y2, y, w, h; 950 951 // 952 // set up viewpoint 953 // 954 glMatrixMode(GL_PROJECTION); 955 glLoadIdentity (); 956 x = r_refdef.vrect.x * glwidth/vid.width; 957 x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width; 958 y = (vid.height-r_refdef.vrect.y) * glheight/vid.height; 959 y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height; 960 961 // fudge around because of frac screen scale 962 if (x > 0) 963 x--; 964 if (x2 < glwidth) 965 x2++; 966 if (y2 < 0) 967 y2--; 968 if (y < glheight) 969 y++; 970 971 w = x2 - x; 972 h = y - y2; 973 974 if (envmap) 975 { 976 x = y2 = 0; 977 w = h = 256; 978 } 979 980 glViewport (glx + x, gly + y2, w, h); 981 screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; 982// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI; 983// yfov = (2.0 * tan (scr_fov.value/360*M_PI)) / screenaspect; 984// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*(scr_fov.value*2)/M_PI; 985// MYgluPerspective (yfov, screenaspect, 4, 4096); 986 MYgluPerspective (r_refdef.fov_y, screenaspect, 4, 4096); 987 988 if (mirror) 989 { 990 if (mirror_plane->normal[2]) 991 glScalef (1, -1, 1); 992 else 993 glScalef (-1, 1, 1); 994 glCullFace(GL_BACK); 995 } 996 else 997 glCullFace(GL_FRONT); 998 999 glMatrixMode(GL_MODELVIEW); 1000 glLoadIdentity (); 1001 1002 glRotatef (-90, 1, 0, 0); // put Z going up 1003 glRotatef (90, 0, 0, 1); // put Z going up 1004 glRotatef (-r_refdef.viewangles[2], 1, 0, 0); 1005 glRotatef (-r_refdef.viewangles[0], 0, 1, 0); 1006 glRotatef (-r_refdef.viewangles[1], 0, 0, 1); 1007 glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); 1008 1009#ifdef USE_OPENGLES 1010 glGetIntegerv (MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, (GLint*) r_world_matrix); 1011#else 1012 glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); 1013#endif 1014 1015 // 1016 // set drawing parms 1017 // 1018 if (gl_cull.value) 1019 glEnable(GL_CULL_FACE); 1020 else 1021 glDisable(GL_CULL_FACE); 1022 1023 glDisable(GL_BLEND); 1024 glDisable(GL_ALPHA_TEST); 1025 glEnable(GL_DEPTH_TEST); 1026} 1027 1028/* 1029================ 1030R_RenderScene 1031 1032r_refdef must be set before the first call 1033================ 1034*/ 1035void R_RenderScene (void) 1036{ 1037 R_SetupFrame (); 1038 1039 R_SetFrustum (); 1040 1041 R_SetupGL (); 1042 1043 R_MarkLeaves (); // done here so we know if we're in water 1044 1045 R_DrawWorld (); // adds static entities to the list 1046 1047 S_ExtraUpdate (); // don't let sound get messed up if going slow 1048 1049 R_DrawEntitiesOnList (); 1050 1051 GL_DisableMultitexture(); 1052 1053 R_RenderDlights (); 1054 1055 R_DrawParticles (); 1056 1057#ifdef GLTEST 1058 Test_Draw (); 1059#endif 1060 1061} 1062 1063 1064/* 1065============= 1066R_Clear 1067============= 1068*/ 1069void R_Clear (void) 1070{ 1071 if (r_mirroralpha.value != 1.0) 1072 { 1073 if (gl_clear.value) 1074 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1075 else 1076 glClear (GL_DEPTH_BUFFER_BIT); 1077 gldepthmin = 0; 1078 gldepthmax = 0.5; 1079 glDepthFunc (GL_LEQUAL); 1080 } 1081 else if (gl_ztrick.value) 1082 { 1083 static int trickframe; 1084 1085 if (gl_clear.value) 1086 glClear (GL_COLOR_BUFFER_BIT); 1087 1088 trickframe++; 1089 if (trickframe & 1) 1090 { 1091 gldepthmin = 0; 1092 gldepthmax = 0.49999; 1093 glDepthFunc (GL_LEQUAL); 1094 } 1095 else 1096 { 1097 gldepthmin = 1; 1098 gldepthmax = 0.5; 1099 glDepthFunc (GL_GEQUAL); 1100 } 1101 } 1102 else 1103 { 1104 if (gl_clear.value) 1105 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1106 else 1107 glClear (GL_DEPTH_BUFFER_BIT); 1108 gldepthmin = 0; 1109 gldepthmax = 1; 1110 glDepthFunc (GL_LEQUAL); 1111 } 1112 1113#ifdef USE_OPENGLES 1114 glDepthRangef (gldepthmin, gldepthmax); 1115#else 1116 glDepthRange (gldepthmin, gldepthmax); 1117#endif 1118} 1119 1120#if 0 //!!! FIXME, Zoid, mirror is disabled for now 1121/* 1122============= 1123R_Mirror 1124============= 1125*/ 1126void R_Mirror (void) 1127{ 1128 float d; 1129 msurface_t *s; 1130 entity_t *ent; 1131 1132 if (!mirror) 1133 return; 1134 1135 memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix)); 1136 1137 d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist; 1138 VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg); 1139 1140 d = DotProduct (vpn, mirror_plane->normal); 1141 VectorMA (vpn, -2*d, mirror_plane->normal, vpn); 1142 1143 r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180; 1144 r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180; 1145 r_refdef.viewangles[2] = -r_refdef.viewangles[2]; 1146 1147 ent = &cl_entities[cl.viewentity]; 1148 if (cl_numvisedicts < MAX_VISEDICTS) 1149 { 1150 cl_visedicts[cl_numvisedicts] = ent; 1151 cl_numvisedicts++; 1152 } 1153 1154 gldepthmin = 0.5; 1155 gldepthmax = 1; 1156 glDepthRange (gldepthmin, gldepthmax); 1157 glDepthFunc (GL_LEQUAL); 1158 1159 R_RenderScene (); 1160 R_DrawWaterSurfaces (); 1161 1162 1163 gldepthmin = 0; 1164 gldepthmax = 0.5; 1165 glDepthRange (gldepthmin, gldepthmax); 1166 glDepthFunc (GL_LEQUAL); 1167 1168 // blend on top 1169 glEnable (GL_BLEND); 1170 glMatrixMode(GL_PROJECTION); 1171 if (mirror_plane->normal[2]) 1172 glScalef (1,-1,1); 1173 else 1174 glScalef (-1,1,1); 1175 glCullFace(GL_FRONT); 1176 glMatrixMode(GL_MODELVIEW); 1177 1178 glLoadMatrixf (r_base_world_matrix); 1179 1180 glColor4f (1,1,1,r_mirroralpha.value); 1181 s = cl.worldmodel->textures[mirrortexturenum]->texturechain; 1182 for ( ; s ; s=s->texturechain) 1183 R_RenderBrushPoly (s); 1184 cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL; 1185 glDisable (GL_BLEND); 1186 glColor4f (1,1,1,1); 1187} 1188#endif 1189 1190/* 1191================ 1192R_RenderView 1193 1194r_refdef must be set before the first call 1195================ 1196*/ 1197void R_RenderView (void) 1198{ 1199 double time1 = 0, time2; 1200 1201 if (r_norefresh.value) 1202 return; 1203 1204 if (!r_worldentity.model || !cl.worldmodel) 1205 Sys_Error ("R_RenderView: NULL worldmodel"); 1206 1207 if (r_speeds.value) 1208 { 1209 glFinish (); 1210 time1 = Sys_DoubleTime (); 1211 c_brush_polys = 0; 1212 c_alias_polys = 0; 1213 } 1214 1215 mirror = false; 1216 1217 if (gl_finish.value) 1218 glFinish (); 1219 1220 R_Clear (); 1221 1222 // render normal view 1223 R_RenderScene (); 1224 R_DrawViewModel (); 1225 R_DrawWaterSurfaces (); 1226 1227 // render mirror view 1228// R_Mirror (); 1229 1230 R_PolyBlend (); 1231 1232 if (r_speeds.value) 1233 { 1234// glFinish (); 1235 time2 = Sys_DoubleTime (); 1236 Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); 1237 } 1238} 1239