visrasterizer.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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:: Jani_p $*
  29. * *
  30. * $Modtime:: 11/24/01 5:42p $*
  31. * *
  32. * $Revision:: 11 $*
  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 TriIndex * 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 TriIndex * 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 TriIndex & 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 TriIndex * 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. TwoSidedRenderingEnabled(false),
  299. PixelCounter(0),
  300. ResWidth(0),
  301. ResHeight(0),
  302. IDBuffer(NULL),
  303. ZBuffer(NULL)
  304. {
  305. }
  306. IDBufferClass::~IDBufferClass(void)
  307. {
  308. Reset();
  309. }
  310. void IDBufferClass::Set_Resolution(int w,int h)
  311. {
  312. if ((w == ResWidth) && (h == ResHeight)) {
  313. return;
  314. } else {
  315. ResWidth = w;
  316. ResHeight = h;
  317. Allocate_Buffers();
  318. }
  319. }
  320. void IDBufferClass::Get_Resolution(int * get_w,int * get_h)
  321. {
  322. if (get_w != NULL) { *get_w = ResWidth; }
  323. if (get_h != NULL) { *get_h = ResHeight; }
  324. }
  325. void IDBufferClass::Reset(void)
  326. {
  327. if (IDBuffer!=NULL) {
  328. delete[] IDBuffer;
  329. IDBuffer = NULL;
  330. }
  331. if (ZBuffer != NULL) {
  332. delete[] ZBuffer;
  333. ZBuffer = NULL;
  334. }
  335. PixelCounter = 0;
  336. }
  337. void IDBufferClass::Allocate_Buffers(void)
  338. {
  339. Reset();
  340. int bufsize = ResWidth * ResHeight;
  341. if (bufsize > 0) {
  342. IDBuffer = W3DNEWARRAY uint32 [bufsize];
  343. ZBuffer = W3DNEWARRAY float [bufsize];
  344. }
  345. }
  346. void IDBufferClass::Clear(void)
  347. {
  348. if ((ResWidth > 0) && (ResHeight > 0)) {
  349. int byte_count = ResWidth * ResWidth * sizeof(uint32);
  350. WWASSERT(IDBuffer != NULL);
  351. WWASSERT(ZBuffer != NULL);
  352. memset(IDBuffer,0,byte_count);
  353. memset(ZBuffer,0,byte_count);
  354. }
  355. }
  356. /**
  357. ** GradientsStruct
  358. ** Computes the gradients for a triangle.
  359. */
  360. struct GradientsStruct
  361. {
  362. GradientsStruct(const Vector3 * verts)
  363. {
  364. float oodx = 1 / ( ((verts[1].X - verts[2].X) * (verts[0].Y - verts[2].Y)) -
  365. ((verts[0].X - verts[2].X) * (verts[1].Y - verts[2].Y)));
  366. float oody = -oodx;
  367. for(int i=0; i<3; i++) {
  368. OOZ[i] = 1/verts[i].Z;
  369. }
  370. DOOZ_DX = oodx * ( ((OOZ[1] - OOZ[2]) * (verts[0].Y - verts[2].Y)) -
  371. ((OOZ[0] - OOZ[2]) * (verts[1].Y - verts[2].Y)));
  372. DOOZ_DY = oody * ( ((OOZ[1] - OOZ[2]) * (verts[0].X - verts[2].X)) -
  373. ((OOZ[0] - OOZ[2]) * (verts[1].X - verts[2].X)));
  374. }
  375. float OOZ[3]; // 1/z for each vertex
  376. float DOOZ_DX; // change in 1/z per change in x
  377. float DOOZ_DY; // change in 1/z per change in y
  378. };
  379. /**
  380. ** EdgeStruct
  381. ** Can accurately scan convert an edge of a triangle.
  382. */
  383. struct EdgeStruct
  384. {
  385. EdgeStruct(const GradientsStruct & grad,const Vector3 * verts,int top,int bottom)
  386. {
  387. Y = WWMath::Ceil(verts[top].Y);
  388. Height = WWMath::Ceil(verts[bottom].Y) - Y;
  389. float y_prestep = Y - verts[top].Y;
  390. float real_height = verts[bottom].Y - verts[top].Y;
  391. float real_width = verts[bottom].X - verts[top].X;
  392. X = ((real_width * y_prestep)/real_height) + verts[top].X;
  393. XStep = real_width / real_height;
  394. float x_prestep = X - verts[top].X;
  395. OOZ = grad.OOZ[top] + y_prestep * grad.DOOZ_DY + x_prestep * grad.DOOZ_DX;
  396. OOZStep = XStep * grad.DOOZ_DX + grad.DOOZ_DY;
  397. }
  398. inline int Step(void)
  399. {
  400. X+=XStep;
  401. Y++;
  402. Height--;
  403. OOZ+=OOZStep;
  404. return Height;
  405. }
  406. float X; // fractional x coord
  407. float XStep; // change in x per scanline
  408. int Y; // current y coord
  409. int Height; // number of scanlines left
  410. float OOZ; // current 1/z
  411. float OOZStep; // change in 1/z per scanline
  412. };
  413. bool IDBufferClass::Render_Triangle(const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)
  414. {
  415. if ((ZBuffer == NULL) || (IDBuffer == NULL)) {
  416. return false;
  417. }
  418. int pixels_passed = 0;
  419. bool is_backfacing = Is_Backfacing(p0,p1,p2);
  420. if ((is_backfacing) && (TwoSidedRenderingEnabled == false)) {
  421. if (RenderMode == NON_OCCLUDER_MODE) {
  422. return false;
  423. }
  424. CurID = BackfaceID;
  425. } else {
  426. CurID = FrontfaceID;
  427. }
  428. /*
  429. ** Transform the coordinates to device coords
  430. ** All coordinates come in with the range -1 -> +1
  431. */
  432. Vector3 points[3];
  433. points[0].X = 0.5f * (p0.X + 1.0f) * ResWidth;
  434. points[1].X = 0.5f * (p1.X + 1.0f) * ResWidth;
  435. points[2].X = 0.5f * (p2.X + 1.0f) * ResWidth;
  436. points[0].Y = 0.5f * (1.0f - p0.Y) * ResHeight;
  437. points[1].Y = 0.5f * (1.0f - p1.Y) * ResHeight;
  438. points[2].Y = 0.5f * (1.0f - p2.Y) * ResHeight;
  439. points[0].Z = 0.5f * (p0.Z + 1.001f) * 1000.0f;
  440. points[1].Z = 0.5f * (p1.Z + 1.001f) * 1000.0f;
  441. points[2].Z = 0.5f * (p2.Z + 1.001f) * 1000.0f;
  442. /*
  443. ** Sort points based on Y
  444. */
  445. float y0 = points[0].Y;
  446. float y1 = points[1].Y;
  447. float y2 = points[2].Y;
  448. int top,middle,bottom,middle_for_compare,bottom_for_compare;
  449. if(y0 < y1) {
  450. if(y2 < y0) {
  451. top = 2; middle = 0; bottom = 1;
  452. middle_for_compare = 0; bottom_for_compare = 1;
  453. } else {
  454. top = 0;
  455. if(y1 < y2) {
  456. middle = 1; bottom = 2;
  457. middle_for_compare = 1; bottom_for_compare = 2;
  458. } else {
  459. middle = 2; bottom = 1;
  460. middle_for_compare = 2; bottom_for_compare = 1;
  461. }
  462. }
  463. } else {
  464. if(y2 < y1) {
  465. top = 2; middle = 1; bottom = 0;
  466. middle_for_compare = 1; bottom_for_compare = 0;
  467. } else {
  468. top = 1;
  469. if(y0 < y2) {
  470. middle = 0; bottom = 2;
  471. middle_for_compare = 3; bottom_for_compare = 2;
  472. } else {
  473. middle = 2; bottom = 0;
  474. middle_for_compare = 2; bottom_for_compare = 3;
  475. }
  476. }
  477. }
  478. /*
  479. ** Compute the gradients and set up the edge structures
  480. */
  481. GradientsStruct grads(points);
  482. EdgeStruct top_to_bottom_edge(grads,points,top,bottom);
  483. EdgeStruct top_to_middle_edge(grads,points,top,middle);
  484. EdgeStruct middle_to_bottom_edge(grads,points,middle,bottom);
  485. EdgeStruct * left_edge = NULL;
  486. EdgeStruct * right_edge = NULL;
  487. bool middle_is_left = false;
  488. if (bottom_for_compare > middle_for_compare) {
  489. middle_is_left = 1 ^ is_backfacing;
  490. } else {
  491. middle_is_left = 0 ^ is_backfacing;
  492. }
  493. if (middle_is_left) {
  494. left_edge = &top_to_middle_edge;
  495. right_edge = &top_to_bottom_edge;
  496. } else {
  497. left_edge = &top_to_bottom_edge;
  498. right_edge = &top_to_middle_edge;
  499. }
  500. /*
  501. ** Fill scanlines
  502. */
  503. int height = top_to_middle_edge.Height;
  504. while (height--) {
  505. if (RenderMode == OCCLUDER_MODE) {
  506. pixels_passed += Render_Occluder_Scanline(grads,left_edge,right_edge);
  507. } else {
  508. pixels_passed += Render_Non_Occluder_Scanline(grads,left_edge,right_edge);
  509. }
  510. left_edge->Step();
  511. right_edge->Step();
  512. }
  513. if (middle_is_left) {
  514. left_edge = &middle_to_bottom_edge;
  515. right_edge = &top_to_bottom_edge;
  516. } else {
  517. left_edge = &top_to_bottom_edge;
  518. right_edge = &middle_to_bottom_edge;
  519. }
  520. height = middle_to_bottom_edge.Height;
  521. while (height--) {
  522. if (RenderMode == OCCLUDER_MODE) {
  523. pixels_passed += Render_Occluder_Scanline(grads,left_edge,right_edge);
  524. } else {
  525. pixels_passed += Render_Non_Occluder_Scanline(grads,left_edge,right_edge);
  526. }
  527. left_edge->Step();
  528. right_edge->Step();
  529. }
  530. return (pixels_passed > 0);
  531. }
  532. int IDBufferClass::Render_Occluder_Scanline(GradientsStruct & grads,EdgeStruct * left,EdgeStruct * right)
  533. {
  534. if ((left->Y < 1) || (left->Y >= ResHeight)) {
  535. return 0;
  536. }
  537. int xstart = WWMath::Float_To_Long(WWMath::Max(WWMath::Ceil(left->X),1.0f));
  538. int width = WWMath::Float_To_Long(WWMath::Ceil(right->X)) - xstart;
  539. if (xstart + width > ResWidth) {
  540. width = ResWidth - xstart;
  541. }
  542. float xprestep = (float)xstart - left->X;
  543. int address = Pixel_Coords_To_Address(xstart,left->Y);
  544. float ooz = left->OOZ + xprestep * grads.DOOZ_DX;
  545. int pixel_counter = 0;
  546. /*
  547. ** Two separate loops, backfaces only render when LESS THAN
  548. */
  549. if (CurID == BackfaceID) {
  550. while (width-- > 0) {
  551. if (ooz > ZBuffer[address]) {
  552. IDBuffer[address] = CurID;
  553. ZBuffer[address] = ooz;
  554. pixel_counter++;
  555. }
  556. ooz += grads.DOOZ_DX;
  557. address++;
  558. }
  559. /*
  560. ** Front faces render when LESS THAN OR EQUAL TO
  561. */
  562. } else {
  563. while (width-- > 0) {
  564. if (ooz >= ZBuffer[address]) {
  565. IDBuffer[address] = CurID;
  566. ZBuffer[address] = ooz;
  567. pixel_counter++;
  568. }
  569. ooz += grads.DOOZ_DX;
  570. address++;
  571. }
  572. }
  573. PixelCounter += pixel_counter;
  574. return pixel_counter;
  575. }
  576. int IDBufferClass::Render_Non_Occluder_Scanline(GradientsStruct & grads,EdgeStruct * left,EdgeStruct * right)
  577. {
  578. if ((left->Y < 1) || (left->Y >= ResHeight)) {
  579. return 0;
  580. }
  581. int xstart = WWMath::Float_To_Long(WWMath::Max(WWMath::Ceil(left->X),1));
  582. int width = WWMath::Float_To_Long(WWMath::Ceil(right->X)) - xstart;
  583. if (xstart + width > ResWidth) {
  584. width = ResWidth - xstart;
  585. }
  586. float xprestep = (float)xstart - left->X;
  587. int address = Pixel_Coords_To_Address(xstart,left->Y);
  588. float ooz = left->OOZ + xprestep * grads.DOOZ_DX;
  589. while (width-- > 0) {
  590. if (ooz >= ZBuffer[address]) {
  591. PixelCounter++;
  592. return 1;
  593. }
  594. ooz += grads.DOOZ_DX;
  595. address++;
  596. }
  597. return 0;
  598. }