r_rast.c (19132B)
1 /* 2 Copyright (C) 1997-2001 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_rast.c 21 22 #include <assert.h> 23 24 #include "r_local.h" 25 26 #define MAXLEFTCLIPEDGES 100 27 28 // !!! if these are changed, they must be changed in asm_draw.h too !!! 29 #define FULLY_CLIPPED_CACHED 0x80000000 30 #define FRAMECOUNT_MASK 0x7FFFFFFF 31 32 unsigned int cacheoffset; 33 34 int c_faceclip; // number of faces clipped 35 36 37 clipplane_t *entity_clipplanes; 38 clipplane_t view_clipplanes[4]; 39 clipplane_t world_clipplanes[16]; 40 41 medge_t *r_pedge; 42 43 qboolean r_leftclipped, r_rightclipped; 44 static qboolean makeleftedge, makerightedge; 45 qboolean r_nearzionly; 46 47 int sintable[1280]; 48 int intsintable[1280]; 49 int blanktable[1280]; // PGM 50 51 mvertex_t r_leftenter, r_leftexit; 52 mvertex_t r_rightenter, r_rightexit; 53 54 typedef struct 55 { 56 float u,v; 57 int ceilv; 58 } evert_t; 59 60 int r_emitted; 61 float r_nearzi; 62 float r_u1, r_v1, r_lzi1; 63 int r_ceilv1; 64 65 qboolean r_lastvertvalid; 66 int r_skyframe; 67 68 msurface_t *r_skyfaces; 69 mplane_t r_skyplanes[6]; 70 mtexinfo_t r_skytexinfo[6]; 71 mvertex_t *r_skyverts; 72 medge_t *r_skyedges; 73 int *r_skysurfedges; 74 75 // I just copied this data from a box map... 76 int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128}; 77 78 int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11, 79 12,-3,-11,-8, -12,-10,-5,-4}; 80 int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4}; 81 82 int box_faces[6] = {0,0,2,2,2,0}; 83 84 vec3_t box_vecs[6][2] = { 85 { {0,-1,0}, {-1,0,0} }, 86 { {0,1,0}, {0,0,-1} }, 87 { {0,-1,0}, {1,0,0} }, 88 { {1,0,0}, {0,0,-1} }, 89 { {0,-1,0}, {0,0,-1} }, 90 { {-1,0,0}, {0,0,-1} } 91 }; 92 93 float box_verts[8][3] = { 94 {-1,-1,-1}, 95 {-1,1,-1}, 96 {1,1,-1}, 97 {1,-1,-1}, 98 {-1,-1,1}, 99 {-1,1,1}, 100 {1,-1,1}, 101 {1,1,1} 102 }; 103 104 // down, west, up, north, east, south 105 // {"rt", "bk", "lf", "ft", "up", "dn"}; 106 107 /* 108 ================ 109 R_InitSkyBox 110 111 ================ 112 */ 113 void R_InitSkyBox (void) 114 { 115 int i; 116 extern model_t *loadmodel; 117 118 r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces; 119 loadmodel->numsurfaces += 6; 120 r_skyverts = loadmodel->vertexes + loadmodel->numvertexes; 121 loadmodel->numvertexes += 8; 122 r_skyedges = loadmodel->edges + loadmodel->numedges; 123 loadmodel->numedges += 12; 124 r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges; 125 loadmodel->numsurfedges += 24; 126 if (loadmodel->numsurfaces > MAX_MAP_FACES 127 || loadmodel->numvertexes > MAX_MAP_VERTS 128 || loadmodel->numedges > MAX_MAP_EDGES) 129 ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow"); 130 131 memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces)); 132 for (i=0 ; i<6 ; i++) 133 { 134 r_skyplanes[i].normal[skybox_planes[i*2]] = 1; 135 r_skyplanes[i].dist = skybox_planes[i*2+1]; 136 137 VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]); 138 VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]); 139 140 r_skyfaces[i].plane = &r_skyplanes[i]; 141 r_skyfaces[i].numedges = 4; 142 r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX; 143 r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4; 144 r_skyfaces[i].texinfo = &r_skytexinfo[i]; 145 r_skyfaces[i].texturemins[0] = -128; 146 r_skyfaces[i].texturemins[1] = -128; 147 r_skyfaces[i].extents[0] = 256; 148 r_skyfaces[i].extents[1] = 256; 149 } 150 151 for (i=0 ; i<24 ; i++) 152 if (box_surfedges[i] > 0) 153 r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i]; 154 else 155 r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]); 156 157 for(i=0 ; i<12 ; i++) 158 { 159 r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0]; 160 r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1]; 161 r_skyedges[i].cachededgeoffset = 0; 162 } 163 } 164 165 /* 166 ================ 167 R_EmitSkyBox 168 ================ 169 */ 170 void R_EmitSkyBox (void) 171 { 172 int i, j; 173 int oldkey; 174 175 if (insubmodel) 176 return; // submodels should never have skies 177 if (r_skyframe == r_framecount) 178 return; // already set this frame 179 180 r_skyframe = r_framecount; 181 182 // set the eight fake vertexes 183 for (i=0 ; i<8 ; i++) 184 for (j=0 ; j<3 ; j++) 185 r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128; 186 187 // set the six fake planes 188 for (i=0 ; i<6 ; i++) 189 if (skybox_planes[i*2+1] > 0) 190 r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128; 191 else 192 r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128; 193 194 // fix texture offseets 195 for (i=0 ; i<6 ; i++) 196 { 197 r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]); 198 r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]); 199 } 200 201 // emit the six faces 202 oldkey = r_currentkey; 203 r_currentkey = 0x7ffffff0; 204 for (i=0 ; i<6 ; i++) 205 { 206 R_RenderFace (r_skyfaces + i, 15); 207 } 208 r_currentkey = oldkey; // bsp sorting order 209 } 210 211 212 #if !id386 213 214 /* 215 ================ 216 R_EmitEdge 217 ================ 218 */ 219 void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1) 220 { 221 edge_t *edge, *pcheck; 222 int u_check; 223 float u, u_step; 224 vec3_t local, transformed; 225 float *world; 226 int v, v2, ceilv0; 227 float scale, lzi0, u0, v0; 228 int side; 229 230 if (r_lastvertvalid) 231 { 232 u0 = r_u1; 233 v0 = r_v1; 234 lzi0 = r_lzi1; 235 ceilv0 = r_ceilv1; 236 } 237 else 238 { 239 world = &pv0->position[0]; 240 241 // transform and project 242 VectorSubtract (world, modelorg, local); 243 TransformVector (local, transformed); 244 245 if (transformed[2] < NEAR_CLIP) 246 transformed[2] = NEAR_CLIP; 247 248 lzi0 = 1.0 / transformed[2]; 249 250 // FIXME: build x/yscale into transform? 251 scale = xscale * lzi0; 252 u0 = (xcenter + scale*transformed[0]); 253 if (u0 < r_refdef.fvrectx_adj) 254 u0 = r_refdef.fvrectx_adj; 255 if (u0 > r_refdef.fvrectright_adj) 256 u0 = r_refdef.fvrectright_adj; 257 258 scale = yscale * lzi0; 259 v0 = (ycenter - scale*transformed[1]); 260 if (v0 < r_refdef.fvrecty_adj) 261 v0 = r_refdef.fvrecty_adj; 262 if (v0 > r_refdef.fvrectbottom_adj) 263 v0 = r_refdef.fvrectbottom_adj; 264 265 ceilv0 = (int) ceil(v0); 266 } 267 268 world = &pv1->position[0]; 269 270 // transform and project 271 VectorSubtract (world, modelorg, local); 272 TransformVector (local, transformed); 273 274 if (transformed[2] < NEAR_CLIP) 275 transformed[2] = NEAR_CLIP; 276 277 r_lzi1 = 1.0 / transformed[2]; 278 279 scale = xscale * r_lzi1; 280 r_u1 = (xcenter + scale*transformed[0]); 281 if (r_u1 < r_refdef.fvrectx_adj) 282 r_u1 = r_refdef.fvrectx_adj; 283 if (r_u1 > r_refdef.fvrectright_adj) 284 r_u1 = r_refdef.fvrectright_adj; 285 286 scale = yscale * r_lzi1; 287 r_v1 = (ycenter - scale*transformed[1]); 288 if (r_v1 < r_refdef.fvrecty_adj) 289 r_v1 = r_refdef.fvrecty_adj; 290 if (r_v1 > r_refdef.fvrectbottom_adj) 291 r_v1 = r_refdef.fvrectbottom_adj; 292 293 if (r_lzi1 > lzi0) 294 lzi0 = r_lzi1; 295 296 if (lzi0 > r_nearzi) // for mipmap finding 297 r_nearzi = lzi0; 298 299 // for right edges, all we want is the effect on 1/z 300 if (r_nearzionly) 301 return; 302 303 r_emitted = 1; 304 305 r_ceilv1 = (int) ceil(r_v1); 306 307 308 // create the edge 309 if (ceilv0 == r_ceilv1) 310 { 311 // we cache unclipped horizontal edges as fully clipped 312 if (cacheoffset != 0x7FFFFFFF) 313 { 314 cacheoffset = FULLY_CLIPPED_CACHED | 315 (r_framecount & FRAMECOUNT_MASK); 316 } 317 318 return; // horizontal edge 319 } 320 321 side = ceilv0 > r_ceilv1; 322 323 edge = edge_p++; 324 325 edge->owner = r_pedge; 326 327 edge->nearzi = lzi0; 328 329 if (side == 0) 330 { 331 // trailing edge (go from p1 to p2) 332 v = ceilv0; 333 v2 = r_ceilv1 - 1; 334 335 edge->surfs[0] = surface_p - surfaces; 336 edge->surfs[1] = 0; 337 338 u_step = ((r_u1 - u0) / (r_v1 - v0)); 339 u = u0 + ((float)v - v0) * u_step; 340 } 341 else 342 { 343 // leading edge (go from p2 to p1) 344 v2 = ceilv0 - 1; 345 v = r_ceilv1; 346 347 edge->surfs[0] = 0; 348 edge->surfs[1] = surface_p - surfaces; 349 350 u_step = ((u0 - r_u1) / (v0 - r_v1)); 351 u = r_u1 + ((float)v - r_v1) * u_step; 352 } 353 354 edge->u_step = u_step*0x100000; 355 edge->u = u*0x100000 + 0xFFFFF; 356 357 // we need to do this to avoid stepping off the edges if a very nearly 358 // horizontal edge is less than epsilon above a scan, and numeric error causes 359 // it to incorrectly extend to the scan, and the extension of the line goes off 360 // the edge of the screen 361 // FIXME: is this actually needed? 362 if (edge->u < r_refdef.vrect_x_adj_shift20) 363 edge->u = r_refdef.vrect_x_adj_shift20; 364 if (edge->u > r_refdef.vrectright_adj_shift20) 365 edge->u = r_refdef.vrectright_adj_shift20; 366 367 // 368 // sort the edge in normally 369 // 370 u_check = edge->u; 371 if (edge->surfs[0]) 372 u_check++; // sort trailers after leaders 373 374 if (!newedges[v] || newedges[v]->u >= u_check) 375 { 376 edge->next = newedges[v]; 377 newedges[v] = edge; 378 } 379 else 380 { 381 pcheck = newedges[v]; 382 while (pcheck->next && pcheck->next->u < u_check) 383 pcheck = pcheck->next; 384 edge->next = pcheck->next; 385 pcheck->next = edge; 386 } 387 388 edge->nextremove = removeedges[v2]; 389 removeedges[v2] = edge; 390 } 391 392 393 /* 394 ================ 395 R_ClipEdge 396 ================ 397 */ 398 void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip) 399 { 400 float d0, d1, f; 401 mvertex_t clipvert; 402 403 if (clip) 404 { 405 do 406 { 407 d0 = DotProduct (pv0->position, clip->normal) - clip->dist; 408 d1 = DotProduct (pv1->position, clip->normal) - clip->dist; 409 410 if (d0 >= 0) 411 { 412 // point 0 is unclipped 413 if (d1 >= 0) 414 { 415 // both points are unclipped 416 continue; 417 } 418 419 // only point 1 is clipped 420 421 // we don't cache clipped edges 422 cacheoffset = 0x7FFFFFFF; 423 424 f = d0 / (d0 - d1); 425 clipvert.position[0] = pv0->position[0] + 426 f * (pv1->position[0] - pv0->position[0]); 427 clipvert.position[1] = pv0->position[1] + 428 f * (pv1->position[1] - pv0->position[1]); 429 clipvert.position[2] = pv0->position[2] + 430 f * (pv1->position[2] - pv0->position[2]); 431 432 if (clip->leftedge) 433 { 434 r_leftclipped = true; 435 r_leftexit = clipvert; 436 } 437 else if (clip->rightedge) 438 { 439 r_rightclipped = true; 440 r_rightexit = clipvert; 441 } 442 443 R_ClipEdge (pv0, &clipvert, clip->next); 444 return; 445 } 446 else 447 { 448 // point 0 is clipped 449 if (d1 < 0) 450 { 451 // both points are clipped 452 // we do cache fully clipped edges 453 if (!r_leftclipped) 454 cacheoffset = FULLY_CLIPPED_CACHED | 455 (r_framecount & FRAMECOUNT_MASK); 456 return; 457 } 458 459 // only point 0 is clipped 460 r_lastvertvalid = false; 461 462 // we don't cache partially clipped edges 463 cacheoffset = 0x7FFFFFFF; 464 465 f = d0 / (d0 - d1); 466 clipvert.position[0] = pv0->position[0] + 467 f * (pv1->position[0] - pv0->position[0]); 468 clipvert.position[1] = pv0->position[1] + 469 f * (pv1->position[1] - pv0->position[1]); 470 clipvert.position[2] = pv0->position[2] + 471 f * (pv1->position[2] - pv0->position[2]); 472 473 if (clip->leftedge) 474 { 475 r_leftclipped = true; 476 r_leftenter = clipvert; 477 } 478 else if (clip->rightedge) 479 { 480 r_rightclipped = true; 481 r_rightenter = clipvert; 482 } 483 484 R_ClipEdge (&clipvert, pv1, clip->next); 485 return; 486 } 487 } while ((clip = clip->next) != NULL); 488 } 489 490 // add the edge 491 R_EmitEdge (pv0, pv1); 492 } 493 494 #endif // !id386 495 496 497 /* 498 ================ 499 R_EmitCachedEdge 500 ================ 501 */ 502 void R_EmitCachedEdge (void) 503 { 504 edge_t *pedge_t; 505 506 pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset); 507 508 if (!pedge_t->surfs[0]) 509 pedge_t->surfs[0] = surface_p - surfaces; 510 else 511 pedge_t->surfs[1] = surface_p - surfaces; 512 513 if (pedge_t->nearzi > r_nearzi) // for mipmap finding 514 r_nearzi = pedge_t->nearzi; 515 516 r_emitted = 1; 517 } 518 519 520 /* 521 ================ 522 R_RenderFace 523 ================ 524 */ 525 void R_RenderFace (msurface_t *fa, int clipflags) 526 { 527 int i, lindex; 528 unsigned mask; 529 mplane_t *pplane; 530 float distinv; 531 vec3_t p_normal; 532 medge_t *pedges, tedge; 533 clipplane_t *pclip; 534 535 // translucent surfaces are not drawn by the edge renderer 536 if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) 537 { 538 fa->nextalphasurface = r_alpha_surfaces; 539 r_alpha_surfaces = fa; 540 return; 541 } 542 543 // sky surfaces encountered in the world will cause the 544 // environment box surfaces to be emited 545 if ( fa->texinfo->flags & SURF_SKY ) 546 { 547 R_EmitSkyBox (); 548 return; 549 } 550 551 // skip out if no more surfs 552 if ((surface_p) >= surf_max) 553 { 554 r_outofsurfaces++; 555 return; 556 } 557 558 // ditto if not enough edges left, or switch to auxedges if possible 559 if ((edge_p + fa->numedges + 4) >= edge_max) 560 { 561 r_outofedges += fa->numedges; 562 return; 563 } 564 565 c_faceclip++; 566 567 // set up clip planes 568 pclip = NULL; 569 570 for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) 571 { 572 if (clipflags & mask) 573 { 574 view_clipplanes[i].next = pclip; 575 pclip = &view_clipplanes[i]; 576 } 577 } 578 579 // push the edges through 580 r_emitted = 0; 581 r_nearzi = 0; 582 r_nearzionly = false; 583 makeleftedge = makerightedge = false; 584 pedges = currentmodel->edges; 585 r_lastvertvalid = false; 586 587 for (i=0 ; i<fa->numedges ; i++) 588 { 589 lindex = currentmodel->surfedges[fa->firstedge + i]; 590 591 if (lindex > 0) 592 { 593 r_pedge = &pedges[lindex]; 594 595 // if the edge is cached, we can just reuse the edge 596 if (!insubmodel) 597 { 598 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) 599 { 600 if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == 601 r_framecount) 602 { 603 r_lastvertvalid = false; 604 continue; 605 } 606 } 607 else 608 { 609 if ((((unsigned long)edge_p - (unsigned long)r_edges) > 610 r_pedge->cachededgeoffset) && 611 (((edge_t *)((unsigned long)r_edges + 612 r_pedge->cachededgeoffset))->owner == r_pedge)) 613 { 614 R_EmitCachedEdge (); 615 r_lastvertvalid = false; 616 continue; 617 } 618 } 619 } 620 621 // assume it's cacheable 622 cacheoffset = (byte *)edge_p - (byte *)r_edges; 623 r_leftclipped = r_rightclipped = false; 624 R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]], 625 &r_pcurrentvertbase[r_pedge->v[1]], 626 pclip); 627 r_pedge->cachededgeoffset = cacheoffset; 628 629 if (r_leftclipped) 630 makeleftedge = true; 631 if (r_rightclipped) 632 makerightedge = true; 633 r_lastvertvalid = true; 634 } 635 else 636 { 637 lindex = -lindex; 638 r_pedge = &pedges[lindex]; 639 // if the edge is cached, we can just reuse the edge 640 if (!insubmodel) 641 { 642 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) 643 { 644 if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == 645 r_framecount) 646 { 647 r_lastvertvalid = false; 648 continue; 649 } 650 } 651 else 652 { 653 // it's cached if the cached edge is valid and is owned 654 // by this medge_t 655 if ((((unsigned long)edge_p - (unsigned long)r_edges) > 656 r_pedge->cachededgeoffset) && 657 (((edge_t *)((unsigned long)r_edges + 658 r_pedge->cachededgeoffset))->owner == r_pedge)) 659 { 660 R_EmitCachedEdge (); 661 r_lastvertvalid = false; 662 continue; 663 } 664 } 665 } 666 667 // assume it's cacheable 668 cacheoffset = (byte *)edge_p - (byte *)r_edges; 669 r_leftclipped = r_rightclipped = false; 670 R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]], 671 &r_pcurrentvertbase[r_pedge->v[0]], 672 pclip); 673 r_pedge->cachededgeoffset = cacheoffset; 674 675 if (r_leftclipped) 676 makeleftedge = true; 677 if (r_rightclipped) 678 makerightedge = true; 679 r_lastvertvalid = true; 680 } 681 } 682 683 // if there was a clip off the left edge, add that edge too 684 // FIXME: faster to do in screen space? 685 // FIXME: share clipped edges? 686 if (makeleftedge) 687 { 688 r_pedge = &tedge; 689 r_lastvertvalid = false; 690 R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next); 691 } 692 693 // if there was a clip off the right edge, get the right r_nearzi 694 if (makerightedge) 695 { 696 r_pedge = &tedge; 697 r_lastvertvalid = false; 698 r_nearzionly = true; 699 R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); 700 } 701 702 // if no edges made it out, return without posting the surface 703 if (!r_emitted) 704 return; 705 706 r_polycount++; 707 708 surface_p->msurf = fa; 709 surface_p->nearzi = r_nearzi; 710 surface_p->flags = fa->flags; 711 surface_p->insubmodel = insubmodel; 712 surface_p->spanstate = 0; 713 surface_p->entity = currententity; 714 surface_p->key = r_currentkey++; 715 surface_p->spans = NULL; 716 717 pplane = fa->plane; 718 // FIXME: cache this? 719 TransformVector (pplane->normal, p_normal); 720 // FIXME: cache this? 721 distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal)); 722 723 surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; 724 surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; 725 surface_p->d_ziorigin = p_normal[2] * distinv - 726 xcenter * surface_p->d_zistepu - 727 ycenter * surface_p->d_zistepv; 728 729 surface_p++; 730 } 731 732 733 /* 734 ================ 735 R_RenderBmodelFace 736 ================ 737 */ 738 void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf) 739 { 740 int i; 741 unsigned mask; 742 mplane_t *pplane; 743 float distinv; 744 vec3_t p_normal; 745 medge_t tedge; 746 clipplane_t *pclip; 747 748 if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) 749 { 750 psurf->nextalphasurface = r_alpha_surfaces; 751 r_alpha_surfaces = psurf; 752 return; 753 } 754 755 // skip out if no more surfs 756 if (surface_p >= surf_max) 757 { 758 r_outofsurfaces++; 759 return; 760 } 761 762 // ditto if not enough edges left, or switch to auxedges if possible 763 if ((edge_p + psurf->numedges + 4) >= edge_max) 764 { 765 r_outofedges += psurf->numedges; 766 return; 767 } 768 769 c_faceclip++; 770 771 // this is a dummy to give the caching mechanism someplace to write to 772 r_pedge = &tedge; 773 774 // set up clip planes 775 pclip = NULL; 776 777 for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) 778 { 779 if (r_clipflags & mask) 780 { 781 view_clipplanes[i].next = pclip; 782 pclip = &view_clipplanes[i]; 783 } 784 } 785 786 // push the edges through 787 r_emitted = 0; 788 r_nearzi = 0; 789 r_nearzionly = false; 790 makeleftedge = makerightedge = false; 791 // FIXME: keep clipped bmodel edges in clockwise order so last vertex caching 792 // can be used? 793 r_lastvertvalid = false; 794 795 for ( ; pedges ; pedges = pedges->pnext) 796 { 797 r_leftclipped = r_rightclipped = false; 798 R_ClipEdge (pedges->v[0], pedges->v[1], pclip); 799 800 if (r_leftclipped) 801 makeleftedge = true; 802 if (r_rightclipped) 803 makerightedge = true; 804 } 805 806 // if there was a clip off the left edge, add that edge too 807 // FIXME: faster to do in screen space? 808 // FIXME: share clipped edges? 809 if (makeleftedge) 810 { 811 r_pedge = &tedge; 812 R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next); 813 } 814 815 // if there was a clip off the right edge, get the right r_nearzi 816 if (makerightedge) 817 { 818 r_pedge = &tedge; 819 r_nearzionly = true; 820 R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); 821 } 822 823 // if no edges made it out, return without posting the surface 824 if (!r_emitted) 825 return; 826 827 r_polycount++; 828 829 surface_p->msurf = psurf; 830 surface_p->nearzi = r_nearzi; 831 surface_p->flags = psurf->flags; 832 surface_p->insubmodel = true; 833 surface_p->spanstate = 0; 834 surface_p->entity = currententity; 835 surface_p->key = r_currentbkey; 836 surface_p->spans = NULL; 837 838 pplane = psurf->plane; 839 // FIXME: cache this? 840 TransformVector (pplane->normal, p_normal); 841 // FIXME: cache this? 842 distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal)); 843 844 surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; 845 surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; 846 surface_p->d_ziorigin = p_normal[2] * distinv - 847 xcenter * surface_p->d_zistepu - 848 ycenter * surface_p->d_zistepv; 849 850 surface_p++; 851 } 852