vxllayer.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** 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, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /Commando/Code/Tools/max2w3d/vxllayer.cpp 4 10/28/97 6:08p Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G *
  24. * *
  25. * File Name : VXLLAYER.CPP *
  26. * *
  27. * Programmer : Greg Hjelstrom *
  28. * *
  29. * Start Date : 06/10/97 *
  30. * *
  31. * Last Update : June 10, 1997 [GH] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * VoxelLayerClass::VoxelLayerClass -- Constructor for VoxelLayerClass *
  36. * VoxelLayerClass::Intersect_Triangle -- Intersect a triangle with the slab *
  37. * VoxelLayerClass::Draw_Line -- Draw a line of voxels into the slab *
  38. * VoxelLayerClass::Scan_Triangle -- Clip and scan-convert a triangle into the slab *
  39. * clip_tri_to_slab -- Clips a triangle against a voxel slab *
  40. * clip_poly -- clip a polygon against a single 3D plane *
  41. * output -- Emit a vertex into a polygons vertex list *
  42. * inside -- Test whether a point is in the front half-space of a plane *
  43. * intersect -- compute intersection between a line and a plane *
  44. * clear_scan_table -- clears the static scanline table *
  45. * fixup_scan_table -- ensure all spans are left->right in order *
  46. * scan_edge -- Scan convert an edge *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #include "vxllayer.h"
  49. #include "plane.h"
  50. /***************************************************************************************
  51. ** local types
  52. ***************************************************************************************/
  53. struct vertexstruct
  54. {
  55. Point3 Pos;
  56. Point3 Bary;
  57. };
  58. struct scanstruct
  59. {
  60. vertexstruct P[2];
  61. };
  62. /***************************************************************************************
  63. ** static data
  64. ***************************************************************************************/
  65. static scanstruct _scantab[256];
  66. const int LEFT = 0;
  67. const int RIGHT = 1;
  68. const float EMPTY_SPAN = -10000.0f;
  69. /***************************************************************************************
  70. ** local functions
  71. ***************************************************************************************/
  72. static void clip_tri_to_slab(
  73. Point3 p0,
  74. Point3 p1,
  75. Point3 p2,
  76. float z0,
  77. float z1,
  78. vertexstruct * outverts,
  79. int * setnum);
  80. static void clip_poly(
  81. vertexstruct * inverts,
  82. int innum,
  83. vertexstruct * outverts,
  84. int * outnum,
  85. const PlaneClass & clipplane);
  86. static void output(
  87. const vertexstruct & outvert,
  88. vertexstruct * poly,
  89. int * numverts);
  90. static int inside(
  91. const vertexstruct & p,
  92. const PlaneClass & plane);
  93. static vertexstruct intersect(
  94. const vertexstruct & p0,
  95. const vertexstruct & p1,
  96. const PlaneClass & plane);
  97. static void clear_scan_table(void);
  98. static void fixup_scan_table(
  99. int y0,
  100. int y1);
  101. static void scan_edge(
  102. const vertexstruct & p0,
  103. const vertexstruct & p1);
  104. /***********************************************************************************************
  105. * VoxelLayerClass::VoxelLayerClass -- Constructor for VoxelLayerClass *
  106. * *
  107. * INPUT: *
  108. * *
  109. * OUTPUT: *
  110. * *
  111. * WARNINGS: *
  112. * *
  113. * HISTORY: *
  114. * 06/10/1997 GH : Created. *
  115. *=============================================================================================*/
  116. VoxelLayerClass::VoxelLayerClass
  117. (
  118. INodeListClass & object_list,
  119. TimeValue time,
  120. Matrix3 parenttm,
  121. Point3 offset,
  122. Point3 scale,
  123. float slicez,
  124. float sliceh,
  125. int bmwidth,
  126. int bmheight
  127. )
  128. {
  129. unsigned i;
  130. SliceZ = slicez;
  131. SliceH = sliceh;
  132. SliceZ0 = slicez - sliceh / 2;
  133. SliceZ1 = slicez + sliceh / 2;
  134. bitmap_width = bmwidth;
  135. bitmap_height = bmheight;
  136. // Initialize everything with zero
  137. memset ( &(Solid[0][0]), 0, sizeof(Solid));
  138. // Go through the list of objects and intersect them with the plane.
  139. for ( i = 0; i < object_list.Num_Nodes(); i++ )
  140. {
  141. // Get relavent data from MAX
  142. INode * inode = object_list[i];
  143. Object * obj = inode->EvalWorldState(time).obj;
  144. TriObject * tri = (TriObject *)obj->ConvertToType(time, triObjectClassID);
  145. Mesh * mesh = &(tri->mesh);
  146. Matrix3 objtm = inode->GetObjectTM(time);
  147. // Compute a delta matrix which puts vertices into the parent space
  148. Matrix3 delta = objtm * Inverse(parenttm);
  149. // Loop through each face, intersecting it with the slice.
  150. unsigned faces = mesh->getNumFaces();
  151. for ( unsigned face_index = 0; face_index < faces; ++ face_index )
  152. {
  153. Face & face = mesh->faces [ face_index ];
  154. // transform the vertices into the parent space
  155. Point3 a = mesh->verts [ face.v[0] ] * delta;
  156. Point3 b = mesh->verts [ face.v[1] ] * delta;
  157. Point3 c = mesh->verts [ face.v[2] ] * delta;
  158. // shift the vertices to the origin
  159. a.x -= offset.x;
  160. a.y -= offset.y;
  161. b.x -= offset.x;
  162. b.y -= offset.y;
  163. c.x -= offset.x;
  164. c.y -= offset.y;
  165. // scale the vertices into the voxel grid
  166. a.x *= scale.x;
  167. a.y *= scale.y;
  168. b.x *= scale.x;
  169. b.y *= scale.y;
  170. c.x *= scale.x;
  171. c.y *= scale.y;
  172. // Intersect_Triangle ( a, b, c, SliceZ );
  173. Scan_Triangle( a, b, c );
  174. }
  175. }
  176. }
  177. /***********************************************************************************************
  178. * VoxelLayerClass::Intersect_Triangle -- Intersect a triangle with the slab *
  179. * *
  180. * INPUT: *
  181. * *
  182. * OUTPUT: *
  183. * *
  184. * WARNINGS: *
  185. * *
  186. * HISTORY: *
  187. * 06/10/1997 GH : Created. *
  188. *=============================================================================================*/
  189. void VoxelLayerClass::Intersect_Triangle
  190. (
  191. Point3 a,
  192. Point3 b,
  193. Point3 c,
  194. float z
  195. )
  196. {
  197. double start_x, start_y, end_x, end_y;
  198. // If the triangle is wholly above or below the intersection plane,
  199. // it does not intersect with the plane.
  200. if ( a.z < z && b.z < z && c.z < z )
  201. return;
  202. if ( a.z > z && b.z > z && c.z > z )
  203. return;
  204. // Find the upward intersection moving counterclockwise. This will be
  205. // the start of the edge.
  206. if ( a.z < z && b.z >= z )
  207. {
  208. start_x = a.x + (b.x - a.x) * (z - a.z) / (b.z - a.z);
  209. start_y = a.y + (b.y - a.y) * (z - a.z) / (b.z - a.z);
  210. }
  211. else if ( b.z < z && c.z >= z )
  212. {
  213. start_x = b.x + (c.x - b.x) * (z - b.z) / (c.z - b.z);
  214. start_y = b.y + (c.y - b.y) * (z - b.z) / (c.z - b.z);
  215. }
  216. else if ( c.z < z && a.z >= z )
  217. {
  218. start_x = c.x + (a.x - c.x) * (z - c.z) / (a.z - c.z);
  219. start_y = c.y + (a.y - c.y) * (z - c.z) / (a.z - c.z);
  220. }
  221. else
  222. {
  223. return;
  224. }
  225. // Find the downward intersection moving counterclockwise. This is the end
  226. // of the edge.
  227. if ( a.z >= z && b.z < z )
  228. {
  229. end_x = a.x + (b.x - a.x) * (z - a.z) / (b.z - a.z);
  230. end_y = a.y + (b.y - a.y) * (z - a.z) / (b.z - a.z);
  231. }
  232. else if ( b.z >= z && c.z < z )
  233. {
  234. end_x = b.x + (c.x - b.x) * (z - b.z) / (c.z - b.z);
  235. end_y = b.y + (c.y - b.y) * (z - b.z) / (c.z - b.z);
  236. }
  237. else if ( c.z >= z && a.z < z )
  238. {
  239. end_x = c.x + (a.x - c.x) * (z - c.z) / (a.z - c.z);
  240. end_y = c.y + (a.y - c.y) * (z - c.z) / (a.z - c.z);
  241. }
  242. else
  243. {
  244. return;
  245. }
  246. // Draw the edge into the bitmap.
  247. Draw_Line(start_x, start_y, end_x, end_y);
  248. }
  249. /***********************************************************************************************
  250. * VoxelLayerClass::Draw_Line -- Draw a line of voxels into the slab *
  251. * *
  252. * INPUT: *
  253. * *
  254. * OUTPUT: *
  255. * *
  256. * WARNINGS: *
  257. * *
  258. * HISTORY: *
  259. * 06/10/1997 GH : Created. *
  260. *=============================================================================================*/
  261. void VoxelLayerClass::Draw_Line
  262. (
  263. double x0,
  264. double y0,
  265. double x1,
  266. double y1
  267. )
  268. {
  269. // Fill in the squares containing the line's endpoints.
  270. Add_Solid((int)x0, (int)y0);
  271. Add_Solid((int)x1, (int)y1);
  272. // Fill in the squares between the endpoints.
  273. double delta_x = fabs (x1 - x0);
  274. double delta_y = fabs (y1 - y0);
  275. if ( delta_x > delta_y )
  276. {
  277. // This is an X-major line.
  278. if ( x0 > x1 )
  279. {
  280. double temp = x0;
  281. x0 = x1;
  282. x1 = temp;
  283. temp = y0;
  284. y0 = y1;
  285. y1 = temp;
  286. }
  287. double step_y = (y1 - y0) / delta_x;
  288. double y = y0 + step_y * (floor (x0 + 1) - x0);
  289. for ( int x = (int) x0; x < (int) x1; ++ x )
  290. {
  291. if ( (int) y >= 0 && (int) y < bitmap_height )
  292. {
  293. Add_Solid(x, (int)y);
  294. Add_Solid(x + 1, (int)y);
  295. }
  296. y += step_y;
  297. }
  298. }
  299. else
  300. {
  301. // This is a Y-major line.
  302. if ( y0 > y1 )
  303. {
  304. double temp = x0;
  305. x0 = x1;
  306. x1 = temp;
  307. temp = y0;
  308. y0 = y1;
  309. y1 = temp;
  310. }
  311. double step_x = (x1 - x0) / delta_y;
  312. double x = x0 + step_x * (floor (y0 + 1) - y0);
  313. for ( int y = (int) y0; y < (int) y1; ++ y )
  314. {
  315. if ( (int) x >= 0 && (int) x < 256 )
  316. {
  317. Add_Solid((int)x, y);
  318. Add_Solid((int)x, y+1);
  319. }
  320. }
  321. }
  322. }
  323. /***********************************************************************************************
  324. * VoxelLayerClass::Scan_Triangle -- Clip and scan-convert a triangle into the slab *
  325. * *
  326. * INPUT: *
  327. * *
  328. * OUTPUT: *
  329. * *
  330. * WARNINGS: *
  331. * *
  332. * HISTORY: *
  333. * 06/10/1997 GH : Created. *
  334. *=============================================================================================*/
  335. void VoxelLayerClass::Scan_Triangle
  336. (
  337. Point3 p0,
  338. Point3 p1,
  339. Point3 p2
  340. )
  341. {
  342. int i;
  343. // check if the entire triangle is above or below the slab:
  344. if (p0.z < SliceZ0 && p1.z < SliceZ0 && p2.z < SliceZ1) return;
  345. if (p0.z > SliceZ1 && p1.z > SliceZ1 && p2.z > SliceZ1) return;
  346. // clip the triangle to the slab
  347. vertexstruct polyvert[8];
  348. int numverts;
  349. clip_tri_to_slab(p0,p1,p2,SliceZ0,SliceZ1,polyvert,&numverts);
  350. if (numverts == 0) return;
  351. // clear the scanline table, get y-extents of polygon
  352. clear_scan_table();
  353. float miny = polyvert[0].Pos.y;
  354. float maxy = polyvert[0].Pos.y;
  355. for (i=1; i<numverts; i++) {
  356. if (polyvert[i].Pos.y < miny) miny = polyvert[i].Pos.y;
  357. if (polyvert[i].Pos.y > maxy) maxy = polyvert[i].Pos.y;
  358. }
  359. // scanconvert the triangle
  360. int start = numverts - 1;
  361. for (i=0; i<numverts; i++) {
  362. scan_edge(polyvert[start],polyvert[i]);
  363. start = i;
  364. }
  365. // make sure all scans go left-right.
  366. fixup_scan_table((int)floor(miny),(int)floor(maxy));
  367. // draw the scanlines
  368. for (i=(int)floor(miny); i<=(int)floor(maxy); i++) {
  369. // if (_scantab[i].P[LEFT].Pos.x != EMPTY_SPAN) {
  370. Draw_Line(
  371. _scantab[i].P[LEFT].Pos.x,
  372. _scantab[i].P[LEFT].Pos.y,
  373. _scantab[i].P[RIGHT].Pos.x,
  374. _scantab[i].P[RIGHT].Pos.y);
  375. // }
  376. }
  377. }
  378. /***********************************************************************************************
  379. * clip_tri_to_slab -- Clips a triangle against a voxel slab *
  380. * *
  381. * INPUT: *
  382. * *
  383. * OUTPUT: *
  384. * *
  385. * WARNINGS: *
  386. * *
  387. * HISTORY: *
  388. * 06/10/1997 GH : Created. *
  389. *=============================================================================================*/
  390. static void clip_tri_to_slab
  391. (
  392. Point3 p0,
  393. Point3 p1,
  394. Point3 p2,
  395. float z0,
  396. float z1,
  397. vertexstruct * outverts,
  398. int * setnum
  399. )
  400. {
  401. static vertexstruct tmpverts[8];
  402. memset(outverts,0,sizeof(outverts));
  403. memset(tmpverts,0,sizeof(tmpverts));
  404. // copy the three intial points:
  405. outverts[0].Pos = p0;
  406. outverts[1].Pos = p1;
  407. outverts[2].Pos = p2;
  408. outverts[0].Bary = Point3(1.0f,0.0f,0.0f);
  409. outverts[1].Bary = Point3(0.0f,1.0f,0.0f);
  410. outverts[2].Bary = Point3(0.0f,0.0f,1.0f);
  411. // clip from the out buffer to the tmp buffer against bottom of slab:
  412. clip_poly(outverts,3,tmpverts,setnum,PlaneClass(Vector3(0.0f,0.0f,1.0f),-z0));
  413. // clip from the tmp buffer to the out buffer against top of slab:
  414. clip_poly(tmpverts,*setnum,outverts,setnum,PlaneClass(Vector3(0.0f,0.0f,-1.0f),z1));
  415. }
  416. /***********************************************************************************************
  417. * clip_poly -- clip a polygon against a single 3D plane *
  418. * *
  419. * INPUT: *
  420. * *
  421. * OUTPUT: *
  422. * *
  423. * WARNINGS: *
  424. * *
  425. * HISTORY: *
  426. * 06/10/1997 GH : Created. *
  427. *=============================================================================================*/
  428. static void clip_poly
  429. (
  430. vertexstruct * inverts,
  431. int innum,
  432. vertexstruct * outverts,
  433. int * outnum,
  434. const PlaneClass & clipplane
  435. )
  436. {
  437. vertexstruct p0,p1; // start and end of current edge
  438. vertexstruct pi; // intersection point
  439. int i;
  440. // start with zero vertices
  441. *outnum = 0;
  442. p0 = inverts[innum-1];
  443. for (i=0; i<innum; i++) {
  444. p1 = inverts[i];
  445. if (inside(p1,clipplane)) {
  446. if (inside(p0,clipplane)) {
  447. output(p1,outverts,outnum); //both inside: output p1
  448. } else {
  449. pi = intersect(p0,p1,clipplane);
  450. output(pi,outverts,outnum); //p0 out, p1 in: output intersect and p1
  451. output(p1,outverts,outnum);
  452. }
  453. } else {
  454. if (inside(p0,clipplane)) {
  455. pi = intersect(p0,p1,clipplane); //p0 in, p1 out: output intersect
  456. output(pi,outverts,outnum);
  457. }
  458. }
  459. p0 = p1;
  460. }
  461. }
  462. /***********************************************************************************************
  463. * output -- Emit a vertex into a polygons vertex list *
  464. * *
  465. * INPUT: *
  466. * *
  467. * OUTPUT: *
  468. * *
  469. * WARNINGS: *
  470. * *
  471. * HISTORY: *
  472. * 06/10/1997 GH : Created. *
  473. *=============================================================================================*/
  474. static void output
  475. (
  476. const vertexstruct & outvert,
  477. vertexstruct * poly,
  478. int * numverts
  479. )
  480. {
  481. poly[*numverts] = outvert;
  482. (*numverts)++;
  483. }
  484. /***********************************************************************************************
  485. * inside -- Test whether a point is in the front half-space of a plane *
  486. * *
  487. * INPUT: *
  488. * *
  489. * OUTPUT: *
  490. * *
  491. * WARNINGS: *
  492. * *
  493. * HISTORY: *
  494. * 06/10/1997 GH : Created. *
  495. *=============================================================================================*/
  496. static int inside
  497. (
  498. const vertexstruct & p,
  499. const PlaneClass & plane
  500. )
  501. {
  502. float dist = p.Pos.x * plane.N[0] + p.Pos.y * plane.N[1] + p.Pos.z * plane.N[2] + plane.D;
  503. if (dist >= 0.0f) {
  504. return 1;
  505. } else {
  506. return 0;
  507. }
  508. }
  509. /***********************************************************************************************
  510. * intersect -- compute intersection between a line and a plane *
  511. * *
  512. * INPUT: *
  513. * *
  514. * OUTPUT: *
  515. * *
  516. * WARNINGS: *
  517. * *
  518. * HISTORY: *
  519. * 06/10/1997 GH : Created. *
  520. *=============================================================================================*/
  521. static vertexstruct intersect
  522. (
  523. const vertexstruct & p0,
  524. const vertexstruct & p1,
  525. const PlaneClass & plane
  526. )
  527. {
  528. float t;
  529. Point3 delta = p1.Pos - p0.Pos;
  530. float num = -( plane.N[0] * p0.Pos.x +
  531. plane.N[1] * p0.Pos.y +
  532. plane.N[2] * p0.Pos.z + plane.D );
  533. float den = plane.N[0] * delta.x +
  534. plane.N[1] * delta.y +
  535. plane.N[2] * delta.z;
  536. if (den != 0.0f) {
  537. t = num / den;
  538. } else {
  539. t = 0.0f;
  540. }
  541. vertexstruct i;
  542. i.Pos = (1.0f - t) * p0.Pos + t*p1.Pos;
  543. i.Bary = (1.0f - t) * p0.Bary + t*p1.Bary;
  544. return i;
  545. }
  546. /***********************************************************************************************
  547. * clear_scan_table -- clears the static scanline table *
  548. * *
  549. * INPUT: *
  550. * *
  551. * OUTPUT: *
  552. * *
  553. * WARNINGS: *
  554. * *
  555. * HISTORY: *
  556. * 06/10/1997 GH : Created. *
  557. *=============================================================================================*/
  558. static void clear_scan_table(void)
  559. {
  560. memset(_scantab,0,sizeof(_scantab));
  561. for (int i=0; i<256; i++) {
  562. _scantab[i].P[0].Pos.x = EMPTY_SPAN;
  563. _scantab[i].P[1].Pos.x = EMPTY_SPAN;
  564. }
  565. }
  566. /***********************************************************************************************
  567. * fixup_scan_table -- ensure all spans are left->right in order *
  568. * *
  569. * INPUT: *
  570. * *
  571. * OUTPUT: *
  572. * *
  573. * WARNINGS: *
  574. * *
  575. * HISTORY: *
  576. * 06/10/1997 GH : Created. *
  577. *=============================================================================================*/
  578. static void fixup_scan_table(int y0,int y1)
  579. {
  580. int i;
  581. assert(y1 >= y0);
  582. // Ensure the left -> right convention is followed.
  583. for (i=y0; i<=y1; i++) {
  584. if (_scantab[i].P[LEFT].Pos.x > _scantab[i].P[RIGHT].Pos.x) {
  585. vertexstruct tmp = _scantab[i].P[LEFT];
  586. _scantab[i].P[LEFT] = _scantab[i].P[RIGHT];
  587. _scantab[i].P[RIGHT] = tmp;
  588. }
  589. }
  590. // Ensure that we leave no gaps.
  591. for (i=y0; i<y1; i++) {
  592. if (_scantab[i+1].P[RIGHT].Pos.x < _scantab[i].P[LEFT].Pos.x) {
  593. _scantab[i+1].P[RIGHT].Pos.x = _scantab[i].P[LEFT].Pos.x;
  594. } else if (_scantab[i+1].P[LEFT].Pos.x > _scantab[i].P[RIGHT].Pos.x) {
  595. _scantab[i+1].P[LEFT].Pos.x = _scantab[i].P[RIGHT].Pos.x;
  596. }
  597. }
  598. }
  599. /***********************************************************************************************
  600. * scan_edge -- Scan convert an edge *
  601. * *
  602. * INPUT: *
  603. * *
  604. * OUTPUT: *
  605. * *
  606. * WARNINGS: *
  607. * *
  608. * HISTORY: *
  609. * 06/10/1997 GH : Created. *
  610. *=============================================================================================*/
  611. static void scan_edge
  612. (
  613. const vertexstruct & p0,
  614. const vertexstruct & p1
  615. )
  616. {
  617. // is this a perfectly horizontal edge:
  618. if (floor(p0.Pos.y) == floor(p1.Pos.y)) {
  619. int si = (int)floor(p0.Pos.y);
  620. const vertexstruct *left, *right;
  621. if (p0.Pos.x < p1.Pos.x) {
  622. left = &p0;
  623. right = &p1;
  624. } else {
  625. left = &p1;
  626. right = &p0;
  627. }
  628. // does this scanline already have a span in it?
  629. if (_scantab[si].P[0].Pos.x != EMPTY_SPAN) {
  630. // yes, expand this scanline's span to include this span
  631. if (left->Pos.x < _scantab[si].P[LEFT].Pos.x) {
  632. _scantab[si].P[LEFT] = *left;
  633. }
  634. if (right->Pos.x > _scantab[si].P[RIGHT].Pos.x) {
  635. _scantab[si].P[RIGHT] = *right;
  636. }
  637. } else {
  638. // no, set this scanline with the span for this edge
  639. _scantab[si].P[LEFT] = *left;
  640. _scantab[si].P[RIGHT] = *right;
  641. }
  642. return;
  643. }
  644. // is this a left or right edge:
  645. int side;
  646. const vertexstruct *top, *bot;
  647. if (p0.Pos.y < p1.Pos.y) {
  648. side = RIGHT;
  649. top = &p0;
  650. bot = &p1;
  651. } else {
  652. side = LEFT;
  653. top = &p1;
  654. bot = &p0;
  655. }
  656. // scan the edge into _scantab
  657. for (double y = floor(top->Pos.y); y <= floor(bot->Pos.y); y += 1.0f) {
  658. // parametric position on the scanline:
  659. double t = (y - floor(top->Pos.y)) / (floor(bot->Pos.y) - floor(top->Pos.y));
  660. // position:
  661. _scantab[(int)y].P[side].Pos = (1.0f - (float)t)*top->Pos + (float)t*bot->Pos;
  662. // barycentric coords:
  663. _scantab[(int)y].P[side].Bary = (1.0f - (float)t)*top->Bary + (float)t*bot->Bary;
  664. }
  665. }