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#include "r_local.h" 24 25//define PASSAGES 26 27void *colormap; 28vec3_t viewlightvec; 29alight_t r_viewlighting = {128, 192, viewlightvec}; 30float r_time1; 31int r_numallocatededges; 32qboolean r_drawpolys; 33qboolean r_drawculledpolys; 34qboolean r_worldpolysbacktofront; 35qboolean r_recursiveaffinetriangles = true; 36int r_pixbytes = 1; 37float r_aliasuvscale = 1.0; 38int r_outofsurfaces; 39int r_outofedges; 40 41qboolean r_dowarp, r_dowarpold, r_viewchanged; 42 43int numbtofpolys; 44btofpoly_t *pbtofpolys; 45mvertex_t *r_pcurrentvertbase; 46 47int c_surf; 48int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; 49qboolean r_surfsonstack; 50int r_clipflags; 51 52byte *r_warpbuffer; 53 54byte *r_stack_start; 55 56qboolean r_fov_greater_than_90; 57 58entity_t r_worldentity; 59 60// 61// view origin 62// 63vec3_t vup, base_vup; 64vec3_t vpn, base_vpn; 65vec3_t vright, base_vright; 66vec3_t r_origin; 67 68// 69// screen size info 70// 71refdef_t r_refdef; 72float xcenter, ycenter; 73float xscale, yscale; 74float xscaleinv, yscaleinv; 75float xscaleshrink, yscaleshrink; 76float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; 77 78int screenwidth; 79 80float pixelAspect; 81float screenAspect; 82float verticalFieldOfView; 83float xOrigin, yOrigin; 84 85mplane_t screenedge[4]; 86 87// 88// refresh flags 89// 90int r_framecount = 1; // so frame counts initialized to 0 don't match 91int r_visframecount; 92int d_spanpixcount; 93int r_polycount; 94int r_drawnpolycount; 95int r_wholepolycount; 96 97int *pfrustum_indexes[4]; 98int r_frustum_indexes[4*6]; 99 100int reinit_surfcache = 1; // if 1, surface cache is currently empty and 101 // must be reinitialized for current cache size 102 103mleaf_t *r_viewleaf, *r_oldviewleaf; 104 105texture_t *r_notexture_mip; 106 107float r_aliastransition, r_resfudge; 108 109int d_lightstylevalue[256]; // 8.8 fraction of base light value 110 111float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; 112float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2; 113 114void R_MarkLeaves (void); 115 116cvar_t r_draworder = {"r_draworder","0"}; 117cvar_t r_speeds = {"r_speeds","0"}; 118cvar_t r_timegraph = {"r_timegraph","0"}; 119cvar_t r_netgraph = {"r_netgraph","0"}; 120cvar_t r_zgraph = {"r_zgraph","0"}; 121cvar_t r_graphheight = {"r_graphheight","15"}; 122cvar_t r_clearcolor = {"r_clearcolor","2"}; 123cvar_t r_waterwarp = {"r_waterwarp","1"}; 124cvar_t r_fullbright = {"r_fullbright","0"}; 125cvar_t r_drawentities = {"r_drawentities","1"}; 126cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; 127cvar_t r_aliasstats = {"r_polymodelstats","0"}; 128cvar_t r_dspeeds = {"r_dspeeds","0"}; 129cvar_t r_drawflat = {"r_drawflat", "0"}; 130cvar_t r_ambient = {"r_ambient", "0"}; 131cvar_t r_reportsurfout = {"r_reportsurfout", "0"}; 132cvar_t r_maxsurfs = {"r_maxsurfs", "0"}; 133cvar_t r_numsurfs = {"r_numsurfs", "0"}; 134cvar_t r_reportedgeout = {"r_reportedgeout", "0"}; 135cvar_t r_maxedges = {"r_maxedges", "0"}; 136cvar_t r_numedges = {"r_numedges", "0"}; 137cvar_t r_aliastransbase = {"r_aliastransbase", "200"}; 138cvar_t r_aliastransadj = {"r_aliastransadj", "100"}; 139 140extern cvar_t scr_fov; 141 142void CreatePassages (void); 143void SetVisibilityByPassages (void); 144 145void R_NetGraph (void); 146void R_ZGraph (void); 147 148/* 149================== 150R_InitTextures 151================== 152*/ 153void R_InitTextures (void) 154{ 155 int x,y, m; 156 byte *dest; 157 158// create a simple checkerboard texture for the default 159 r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture"); 160 161 r_notexture_mip->width = r_notexture_mip->height = 16; 162 r_notexture_mip->offsets[0] = sizeof(texture_t); 163 r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16; 164 r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8; 165 r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4; 166 167 for (m=0 ; m<4 ; m++) 168 { 169 dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m]; 170 for (y=0 ; y< (16>>m) ; y++) 171 for (x=0 ; x< (16>>m) ; x++) 172 { 173 if ( (y< (8>>m) ) ^ (x< (8>>m) ) ) 174 *dest++ = 0; 175 else 176 *dest++ = 0xff; 177 } 178 } 179} 180 181/* 182=============== 183R_Init 184=============== 185*/ 186void R_Init (void) 187{ 188 int dummy; 189 190// get stack position so we can guess if we are going to overflow 191 r_stack_start = (byte *)&dummy; 192 193 R_InitTurb (); 194 195 Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); 196 Cmd_AddCommand ("pointfile", R_ReadPointFile_f); 197 198 Cvar_RegisterVariable (&r_draworder); 199 Cvar_RegisterVariable (&r_speeds); 200 Cvar_RegisterVariable (&r_timegraph); 201 Cvar_RegisterVariable (&r_netgraph); 202 Cvar_RegisterVariable (&r_zgraph); 203 Cvar_RegisterVariable (&r_graphheight); 204 Cvar_RegisterVariable (&r_drawflat); 205 Cvar_RegisterVariable (&r_ambient); 206 Cvar_RegisterVariable (&r_clearcolor); 207 Cvar_RegisterVariable (&r_waterwarp); 208 Cvar_RegisterVariable (&r_fullbright); 209 Cvar_RegisterVariable (&r_drawentities); 210 Cvar_RegisterVariable (&r_drawviewmodel); 211 Cvar_RegisterVariable (&r_aliasstats); 212 Cvar_RegisterVariable (&r_dspeeds); 213 Cvar_RegisterVariable (&r_reportsurfout); 214 Cvar_RegisterVariable (&r_maxsurfs); 215 Cvar_RegisterVariable (&r_numsurfs); 216 Cvar_RegisterVariable (&r_reportedgeout); 217 Cvar_RegisterVariable (&r_maxedges); 218 Cvar_RegisterVariable (&r_numedges); 219 Cvar_RegisterVariable (&r_aliastransbase); 220 Cvar_RegisterVariable (&r_aliastransadj); 221 222 Cvar_SetValue ("r_maxedges", (float)NUMSTACKEDGES); 223 Cvar_SetValue ("r_maxsurfs", (float)NUMSTACKSURFACES); 224 225 view_clipplanes[0].leftedge = true; 226 view_clipplanes[1].rightedge = true; 227 view_clipplanes[1].leftedge = view_clipplanes[2].leftedge = 228 view_clipplanes[3].leftedge = false; 229 view_clipplanes[0].rightedge = view_clipplanes[2].rightedge = 230 view_clipplanes[3].rightedge = false; 231 232 r_refdef.xOrigin = XCENTERING; 233 r_refdef.yOrigin = YCENTERING; 234 235 R_InitParticles (); 236 237// TODO: collect 386-specific code in one place 238#if id386 239 Sys_MakeCodeWriteable ((long)R_EdgeCodeStart, 240 (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart); 241#endif // id386 242 243 D_Init (); 244} 245 246/* 247=============== 248R_NewMap 249=============== 250*/ 251void R_NewMap (void) 252{ 253 int i; 254 255 memset (&r_worldentity, 0, sizeof(r_worldentity)); 256 r_worldentity.model = cl.worldmodel; 257 258// clear out efrags in case the level hasn't been reloaded 259// FIXME: is this one short? 260 for (i=0 ; i<cl.worldmodel->numleafs ; i++) 261 cl.worldmodel->leafs[i].efrags = NULL; 262 263 r_viewleaf = NULL; 264 R_ClearParticles (); 265 266 r_cnumsurfs = r_maxsurfs.value; 267 268 if (r_cnumsurfs <= MINSURFACES) 269 r_cnumsurfs = MINSURFACES; 270 271 if (r_cnumsurfs > NUMSTACKSURFACES) 272 { 273 surfaces = Hunk_AllocName (r_cnumsurfs * sizeof(surf_t), "surfaces"); 274 surface_p = surfaces; 275 surf_max = &surfaces[r_cnumsurfs]; 276 r_surfsonstack = false; 277 // surface 0 doesn't really exist; it's just a dummy because index 0 278 // is used to indicate no edge attached to surface 279 surfaces--; 280 R_SurfacePatch (); 281 } 282 else 283 { 284 r_surfsonstack = true; 285 } 286 287 r_maxedgesseen = 0; 288 r_maxsurfsseen = 0; 289 290 r_numallocatededges = r_maxedges.value; 291 292 if (r_numallocatededges < MINEDGES) 293 r_numallocatededges = MINEDGES; 294 295 if (r_numallocatededges <= NUMSTACKEDGES) 296 { 297 auxedges = NULL; 298 } 299 else 300 { 301 auxedges = Hunk_AllocName (r_numallocatededges * sizeof(edge_t), 302 "edges"); 303 } 304 305 r_dowarpold = false; 306 r_viewchanged = false; 307} 308 309 310/* 311=============== 312R_SetVrect 313=============== 314*/ 315void R_SetVrect (vrect_t *pvrectin, vrect_t *pvrect, int lineadj) 316{ 317 int h; 318 float size; 319 qboolean full = false; 320 321 if (scr_viewsize.value >= 100.0) { 322 size = 100.0; 323 full = true; 324 } else 325 size = scr_viewsize.value; 326 327 if (cl.intermission) 328 { 329 full = true; 330 size = 100.0; 331 lineadj = 0; 332 } 333 size /= 100.0; 334 335 if (!cl_sbar.value && full) 336 h = pvrectin->height; 337 else 338 h = pvrectin->height - lineadj; 339 340// h = (!cl_sbar.value && size==1.0) ? pvrectin->height : (pvrectin->height - lineadj); 341// h = pvrectin->height - lineadj; 342 if (full) 343 pvrect->width = pvrectin->width; 344 else 345 pvrect->width = pvrectin->width * size; 346 if (pvrect->width < 96) 347 { 348 size = 96.0 / pvrectin->width; 349 pvrect->width = 96; // min for icons 350 } 351 pvrect->width &= ~7; 352 pvrect->height = pvrectin->height * size; 353 if (cl_sbar.value || !full) { 354 if (pvrect->height > pvrectin->height - lineadj) 355 pvrect->height = pvrectin->height - lineadj; 356 } else 357 if (pvrect->height > pvrectin->height) 358 pvrect->height = pvrectin->height; 359 360 pvrect->height &= ~1; 361 362 pvrect->x = (pvrectin->width - pvrect->width)/2; 363 if (full) 364 pvrect->y = 0; 365 else 366 pvrect->y = (h - pvrect->height)/2; 367} 368 369 370/* 371=============== 372R_ViewChanged 373 374Called every time the vid structure or r_refdef changes. 375Guaranteed to be called before the first refresh 376=============== 377*/ 378void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect) 379{ 380 int i; 381 float res_scale; 382 383 r_viewchanged = true; 384 385 R_SetVrect (pvrect, &r_refdef.vrect, lineadj); 386 387 r_refdef.horizontalFieldOfView = 2.0 * tan (r_refdef.fov_x/360*M_PI); 388 r_refdef.fvrectx = (float)r_refdef.vrect.x; 389 r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5; 390 r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; 391 r_refdef.fvrecty = (float)r_refdef.vrect.y; 392 r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5; 393 r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; 394 r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; 395 r_refdef.fvrectright = (float)r_refdef.vrectright; 396 r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5; 397 r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99; 398 r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; 399 r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; 400 r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5; 401 402 r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); 403 r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); 404 r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); 405 r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); 406 r_refdef.aliasvrectright = r_refdef.aliasvrect.x + 407 r_refdef.aliasvrect.width; 408 r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + 409 r_refdef.aliasvrect.height; 410 411 pixelAspect = aspect; 412 xOrigin = r_refdef.xOrigin; 413 yOrigin = r_refdef.yOrigin; 414 415 screenAspect = r_refdef.vrect.width*pixelAspect / 416 r_refdef.vrect.height; 417// 320*200 1.0 pixelAspect = 1.6 screenAspect 418// 320*240 1.0 pixelAspect = 1.3333 screenAspect 419// proper 320*200 pixelAspect = 0.8333333 420 421 verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect; 422 423// values for perspective projection 424// if math were exact, the values would range from 0.5 to to range+0.5 425// hopefully they wll be in the 0.000001 to range+.999999 and truncate 426// the polygon rasterization will never render in the first row or column 427// but will definately render in the [range] row and column, so adjust the 428// buffer origin to get an exact edge to edge fill 429 xcenter = ((float)r_refdef.vrect.width * XCENTERING) + 430 r_refdef.vrect.x - 0.5; 431 aliasxcenter = xcenter * r_aliasuvscale; 432 ycenter = ((float)r_refdef.vrect.height * YCENTERING) + 433 r_refdef.vrect.y - 0.5; 434 aliasycenter = ycenter * r_aliasuvscale; 435 436 xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; 437 aliasxscale = xscale * r_aliasuvscale; 438 xscaleinv = 1.0 / xscale; 439 yscale = xscale * pixelAspect; 440 aliasyscale = yscale * r_aliasuvscale; 441 yscaleinv = 1.0 / yscale; 442 xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; 443 yscaleshrink = xscaleshrink*pixelAspect; 444 445// left side clip 446 screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView); 447 screenedge[0].normal[1] = 0; 448 screenedge[0].normal[2] = 1; 449 screenedge[0].type = PLANE_ANYZ; 450 451// right side clip 452 screenedge[1].normal[0] = 453 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView); 454 screenedge[1].normal[1] = 0; 455 screenedge[1].normal[2] = 1; 456 screenedge[1].type = PLANE_ANYZ; 457 458// top side clip 459 screenedge[2].normal[0] = 0; 460 screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView); 461 screenedge[2].normal[2] = 1; 462 screenedge[2].type = PLANE_ANYZ; 463 464// bottom side clip 465 screenedge[3].normal[0] = 0; 466 screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView); 467 screenedge[3].normal[2] = 1; 468 screenedge[3].type = PLANE_ANYZ; 469 470 for (i=0 ; i<4 ; i++) 471 VectorNormalize (screenedge[i].normal); 472 473 res_scale = sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) / 474 (320.0 * 152.0)) * 475 (2.0 / r_refdef.horizontalFieldOfView); 476 r_aliastransition = r_aliastransbase.value * res_scale; 477 r_resfudge = r_aliastransadj.value * res_scale; 478 479 if (scr_fov.value <= 90.0) 480 r_fov_greater_than_90 = false; 481 else 482 r_fov_greater_than_90 = true; 483 484// TODO: collect 386-specific code in one place 485#if id386 486 if (r_pixbytes == 1) 487 { 488 Sys_MakeCodeWriteable ((long)R_Surf8Start, 489 (long)R_Surf8End - (long)R_Surf8Start); 490 colormap = vid.colormap; 491 R_Surf8Patch (); 492 } 493 else 494 { 495 Sys_MakeCodeWriteable ((long)R_Surf16Start, 496 (long)R_Surf16End - (long)R_Surf16Start); 497 colormap = vid.colormap16; 498 R_Surf16Patch (); 499 } 500#endif // id386 501 502 D_ViewChanged (); 503} 504 505 506/* 507=============== 508R_MarkLeaves 509=============== 510*/ 511void R_MarkLeaves (void) 512{ 513 byte *vis; 514 mnode_t *node; 515 int i; 516 517 if (r_oldviewleaf == r_viewleaf) 518 return; 519 520 r_visframecount++; 521 r_oldviewleaf = r_viewleaf; 522 523 vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); 524 525 for (i=0 ; i<cl.worldmodel->numleafs ; i++) 526 { 527 if (vis[i>>3] & (1<<(i&7))) 528 { 529 node = (mnode_t *)&cl.worldmodel->leafs[i+1]; 530 do 531 { 532 if (node->visframe == r_visframecount) 533 break; 534 node->visframe = r_visframecount; 535 node = node->parent; 536 } while (node); 537 } 538 } 539} 540 541 542/* 543============= 544R_DrawEntitiesOnList 545============= 546*/ 547void R_DrawEntitiesOnList (void) 548{ 549 int i, j; 550 int lnum; 551 alight_t lighting; 552// FIXME: remove and do real lighting 553 float lightvec[3] = {-1, 0, 0}; 554 vec3_t dist; 555 float add; 556 557 if (!r_drawentities.value) 558 return; 559 560 for (i=0 ; i<cl_numvisedicts ; i++) 561 { 562 currententity = &cl_visedicts[i]; 563 564 switch (currententity->model->type) 565 { 566 case mod_sprite: 567 VectorCopy (currententity->origin, r_entorigin); 568 VectorSubtract (r_origin, r_entorigin, modelorg); 569 R_DrawSprite (); 570 break; 571 572 case mod_alias: 573 VectorCopy (currententity->origin, r_entorigin); 574 VectorSubtract (r_origin, r_entorigin, modelorg); 575 576 // see if the bounding box lets us trivially reject, also sets 577 // trivial accept status 578 if (R_AliasCheckBBox ()) 579 { 580 j = R_LightPoint (currententity->origin); 581 582 lighting.ambientlight = j; 583 lighting.shadelight = j; 584 585 lighting.plightvec = lightvec; 586 587 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 588 { 589 if (cl_dlights[lnum].die >= cl.time) 590 { 591 VectorSubtract (currententity->origin, 592 cl_dlights[lnum].origin, 593 dist); 594 add = cl_dlights[lnum].radius - Length(dist); 595 596 if (add > 0) 597 lighting.ambientlight += add; 598 } 599 } 600 601 // clamp lighting so it doesn't overbright as much 602 if (lighting.ambientlight > 128) 603 lighting.ambientlight = 128; 604 if (lighting.ambientlight + lighting.shadelight > 192) 605 lighting.shadelight = 192 - lighting.ambientlight; 606 607 R_AliasDrawModel (&lighting); 608 } 609 610 break; 611 612 default: 613 break; 614 } 615 } 616} 617 618/* 619============= 620R_DrawViewModel 621============= 622*/ 623void R_DrawViewModel (void) 624{ 625// FIXME: remove and do real lighting 626 float lightvec[3] = {-1, 0, 0}; 627 int j; 628 int lnum; 629 vec3_t dist; 630 float add; 631 dlight_t *dl; 632 633 if (!r_drawviewmodel.value || r_fov_greater_than_90 || !Cam_DrawViewModel()) 634 return; 635 636 if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) 637 return; 638 639 if (cl.stats[STAT_HEALTH] <= 0) 640 return; 641 642 currententity = &cl.viewent; 643 if (!currententity->model) 644 return; 645 646 VectorCopy (currententity->origin, r_entorigin); 647 VectorSubtract (r_origin, r_entorigin, modelorg); 648 649 VectorCopy (vup, viewlightvec); 650 VectorInverse (viewlightvec); 651 652 j = R_LightPoint (currententity->origin); 653 654 if (j < 24) 655 j = 24; // allways give some light on gun 656 r_viewlighting.ambientlight = j; 657 r_viewlighting.shadelight = j; 658 659// add dynamic lights 660 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 661 { 662 dl = &cl_dlights[lnum]; 663 if (!dl->radius) 664 continue; 665 if (!dl->radius) 666 continue; 667 if (dl->die < cl.time) 668 continue; 669 670 VectorSubtract (currententity->origin, dl->origin, dist); 671 add = dl->radius - Length(dist); 672 if (add > 0) 673 r_viewlighting.ambientlight += add; 674 } 675 676// clamp lighting so it doesn't overbright as much 677 if (r_viewlighting.ambientlight > 128) 678 r_viewlighting.ambientlight = 128; 679 if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192) 680 r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight; 681 682 r_viewlighting.plightvec = lightvec; 683 684 R_AliasDrawModel (&r_viewlighting); 685} 686 687 688/* 689============= 690R_BmodelCheckBBox 691============= 692*/ 693int R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) 694{ 695 int i, *pindex, clipflags; 696 vec3_t acceptpt, rejectpt; 697 double d; 698 699 clipflags = 0; 700 701 if (currententity->angles[0] || currententity->angles[1] 702 || currententity->angles[2]) 703 { 704 for (i=0 ; i<4 ; i++) 705 { 706 d = DotProduct (currententity->origin, view_clipplanes[i].normal); 707 d -= view_clipplanes[i].dist; 708 709 if (d <= -clmodel->radius) 710 return BMODEL_FULLY_CLIPPED; 711 712 if (d <= clmodel->radius) 713 clipflags |= (1<<i); 714 } 715 } 716 else 717 { 718 for (i=0 ; i<4 ; i++) 719 { 720 // generate accept and reject points 721 // FIXME: do with fast look-ups or integer tests based on the sign bit 722 // of the floating point values 723 724 pindex = pfrustum_indexes[i]; 725 726 rejectpt[0] = minmaxs[pindex[0]]; 727 rejectpt[1] = minmaxs[pindex[1]]; 728 rejectpt[2] = minmaxs[pindex[2]]; 729 730 d = DotProduct (rejectpt, view_clipplanes[i].normal); 731 d -= view_clipplanes[i].dist; 732 733 if (d <= 0) 734 return BMODEL_FULLY_CLIPPED; 735 736 acceptpt[0] = minmaxs[pindex[3+0]]; 737 acceptpt[1] = minmaxs[pindex[3+1]]; 738 acceptpt[2] = minmaxs[pindex[3+2]]; 739 740 d = DotProduct (acceptpt, view_clipplanes[i].normal); 741 d -= view_clipplanes[i].dist; 742 743 if (d <= 0) 744 clipflags |= (1<<i); 745 } 746 } 747 748 return clipflags; 749} 750 751 752/* 753============= 754R_DrawBEntitiesOnList 755============= 756*/ 757void R_DrawBEntitiesOnList (void) 758{ 759 int i, j, k, clipflags; 760 vec3_t oldorigin; 761 model_t *clmodel; 762 float minmaxs[6]; 763 764 if (!r_drawentities.value) 765 return; 766 767 VectorCopy (modelorg, oldorigin); 768 insubmodel = true; 769 r_dlightframecount = r_framecount; 770 771 for (i=0 ; i<cl_numvisedicts ; i++) 772 { 773 currententity = &cl_visedicts[i]; 774 775 switch (currententity->model->type) 776 { 777 case mod_brush: 778 779 clmodel = currententity->model; 780 781 // see if the bounding box lets us trivially reject, also sets 782 // trivial accept status 783 for (j=0 ; j<3 ; j++) 784 { 785 minmaxs[j] = currententity->origin[j] + 786 clmodel->mins[j]; 787 minmaxs[3+j] = currententity->origin[j] + 788 clmodel->maxs[j]; 789 } 790 791 clipflags = R_BmodelCheckBBox (clmodel, minmaxs); 792 793 if (clipflags != BMODEL_FULLY_CLIPPED) 794 { 795 VectorCopy (currententity->origin, r_entorigin); 796 VectorSubtract (r_origin, r_entorigin, modelorg); 797 // FIXME: is this needed? 798 VectorCopy (modelorg, r_worldmodelorg); 799 800 r_pcurrentvertbase = clmodel->vertexes; 801 802 // FIXME: stop transforming twice 803 R_RotateBmodel (); 804 805 // calculate dynamic lighting for bmodel if it's not an 806 // instanced model 807 if (clmodel->firstmodelsurface != 0) 808 { 809 for (k=0 ; k<MAX_DLIGHTS ; k++) 810 { 811 if ((cl_dlights[k].die < cl.time) || 812 (!cl_dlights[k].radius)) 813 { 814 continue; 815 } 816 817 R_MarkLights (&cl_dlights[k], 1<<k, 818 clmodel->nodes + clmodel->hulls[0].firstclipnode); 819 } 820 } 821 822 // if the driver wants polygons, deliver those. Z-buffering is on 823 // at this point, so no clipping to the world tree is needed, just 824 // frustum clipping 825 if (r_drawpolys | r_drawculledpolys) 826 { 827 R_ZDrawSubmodelPolys (clmodel); 828 } 829 else 830 { 831 r_pefragtopnode = NULL; 832 833 for (j=0 ; j<3 ; j++) 834 { 835 r_emins[j] = minmaxs[j]; 836 r_emaxs[j] = minmaxs[3+j]; 837 } 838 839 R_SplitEntityOnNode2 (cl.worldmodel->nodes); 840 841 if (r_pefragtopnode) 842 { 843 currententity->topnode = r_pefragtopnode; 844 845 if (r_pefragtopnode->contents >= 0) 846 { 847 // not a leaf; has to be clipped to the world BSP 848 r_clipflags = clipflags; 849 R_DrawSolidClippedSubmodelPolygons (clmodel); 850 } 851 else 852 { 853 // falls entirely in one leaf, so we just put all the 854 // edges in the edge list and let 1/z sorting handle 855 // drawing order 856 R_DrawSubmodelPolygons (clmodel, clipflags); 857 } 858 859 currententity->topnode = NULL; 860 } 861 } 862 863 // put back world rotation and frustum clipping 864 // FIXME: R_RotateBmodel should just work off base_vxx 865 VectorCopy (base_vpn, vpn); 866 VectorCopy (base_vup, vup); 867 VectorCopy (base_vright, vright); 868 VectorCopy (base_modelorg, modelorg); 869 VectorCopy (oldorigin, modelorg); 870 R_TransformFrustum (); 871 } 872 873 break; 874 875 default: 876 break; 877 } 878 } 879 880 insubmodel = false; 881} 882 883 884/* 885================ 886R_EdgeDrawing 887================ 888*/ 889void R_EdgeDrawing (void) 890{ 891 edge_t ledges[NUMSTACKEDGES + 892 ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; 893 surf_t lsurfs[NUMSTACKSURFACES + 894 ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; 895 896 if (auxedges) 897 { 898 r_edges = auxedges; 899 } 900 else 901 { 902 r_edges = (edge_t *) 903 (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); 904 } 905 906 if (r_surfsonstack) 907 { 908 surfaces = (surf_t *) 909 (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); 910 surf_max = &surfaces[r_cnumsurfs]; 911 // surface 0 doesn't really exist; it's just a dummy because index 0 912 // is used to indicate no edge attached to surface 913 surfaces--; 914 R_SurfacePatch (); 915 } 916 917 R_BeginEdgeFrame (); 918 919 if (r_dspeeds.value) 920 { 921 rw_time1 = Sys_DoubleTime (); 922 } 923 924 R_RenderWorld (); 925 926 if (r_drawculledpolys) 927 R_ScanEdges (); 928 929// only the world can be drawn back to front with no z reads or compares, just 930// z writes, so have the driver turn z compares on now 931 D_TurnZOn (); 932 933 if (r_dspeeds.value) 934 { 935 rw_time2 = Sys_DoubleTime (); 936 db_time1 = rw_time2; 937 } 938 939 R_DrawBEntitiesOnList (); 940 941 if (r_dspeeds.value) 942 { 943 db_time2 = Sys_DoubleTime (); 944 se_time1 = db_time2; 945 } 946 947 if (!r_dspeeds.value) 948 { 949 VID_UnlockBuffer (); 950 S_ExtraUpdate (); // don't let sound get messed up if going slow 951 VID_LockBuffer (); 952 } 953 954 if (!(r_drawpolys | r_drawculledpolys)) 955 R_ScanEdges (); 956} 957 958 959/* 960================ 961R_RenderView 962 963r_refdef must be set before the first call 964================ 965*/ 966void R_RenderView_ (void) 967{ 968 byte warpbuffer[WARP_WIDTH * WARP_HEIGHT]; 969 970 r_warpbuffer = warpbuffer; 971 972 if (r_timegraph.value || r_speeds.value || r_dspeeds.value) 973 r_time1 = Sys_DoubleTime (); 974 975 R_SetupFrame (); 976 977#ifdef PASSAGES 978SetVisibilityByPassages (); 979#else 980 R_MarkLeaves (); // done here so we know if we're in water 981#endif 982 983// make FDIV fast. This reduces timing precision after we've been running for a 984// while, so we don't do it globally. This also sets chop mode, and we do it 985// here so that setup stuff like the refresh area calculations match what's 986// done in screen.c 987 Sys_LowFPPrecision (); 988 989 if (!r_worldentity.model || !cl.worldmodel) 990 Sys_Error ("R_RenderView: NULL worldmodel"); 991 992 if (!r_dspeeds.value) 993 { 994 VID_UnlockBuffer (); 995 S_ExtraUpdate (); // don't let sound get messed up if going slow 996 VID_LockBuffer (); 997 } 998 999 R_EdgeDrawing (); 1000 1001 if (!r_dspeeds.value) 1002 { 1003 VID_UnlockBuffer (); 1004 S_ExtraUpdate (); // don't let sound get messed up if going slow 1005 VID_LockBuffer (); 1006 } 1007 1008 if (r_dspeeds.value) 1009 { 1010 se_time2 = Sys_DoubleTime (); 1011 de_time1 = se_time2; 1012 } 1013 1014 R_DrawEntitiesOnList (); 1015 1016 if (r_dspeeds.value) 1017 { 1018 de_time2 = Sys_DoubleTime (); 1019 dv_time1 = de_time2; 1020 } 1021 1022 R_DrawViewModel (); 1023 1024 if (r_dspeeds.value) 1025 { 1026 dv_time2 = Sys_DoubleTime (); 1027 dp_time1 = Sys_DoubleTime (); 1028 } 1029 1030 R_DrawParticles (); 1031 1032 if (r_dspeeds.value) 1033 dp_time2 = Sys_DoubleTime (); 1034 1035 if (r_dowarp) 1036 D_WarpScreen (); 1037 1038 V_SetContentsColor (r_viewleaf->contents); 1039 1040 if (r_timegraph.value) 1041 R_TimeGraph (); 1042 1043 if (r_netgraph.value) 1044 R_NetGraph (); 1045 1046 if (r_zgraph.value) 1047 R_ZGraph (); 1048 1049 if (r_aliasstats.value) 1050 R_PrintAliasStats (); 1051 1052 if (r_speeds.value) 1053 R_PrintTimes (); 1054 1055 if (r_dspeeds.value) 1056 R_PrintDSpeeds (); 1057 1058 if (r_reportsurfout.value && r_outofsurfaces) 1059 Con_Printf ("Short %d surfaces\n", r_outofsurfaces); 1060 1061 if (r_reportedgeout.value && r_outofedges) 1062 Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3); 1063 1064// back to high floating-point precision 1065 Sys_HighFPPrecision (); 1066} 1067 1068void R_RenderView (void) 1069{ 1070 int dummy; 1071 int delta; 1072 1073 delta = (byte *)&dummy - r_stack_start; 1074 if (delta < -10000 || delta > 10000) 1075 Sys_Error ("R_RenderView: called without enough stack"); 1076 1077 if ( Hunk_LowMark() & 3 ) 1078 Sys_Error ("Hunk is missaligned"); 1079 1080 if ( (long)(&dummy) & 3 ) 1081 Sys_Error ("Stack is missaligned"); 1082 1083 if ( (long)(&r_warpbuffer) & 3 ) 1084 Sys_Error ("Globals are missaligned"); 1085 1086 R_RenderView_ (); 1087} 1088 1089/* 1090================ 1091R_InitTurb 1092================ 1093*/ 1094void R_InitTurb (void) 1095{ 1096 int i; 1097 1098 for (i=0 ; i<1280 ; i++) 1099 { 1100 sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP; 1101 intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20 1102 } 1103} 1104 1105