r_bsp.c (14300B)
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_bsp.c 21 22 #include "r_local.h" 23 24 // 25 // current entity info 26 // 27 qboolean insubmodel; 28 entity_t *currententity; 29 vec3_t modelorg; // modelorg is the viewpoint reletive to 30 // the currently rendering entity 31 vec3_t r_entorigin; // the currently rendering entity in world 32 // coordinates 33 34 float entity_rotation[3][3]; 35 36 int r_currentbkey; 37 38 typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t; 39 40 #define MAX_BMODEL_VERTS 500 // 6K 41 #define MAX_BMODEL_EDGES 1000 // 12K 42 43 static mvertex_t *pbverts; 44 static bedge_t *pbedges; 45 static int numbverts, numbedges; 46 47 static mvertex_t *pfrontenter, *pfrontexit; 48 49 static qboolean makeclippededge; 50 51 52 //=========================================================================== 53 54 /* 55 ================ 56 R_EntityRotate 57 ================ 58 */ 59 void R_EntityRotate (vec3_t vec) 60 { 61 vec3_t tvec; 62 63 VectorCopy (vec, tvec); 64 vec[0] = DotProduct (entity_rotation[0], tvec); 65 vec[1] = DotProduct (entity_rotation[1], tvec); 66 vec[2] = DotProduct (entity_rotation[2], tvec); 67 } 68 69 70 /* 71 ================ 72 R_RotateBmodel 73 ================ 74 */ 75 void R_RotateBmodel (void) 76 { 77 float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3]; 78 79 // TODO: should use a look-up table 80 // TODO: should really be stored with the entity instead of being reconstructed 81 // TODO: could cache lazily, stored in the entity 82 // TODO: share work with R_SetUpAliasTransform 83 84 // yaw 85 angle = currententity->angles[YAW]; 86 angle = angle * M_PI*2 / 360; 87 s = sin(angle); 88 c = cos(angle); 89 90 temp1[0][0] = c; 91 temp1[0][1] = s; 92 temp1[0][2] = 0; 93 temp1[1][0] = -s; 94 temp1[1][1] = c; 95 temp1[1][2] = 0; 96 temp1[2][0] = 0; 97 temp1[2][1] = 0; 98 temp1[2][2] = 1; 99 100 101 // pitch 102 angle = currententity->angles[PITCH]; 103 angle = angle * M_PI*2 / 360; 104 s = sin(angle); 105 c = cos(angle); 106 107 temp2[0][0] = c; 108 temp2[0][1] = 0; 109 temp2[0][2] = -s; 110 temp2[1][0] = 0; 111 temp2[1][1] = 1; 112 temp2[1][2] = 0; 113 temp2[2][0] = s; 114 temp2[2][1] = 0; 115 temp2[2][2] = c; 116 117 R_ConcatRotations (temp2, temp1, temp3); 118 119 // roll 120 angle = currententity->angles[ROLL]; 121 angle = angle * M_PI*2 / 360; 122 s = sin(angle); 123 c = cos(angle); 124 125 temp1[0][0] = 1; 126 temp1[0][1] = 0; 127 temp1[0][2] = 0; 128 temp1[1][0] = 0; 129 temp1[1][1] = c; 130 temp1[1][2] = s; 131 temp1[2][0] = 0; 132 temp1[2][1] = -s; 133 temp1[2][2] = c; 134 135 R_ConcatRotations (temp1, temp3, entity_rotation); 136 137 // 138 // rotate modelorg and the transformation matrix 139 // 140 R_EntityRotate (modelorg); 141 R_EntityRotate (vpn); 142 R_EntityRotate (vright); 143 R_EntityRotate (vup); 144 145 R_TransformFrustum (); 146 } 147 148 149 /* 150 ================ 151 R_RecursiveClipBPoly 152 153 Clip a bmodel poly down the world bsp tree 154 ================ 155 */ 156 void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) 157 { 158 bedge_t *psideedges[2], *pnextedge, *ptedge; 159 int i, side, lastside; 160 float dist, frac, lastdist; 161 mplane_t *splitplane, tplane; 162 mvertex_t *pvert, *plastvert, *ptvert; 163 mnode_t *pn; 164 int area; 165 166 psideedges[0] = psideedges[1] = NULL; 167 168 makeclippededge = false; 169 170 // transform the BSP plane into model space 171 // FIXME: cache these? 172 splitplane = pnode->plane; 173 tplane.dist = splitplane->dist - 174 DotProduct(r_entorigin, splitplane->normal); 175 tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal); 176 tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal); 177 tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal); 178 179 // clip edges to BSP plane 180 for ( ; pedges ; pedges = pnextedge) 181 { 182 pnextedge = pedges->pnext; 183 184 // set the status for the last point as the previous point 185 // FIXME: cache this stuff somehow? 186 plastvert = pedges->v[0]; 187 lastdist = DotProduct (plastvert->position, tplane.normal) - 188 tplane.dist; 189 190 if (lastdist > 0) 191 lastside = 0; 192 else 193 lastside = 1; 194 195 pvert = pedges->v[1]; 196 197 dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; 198 199 if (dist > 0) 200 side = 0; 201 else 202 side = 1; 203 204 if (side != lastside) 205 { 206 // clipped 207 if (numbverts >= MAX_BMODEL_VERTS) 208 return; 209 210 // generate the clipped vertex 211 frac = lastdist / (lastdist - dist); 212 ptvert = &pbverts[numbverts++]; 213 ptvert->position[0] = plastvert->position[0] + 214 frac * (pvert->position[0] - 215 plastvert->position[0]); 216 ptvert->position[1] = plastvert->position[1] + 217 frac * (pvert->position[1] - 218 plastvert->position[1]); 219 ptvert->position[2] = plastvert->position[2] + 220 frac * (pvert->position[2] - 221 plastvert->position[2]); 222 223 // split into two edges, one on each side, and remember entering 224 // and exiting points 225 // FIXME: share the clip edge by having a winding direction flag? 226 if (numbedges >= (MAX_BMODEL_EDGES - 1)) 227 { 228 ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n"); 229 return; 230 } 231 232 ptedge = &pbedges[numbedges]; 233 ptedge->pnext = psideedges[lastside]; 234 psideedges[lastside] = ptedge; 235 ptedge->v[0] = plastvert; 236 ptedge->v[1] = ptvert; 237 238 ptedge = &pbedges[numbedges + 1]; 239 ptedge->pnext = psideedges[side]; 240 psideedges[side] = ptedge; 241 ptedge->v[0] = ptvert; 242 ptedge->v[1] = pvert; 243 244 numbedges += 2; 245 246 if (side == 0) 247 { 248 // entering for front, exiting for back 249 pfrontenter = ptvert; 250 makeclippededge = true; 251 } 252 else 253 { 254 pfrontexit = ptvert; 255 makeclippededge = true; 256 } 257 } 258 else 259 { 260 // add the edge to the appropriate side 261 pedges->pnext = psideedges[side]; 262 psideedges[side] = pedges; 263 } 264 } 265 266 // if anything was clipped, reconstitute and add the edges along the clip 267 // plane to both sides (but in opposite directions) 268 if (makeclippededge) 269 { 270 if (numbedges >= (MAX_BMODEL_EDGES - 2)) 271 { 272 ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n"); 273 return; 274 } 275 276 ptedge = &pbedges[numbedges]; 277 ptedge->pnext = psideedges[0]; 278 psideedges[0] = ptedge; 279 ptedge->v[0] = pfrontexit; 280 ptedge->v[1] = pfrontenter; 281 282 ptedge = &pbedges[numbedges + 1]; 283 ptedge->pnext = psideedges[1]; 284 psideedges[1] = ptedge; 285 ptedge->v[0] = pfrontenter; 286 ptedge->v[1] = pfrontexit; 287 288 numbedges += 2; 289 } 290 291 // draw or recurse further 292 for (i=0 ; i<2 ; i++) 293 { 294 if (psideedges[i]) 295 { 296 // draw if we've reached a non-solid leaf, done if all that's left is a 297 // solid leaf, and continue down the tree if it's not a leaf 298 pn = pnode->children[i]; 299 300 // we're done with this branch if the node or leaf isn't in the PVS 301 if (pn->visframe == r_visframecount) 302 { 303 if (pn->contents != CONTENTS_NODE) 304 { 305 if (pn->contents != CONTENTS_SOLID) 306 { 307 if (r_newrefdef.areabits) 308 { 309 area = ((mleaf_t *)pn)->area; 310 if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) ) 311 continue; // not visible 312 } 313 314 r_currentbkey = ((mleaf_t *)pn)->key; 315 R_RenderBmodelFace (psideedges[i], psurf); 316 } 317 } 318 else 319 { 320 R_RecursiveClipBPoly (psideedges[i], pnode->children[i], 321 psurf); 322 } 323 } 324 } 325 } 326 } 327 328 329 /* 330 ================ 331 R_DrawSolidClippedSubmodelPolygons 332 333 Bmodel crosses multiple leafs 334 ================ 335 */ 336 void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode) 337 { 338 int i, j, lindex; 339 vec_t dot; 340 msurface_t *psurf; 341 int numsurfaces; 342 mplane_t *pplane; 343 mvertex_t bverts[MAX_BMODEL_VERTS]; 344 bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; 345 medge_t *pedge, *pedges; 346 347 // FIXME: use bounding-box-based frustum clipping info? 348 349 psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; 350 numsurfaces = pmodel->nummodelsurfaces; 351 pedges = pmodel->edges; 352 353 for (i=0 ; i<numsurfaces ; i++, psurf++) 354 { 355 // find which side of the node we are on 356 pplane = psurf->plane; 357 358 dot = DotProduct (modelorg, pplane->normal) - pplane->dist; 359 360 // draw the polygon 361 if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || 362 ((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) 363 continue; 364 365 // FIXME: use bounding-box-based frustum clipping info? 366 367 // copy the edges to bedges, flipping if necessary so always 368 // clockwise winding 369 // FIXME: if edges and vertices get caches, these assignments must move 370 // outside the loop, and overflow checking must be done here 371 pbverts = bverts; 372 pbedges = bedges; 373 numbverts = numbedges = 0; 374 pbedge = &bedges[numbedges]; 375 numbedges += psurf->numedges; 376 377 for (j=0 ; j<psurf->numedges ; j++) 378 { 379 lindex = pmodel->surfedges[psurf->firstedge+j]; 380 381 if (lindex > 0) 382 { 383 pedge = &pedges[lindex]; 384 pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]]; 385 pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]]; 386 } 387 else 388 { 389 lindex = -lindex; 390 pedge = &pedges[lindex]; 391 pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]]; 392 pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]]; 393 } 394 395 pbedge[j].pnext = &pbedge[j+1]; 396 } 397 398 pbedge[j-1].pnext = NULL; // mark end of edges 399 400 if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) ) 401 R_RecursiveClipBPoly (pbedge, topnode, psurf); 402 else 403 R_RenderBmodelFace( pbedge, psurf ); 404 } 405 } 406 407 408 /* 409 ================ 410 R_DrawSubmodelPolygons 411 412 All in one leaf 413 ================ 414 */ 415 void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode) 416 { 417 int i; 418 vec_t dot; 419 msurface_t *psurf; 420 int numsurfaces; 421 mplane_t *pplane; 422 423 // FIXME: use bounding-box-based frustum clipping info? 424 425 psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; 426 numsurfaces = pmodel->nummodelsurfaces; 427 428 for (i=0 ; i<numsurfaces ; i++, psurf++) 429 { 430 // find which side of the node we are on 431 pplane = psurf->plane; 432 433 dot = DotProduct (modelorg, pplane->normal) - pplane->dist; 434 435 // draw the polygon 436 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || 437 (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) 438 { 439 r_currentkey = ((mleaf_t *)topnode)->key; 440 441 // FIXME: use bounding-box-based frustum clipping info? 442 R_RenderFace (psurf, clipflags); 443 } 444 } 445 } 446 447 448 int c_drawnode; 449 450 /* 451 ================ 452 R_RecursiveWorldNode 453 ================ 454 */ 455 void R_RecursiveWorldNode (mnode_t *node, int clipflags) 456 { 457 int i, c, side, *pindex; 458 vec3_t acceptpt, rejectpt; 459 mplane_t *plane; 460 msurface_t *surf, **mark; 461 float d, dot; 462 mleaf_t *pleaf; 463 464 if (node->contents == CONTENTS_SOLID) 465 return; // solid 466 467 if (node->visframe != r_visframecount) 468 return; 469 470 // cull the clipping planes if not trivial accept 471 // FIXME: the compiler is doing a lousy job of optimizing here; it could be 472 // twice as fast in ASM 473 if (clipflags) 474 { 475 for (i=0 ; i<4 ; i++) 476 { 477 if (! (clipflags & (1<<i)) ) 478 continue; // don't need to clip against it 479 480 // generate accept and reject points 481 // FIXME: do with fast look-ups or integer tests based on the sign bit 482 // of the floating point values 483 484 pindex = pfrustum_indexes[i]; 485 486 rejectpt[0] = (float)node->minmaxs[pindex[0]]; 487 rejectpt[1] = (float)node->minmaxs[pindex[1]]; 488 rejectpt[2] = (float)node->minmaxs[pindex[2]]; 489 490 d = DotProduct (rejectpt, view_clipplanes[i].normal); 491 d -= view_clipplanes[i].dist; 492 if (d <= 0) 493 return; 494 acceptpt[0] = (float)node->minmaxs[pindex[3+0]]; 495 acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; 496 acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; 497 498 d = DotProduct (acceptpt, view_clipplanes[i].normal); 499 d -= view_clipplanes[i].dist; 500 501 if (d >= 0) 502 clipflags &= ~(1<<i); // node is entirely on screen 503 } 504 } 505 506 c_drawnode++; 507 508 // if a leaf node, draw stuff 509 if (node->contents != -1) 510 { 511 pleaf = (mleaf_t *)node; 512 513 // check for door connected areas 514 if (r_newrefdef.areabits) 515 { 516 if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) ) 517 return; // not visible 518 } 519 520 mark = pleaf->firstmarksurface; 521 c = pleaf->nummarksurfaces; 522 523 if (c) 524 { 525 do 526 { 527 (*mark)->visframe = r_framecount; 528 mark++; 529 } while (--c); 530 } 531 532 pleaf->key = r_currentkey; 533 r_currentkey++; // all bmodels in a leaf share the same key 534 } 535 else 536 { 537 // node is just a decision point, so go down the apropriate sides 538 539 // find which side of the node we are on 540 plane = node->plane; 541 542 switch (plane->type) 543 { 544 case PLANE_X: 545 dot = modelorg[0] - plane->dist; 546 break; 547 case PLANE_Y: 548 dot = modelorg[1] - plane->dist; 549 break; 550 case PLANE_Z: 551 dot = modelorg[2] - plane->dist; 552 break; 553 default: 554 dot = DotProduct (modelorg, plane->normal) - plane->dist; 555 break; 556 } 557 558 if (dot >= 0) 559 side = 0; 560 else 561 side = 1; 562 563 // recurse down the children, front side first 564 R_RecursiveWorldNode (node->children[side], clipflags); 565 566 // draw stuff 567 c = node->numsurfaces; 568 569 if (c) 570 { 571 surf = r_worldmodel->surfaces + node->firstsurface; 572 573 if (dot < -BACKFACE_EPSILON) 574 { 575 do 576 { 577 if ((surf->flags & SURF_PLANEBACK) && 578 (surf->visframe == r_framecount)) 579 { 580 R_RenderFace (surf, clipflags); 581 } 582 583 surf++; 584 } while (--c); 585 } 586 else if (dot > BACKFACE_EPSILON) 587 { 588 do 589 { 590 if (!(surf->flags & SURF_PLANEBACK) && 591 (surf->visframe == r_framecount)) 592 { 593 R_RenderFace (surf, clipflags); 594 } 595 596 surf++; 597 } while (--c); 598 } 599 600 // all surfaces on the same node share the same sequence number 601 r_currentkey++; 602 } 603 604 // recurse down the back side 605 R_RecursiveWorldNode (node->children[!side], clipflags); 606 } 607 } 608 609 610 611 /* 612 ================ 613 R_RenderWorld 614 ================ 615 */ 616 void R_RenderWorld (void) 617 { 618 619 if (!r_drawworld->value) 620 return; 621 if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) 622 return; 623 624 c_drawnode=0; 625 626 // auto cycle the world frame for texture animation 627 r_worldentity.frame = (int)(r_newrefdef.time*2); 628 currententity = &r_worldentity; 629 630 VectorCopy (r_origin, modelorg); 631 currentmodel = r_worldmodel; 632 r_pcurrentvertbase = currentmodel->vertexes; 633 634 R_RecursiveWorldNode (currentmodel->nodes, 15); 635 } 636 637