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