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