r_draw.c 20 KB

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