visrasterizer.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. /*
  2. ** Command & Conquer Generals(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. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : ww3d *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/visrasterizer.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Greg_h $*
  29. * *
  30. * $Modtime:: 5/17/01 10:41a $*
  31. * *
  32. * $Revision:: 9 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "visrasterizer.h"
  38. #include "camera.h"
  39. #include "plane.h"
  40. #include "vp.h"
  41. /**
  42. ** VisPolyClass - This class is used to clip polygons as they are
  43. ** sent through the vis rasterization system
  44. */
  45. class VisPolyClass
  46. {
  47. public:
  48. void Reset(void);
  49. void Add_Vertex(const Vector3 & point);
  50. void Clip(const PlaneClass & plane,VisPolyClass & dest) const;
  51. SimpleDynVecClass<Vector3> Verts;
  52. };
  53. void VisPolyClass::Reset(void)
  54. {
  55. Verts.Delete_All(false);
  56. }
  57. void VisPolyClass::Add_Vertex(const Vector3 & point)
  58. {
  59. Verts.Add(point);
  60. }
  61. void VisPolyClass::Clip(const PlaneClass & plane,VisPolyClass & dest) const
  62. {
  63. dest.Reset();
  64. // temporary variables used in clipping
  65. int i = 0;
  66. int vcount = Verts.Count();
  67. int iprev = vcount - 1;
  68. bool cur_point_in_front;
  69. bool prev_point_in_front;
  70. float alpha;
  71. Vector3 int_point;
  72. if (vcount <= 2) return;
  73. // perform clipping
  74. prev_point_in_front = !plane.In_Front(Verts[iprev]); // Note, plane normal is outward so we invert this test
  75. for (int j=0; j<vcount; j++) {
  76. cur_point_in_front = !plane.In_Front(Verts[i]); // Note, plane nomral is out so we invert this test
  77. if (prev_point_in_front) {
  78. if (cur_point_in_front) {
  79. // Previous vertex was in front of plane and this vertex is in
  80. // front of the plane so we emit this vertex.
  81. dest.Add_Vertex(Verts[i]);
  82. } else {
  83. // Previous vert was in front, this vert is behind, compute
  84. // the intersection and emit the point.
  85. plane.Compute_Intersection(Verts[iprev],Verts[i],&alpha);
  86. Vector3::Lerp(Verts[iprev],Verts[i],alpha,&int_point);
  87. dest.Add_Vertex(int_point);
  88. }
  89. } else {
  90. if (cur_point_in_front) {
  91. // segment is going from the back halfspace to the front halfspace
  92. // compute the intersection and emit it, then continue
  93. // the edge into the front halfspace and emit the end point.
  94. plane.Compute_Intersection(Verts[iprev],Verts[i],&alpha);
  95. Vector3::Lerp(Verts[iprev],Verts[i],alpha,&int_point);
  96. dest.Add_Vertex(int_point);
  97. dest.Add_Vertex(Verts[i]);
  98. }
  99. }
  100. prev_point_in_front = cur_point_in_front;
  101. iprev = i;
  102. //i = (i+1)%(Verts.Count());
  103. i++;
  104. if (i>=vcount) {
  105. i = 0;
  106. }
  107. }
  108. }
  109. static VisPolyClass _VisPoly0;
  110. static VisPolyClass _VisPoly1;
  111. /*********************************************************************************************
  112. VisRasterizerClass Implementation
  113. *********************************************************************************************/
  114. VisRasterizerClass::VisRasterizerClass(void) :
  115. ModelTransform(1),
  116. Camera(NULL),
  117. MVTransform(1)
  118. {
  119. }
  120. VisRasterizerClass::~VisRasterizerClass(void)
  121. {
  122. REF_PTR_RELEASE(Camera);
  123. }
  124. void VisRasterizerClass::Set_Resolution(int width,int height)
  125. {
  126. IDBuffer.Set_Resolution(width,height);
  127. }
  128. void VisRasterizerClass::Get_Resolution(int * set_width,int * set_height)
  129. {
  130. IDBuffer.Get_Resolution(set_width,set_height);
  131. }
  132. void VisRasterizerClass::Set_Model_Transform(const Matrix3D & model)
  133. {
  134. ModelTransform = model;
  135. Update_MV_Transform();
  136. }
  137. void VisRasterizerClass::Set_Camera(CameraClass * camera)
  138. {
  139. REF_PTR_SET(Camera,camera);
  140. Update_MV_Transform();
  141. }
  142. CameraClass * VisRasterizerClass::Get_Camera(void)
  143. {
  144. if (Camera != NULL) {
  145. Camera->Add_Ref();
  146. }
  147. return Camera;
  148. }
  149. CameraClass * VisRasterizerClass::Peek_Camera(void)
  150. {
  151. return Camera;
  152. }
  153. void VisRasterizerClass::Update_MV_Transform(void)
  154. {
  155. Matrix3D view_tm(1);
  156. if (Camera) {
  157. Camera->Get_View_Matrix(&view_tm);
  158. }
  159. #ifdef ALLOW_TEMPORARIES
  160. MVTransform = view_tm * ModelTransform;
  161. #else
  162. MVTransform.mul(view_tm, ModelTransform);
  163. #endif
  164. }
  165. const Matrix3D & VisRasterizerClass::Get_MV_Transform(void)
  166. {
  167. // TODO: optimize this
  168. Update_MV_Transform(); // the user can and does mess with the camera directly!
  169. return MVTransform;
  170. }
  171. Vector3 * VisRasterizerClass::Get_Temp_Vertex_Buffer(int count)
  172. {
  173. TempVertexBuffer.Uninitialised_Grow(count);
  174. return &(TempVertexBuffer[0]);
  175. }
  176. bool VisRasterizerClass::Render_Triangles
  177. (
  178. const Vector3 * verts,
  179. int vcount,
  180. const Vector3i * tris,
  181. int tcount,const
  182. AABoxClass & bounds
  183. )
  184. {
  185. WWASSERT(verts != NULL);
  186. WWASSERT(tris != NULL);
  187. WWASSERT(vcount > 0);
  188. WWASSERT(tcount > 0);
  189. /*
  190. ** if the user supplied bounds, check if we need to clip
  191. */
  192. if (CollisionMath::Overlap_Test(Camera->Get_Frustum(),bounds) == CollisionMath::INSIDE) {
  193. return Render_Triangles_No_Clip(verts,vcount,tris,tcount);
  194. } else {
  195. return Render_Triangles_Clip(verts,vcount,tris,tcount);
  196. }
  197. }
  198. bool VisRasterizerClass::Render_Triangles_No_Clip
  199. (
  200. const Vector3 * verts,
  201. int vcount,
  202. const Vector3i * tris,
  203. int tcount
  204. )
  205. {
  206. bool pixel_passed = false;
  207. /*
  208. ** 1. transform verts into homogeneous view space and project
  209. */
  210. const Matrix3D & tm = Get_MV_Transform();
  211. Vector3 * tverts = Get_Temp_Vertex_Buffer(vcount);
  212. VectorProcessorClass::Transform(tverts,verts,tm,vcount);
  213. for (int i=0; i<vcount; i++) {
  214. Camera->Project_Camera_Space_Point(tverts[i],tverts[i]);
  215. }
  216. /*
  217. ** 2. Pass triangles on to the ID buffer for scan conversion
  218. */
  219. for (int tri_index=0; tri_index<tcount; tri_index++) {
  220. const Vector3i & tri = tris[tri_index];
  221. pixel_passed |= IDBuffer.Render_Triangle(tverts[tri.I],tverts[tri.J],tverts[tri.K]);
  222. if (pixel_passed && (IDBuffer.Get_Render_Mode() == IDBufferClass::NON_OCCLUDER_MODE)) {
  223. return true;
  224. }
  225. }
  226. return pixel_passed;
  227. }
  228. bool VisRasterizerClass::Render_Triangles_Clip
  229. (
  230. const Vector3 * verts,
  231. int vcount,
  232. const Vector3i * tris,
  233. int tcount
  234. )
  235. {
  236. bool pixel_passed = false;
  237. /*
  238. ** 1. transform triangles into homogeneous view space
  239. */
  240. const Matrix3D & tm = Get_MV_Transform();
  241. Vector3 * tverts = Get_Temp_Vertex_Buffer(vcount);
  242. VectorProcessorClass::Transform(tverts,verts,tm,vcount);
  243. /*
  244. ** 2. get the frustum clipping planes
  245. */
  246. const PlaneClass *planes = Camera->Get_View_Space_Frustum_Planes();
  247. /*
  248. ** 3. Clip triangles to the view volume and pass on to the ID buffer for scan conversion
  249. */
  250. for (int tri_index=0; tri_index<tcount; tri_index++) {
  251. /*
  252. ** Copy triangle data into the vis clipping structure
  253. */
  254. _VisPoly0.Reset();
  255. _VisPoly0.Add_Vertex(tverts[tris[tri_index].I]);
  256. _VisPoly0.Add_Vertex(tverts[tris[tri_index].J]);
  257. _VisPoly0.Add_Vertex(tverts[tris[tri_index].K]);
  258. /*
  259. ** Clip against the view frustum
  260. */
  261. _VisPoly0.Clip(planes[0],_VisPoly1);
  262. _VisPoly1.Clip(planes[1],_VisPoly0);
  263. _VisPoly0.Clip(planes[2],_VisPoly1);
  264. _VisPoly1.Clip(planes[3],_VisPoly0);
  265. _VisPoly0.Clip(planes[4],_VisPoly1);
  266. _VisPoly1.Clip(planes[5],_VisPoly0);
  267. /*
  268. ** Project the vertices
  269. */
  270. int final_vcount = _VisPoly0.Verts.Count();
  271. if (final_vcount >= 3) {
  272. Vector3 * final_verts = &(_VisPoly0.Verts[0]);
  273. int i;
  274. for (i=0; i<final_vcount; i++) {
  275. Camera->Project_Camera_Space_Point(final_verts[i],final_verts[i]);
  276. }
  277. /*
  278. ** Pass the resulting triangle fan to the IDBuffer
  279. */
  280. for (i=1; i<final_vcount - 1; i++) {
  281. pixel_passed |= IDBuffer.Render_Triangle(final_verts[0],final_verts[i],final_verts[i+1]);
  282. if (pixel_passed && (IDBuffer.Get_Render_Mode() == IDBufferClass::NON_OCCLUDER_MODE)) {
  283. return true;
  284. }
  285. }
  286. }
  287. }
  288. return pixel_passed;
  289. }
  290. /*********************************************************************************************
  291. IDBufferClass Implementation
  292. *********************************************************************************************/
  293. IDBufferClass::IDBufferClass(void) :
  294. BackfaceID(0),
  295. FrontfaceID(0),
  296. CurID(0),
  297. RenderMode(OCCLUDER_MODE),
  298. PixelCounter(0),
  299. ResWidth(0),
  300. ResHeight(0),
  301. IDBuffer(NULL),
  302. ZBuffer(NULL)
  303. {
  304. }
  305. IDBufferClass::~IDBufferClass(void)
  306. {
  307. Reset();
  308. }
  309. void IDBufferClass::Set_Resolution(int w,int h)
  310. {
  311. if ((w == ResWidth) && (h == ResHeight)) {
  312. return;
  313. } else {
  314. ResWidth = w;
  315. ResHeight = h;
  316. Allocate_Buffers();
  317. }
  318. }
  319. void IDBufferClass::Get_Resolution(int * get_w,int * get_h)
  320. {
  321. if (get_w != NULL) { *get_w = ResWidth; }
  322. if (get_h != NULL) { *get_h = ResHeight; }
  323. }
  324. void IDBufferClass::Reset(void)
  325. {
  326. if (IDBuffer!=NULL) {
  327. delete[] IDBuffer;
  328. IDBuffer = NULL;
  329. }
  330. if (ZBuffer != NULL) {
  331. delete[] ZBuffer;
  332. ZBuffer = NULL;
  333. }
  334. PixelCounter = 0;
  335. }
  336. void IDBufferClass::Allocate_Buffers(void)
  337. {
  338. Reset();
  339. int bufsize = ResWidth * ResHeight;
  340. if (bufsize > 0) {
  341. IDBuffer = W3DNEWARRAY uint32 [bufsize];
  342. ZBuffer = W3DNEWARRAY float [bufsize];
  343. }
  344. }
  345. void IDBufferClass::Clear(void)
  346. {
  347. if ((ResWidth > 0) && (ResHeight > 0)) {
  348. int byte_count = ResWidth * ResWidth * sizeof(uint32);
  349. WWASSERT(IDBuffer != NULL);
  350. WWASSERT(ZBuffer != NULL);
  351. memset(IDBuffer,0,byte_count);
  352. memset(ZBuffer,0,byte_count);
  353. }
  354. }
  355. /**
  356. ** GradientsStruct
  357. ** Computes the gradients for a triangle.
  358. */
  359. struct GradientsStruct
  360. {
  361. GradientsStruct(const Vector3 * verts)
  362. {
  363. float oodx = 1 / ( ((verts[1].X - verts[2].X) * (verts[0].Y - verts[2].Y)) -
  364. ((verts[0].X - verts[2].X) * (verts[1].Y - verts[2].Y)));
  365. float oody = -oodx;
  366. for(int i=0; i<3; i++) {
  367. OOZ[i] = 1/verts[i].Z;
  368. }
  369. DOOZ_DX = oodx * ( ((OOZ[1] - OOZ[2]) * (verts[0].Y - verts[2].Y)) -
  370. ((OOZ[0] - OOZ[2]) * (verts[1].Y - verts[2].Y)));
  371. DOOZ_DY = oody * ( ((OOZ[1] - OOZ[2]) * (verts[0].X - verts[2].X)) -
  372. ((OOZ[0] - OOZ[2]) * (verts[1].X - verts[2].X)));
  373. }
  374. float OOZ[3]; // 1/z for each vertex
  375. float DOOZ_DX; // change in 1/z per change in x
  376. float DOOZ_DY; // change in 1/z per change in y
  377. };
  378. /**
  379. ** EdgeStruct
  380. ** Can accurately scan convert an edge of a triangle.
  381. */
  382. struct EdgeStruct
  383. {
  384. EdgeStruct(const GradientsStruct & grad,const Vector3 * verts,int top,int bottom)
  385. {
  386. Y = WWMath::Ceil(verts[top].Y);
  387. Height = WWMath::Ceil(verts[bottom].Y) - Y;
  388. float y_prestep = Y - verts[top].Y;
  389. float real_height = verts[bottom].Y - verts[top].Y;
  390. float real_width = verts[bottom].X - verts[top].X;
  391. X = ((real_width * y_prestep)/real_height) + verts[top].X;
  392. XStep = real_width / real_height;
  393. float x_prestep = X - verts[top].X;
  394. OOZ = grad.OOZ[top] + y_prestep * grad.DOOZ_DY + x_prestep * grad.DOOZ_DX;
  395. OOZStep = XStep * grad.DOOZ_DX + grad.DOOZ_DY;
  396. }
  397. inline int Step(void)
  398. {
  399. X+=XStep;
  400. Y++;
  401. Height--;
  402. OOZ+=OOZStep;
  403. return Height;
  404. }
  405. float X; // fractional x coord
  406. float XStep; // change in x per scanline
  407. int Y; // current y coord
  408. int Height; // number of scanlines left
  409. float OOZ; // current 1/z
  410. float OOZStep; // change in 1/z per scanline
  411. };
  412. bool IDBufferClass::Render_Triangle(const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)
  413. {
  414. if ((ZBuffer == NULL) || (IDBuffer == NULL)) {
  415. return false;
  416. }
  417. int pixels_passed = 0;
  418. bool is_backfacing = Is_Backfacing(p0,p1,p2);
  419. if (is_backfacing) {
  420. if (RenderMode == NON_OCCLUDER_MODE) {
  421. return false;
  422. }
  423. CurID = BackfaceID;
  424. } else {
  425. CurID = FrontfaceID;
  426. }
  427. /*
  428. ** Transform the coordinates to device coords
  429. ** All coordinates come in with the range -1 -> +1
  430. */
  431. Vector3 points[3];
  432. points[0].X = 0.5f * (p0.X + 1.0f) * ResWidth;
  433. points[1].X = 0.5f * (p1.X + 1.0f) * ResWidth;
  434. points[2].X = 0.5f * (p2.X + 1.0f) * ResWidth;
  435. points[0].Y = 0.5f * (1.0f - p0.Y) * ResHeight;
  436. points[1].Y = 0.5f * (1.0f - p1.Y) * ResHeight;
  437. points[2].Y = 0.5f * (1.0f - p2.Y) * ResHeight;
  438. points[0].Z = 0.5f * (p0.Z + 1.001f) * 1000.0f;
  439. points[1].Z = 0.5f * (p1.Z + 1.001f) * 1000.0f;
  440. points[2].Z = 0.5f * (p2.Z + 1.001f) * 1000.0f;
  441. /*
  442. ** Sort points based on Y
  443. */
  444. float y0 = points[0].Y;
  445. float y1 = points[1].Y;
  446. float y2 = points[2].Y;
  447. int top,middle,bottom,middle_for_compare,bottom_for_compare;
  448. if(y0 < y1) {
  449. if(y2 < y0) {
  450. top = 2; middle = 0; bottom = 1;
  451. middle_for_compare = 0; bottom_for_compare = 1;
  452. } else {
  453. top = 0;
  454. if(y1 < y2) {
  455. middle = 1; bottom = 2;
  456. middle_for_compare = 1; bottom_for_compare = 2;
  457. } else {
  458. middle = 2; bottom = 1;
  459. middle_for_compare = 2; bottom_for_compare = 1;
  460. }
  461. }
  462. } else {
  463. if(y2 < y1) {
  464. top = 2; middle = 1; bottom = 0;
  465. middle_for_compare = 1; bottom_for_compare = 0;
  466. } else {
  467. top = 1;
  468. if(y0 < y2) {
  469. middle = 0; bottom = 2;
  470. middle_for_compare = 3; bottom_for_compare = 2;
  471. } else {
  472. middle = 2; bottom = 0;
  473. middle_for_compare = 2; bottom_for_compare = 3;
  474. }
  475. }
  476. }
  477. /*
  478. ** Compute the gradients and set up the edge structures
  479. */
  480. GradientsStruct grads(points);
  481. EdgeStruct top_to_bottom_edge(grads,points,top,bottom);
  482. EdgeStruct top_to_middle_edge(grads,points,top,middle);
  483. EdgeStruct middle_to_bottom_edge(grads,points,middle,bottom);
  484. EdgeStruct * left_edge = NULL;
  485. EdgeStruct * right_edge = NULL;
  486. bool middle_is_left = false;
  487. if (bottom_for_compare > middle_for_compare) {
  488. middle_is_left = 1 ^ is_backfacing;
  489. } else {
  490. middle_is_left = 0 ^ is_backfacing;
  491. }
  492. if (middle_is_left) {
  493. left_edge = &top_to_middle_edge;
  494. right_edge = &top_to_bottom_edge;
  495. } else {
  496. left_edge = &top_to_bottom_edge;
  497. right_edge = &top_to_middle_edge;
  498. }
  499. /*
  500. ** Fill scanlines
  501. */
  502. int height = top_to_middle_edge.Height;
  503. while (height--) {
  504. if (RenderMode == OCCLUDER_MODE) {
  505. pixels_passed += Render_Occluder_Scanline(grads,left_edge,right_edge);
  506. } else {
  507. pixels_passed += Render_Non_Occluder_Scanline(grads,left_edge,right_edge);
  508. }
  509. left_edge->Step();
  510. right_edge->Step();
  511. }
  512. if (middle_is_left) {
  513. left_edge = &middle_to_bottom_edge;
  514. right_edge = &top_to_bottom_edge;
  515. } else {
  516. left_edge = &top_to_bottom_edge;
  517. right_edge = &middle_to_bottom_edge;
  518. }
  519. height = middle_to_bottom_edge.Height;
  520. while (height--) {
  521. if (RenderMode == OCCLUDER_MODE) {
  522. pixels_passed += Render_Occluder_Scanline(grads,left_edge,right_edge);
  523. } else {
  524. pixels_passed += Render_Non_Occluder_Scanline(grads,left_edge,right_edge);
  525. }
  526. left_edge->Step();
  527. right_edge->Step();
  528. }
  529. return (pixels_passed > 0);
  530. }
  531. int IDBufferClass::Render_Occluder_Scanline(GradientsStruct & grads,EdgeStruct * left,EdgeStruct * right)
  532. {
  533. if ((left->Y < 1) || (left->Y >= ResHeight)) {
  534. return 0;
  535. }
  536. int xstart = WWMath::Float_To_Long(WWMath::Max(WWMath::Ceil(left->X),1.0f));
  537. int width = WWMath::Float_To_Long(WWMath::Ceil(right->X)) - xstart;
  538. if (xstart + width > ResWidth) {
  539. width = ResWidth - xstart;
  540. }
  541. float xprestep = (float)xstart - left->X;
  542. int address = Pixel_Coords_To_Address(xstart,left->Y);
  543. float ooz = left->OOZ + xprestep * grads.DOOZ_DX;
  544. int pixel_counter = 0;
  545. /*
  546. ** Two separate loops, backfaces only render when LESS THAN
  547. */
  548. if (CurID == BackfaceID) {
  549. while (width-- > 0) {
  550. if (ooz > ZBuffer[address]) {
  551. IDBuffer[address] = CurID;
  552. ZBuffer[address] = ooz;
  553. pixel_counter++;
  554. }
  555. ooz += grads.DOOZ_DX;
  556. address++;
  557. }
  558. /*
  559. ** Front faces render when LESS THAN OR EQUAL TO
  560. */
  561. } else {
  562. while (width-- > 0) {
  563. if (ooz >= ZBuffer[address]) {
  564. IDBuffer[address] = CurID;
  565. ZBuffer[address] = ooz;
  566. pixel_counter++;
  567. }
  568. ooz += grads.DOOZ_DX;
  569. address++;
  570. }
  571. }
  572. PixelCounter += pixel_counter;
  573. return pixel_counter;
  574. }
  575. int IDBufferClass::Render_Non_Occluder_Scanline(GradientsStruct & grads,EdgeStruct * left,EdgeStruct * right)
  576. {
  577. if ((left->Y < 1) || (left->Y >= ResHeight)) {
  578. return 0;
  579. }
  580. int xstart = WWMath::Float_To_Long(WWMath::Max(WWMath::Ceil(left->X),1));
  581. int width = WWMath::Float_To_Long(WWMath::Ceil(right->X)) - xstart;
  582. if (xstart + width > ResWidth) {
  583. width = ResWidth - xstart;
  584. }
  585. float xprestep = (float)xstart - left->X;
  586. int address = Pixel_Coords_To_Address(xstart,left->Y);
  587. float ooz = left->OOZ + xprestep * grads.DOOZ_DX;
  588. while (width-- > 0) {
  589. if (ooz >= ZBuffer[address]) {
  590. PixelCounter++;
  591. return 1;
  592. }
  593. ooz += grads.DOOZ_DX;
  594. address++;
  595. }
  596. return 0;
  597. }