Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

538 lines
20 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mcdrend.c
  3. *
  4. * This file contains routines to do high-level triangle rendering for the
  5. * Millenium MCD driver, including culling and face computations. Note that
  6. * in this driver, we don't use vertex color pointer at all since all pointer
  7. * references need to be checked to avoid the possibility of an invalid
  8. * memory reference. Instead, we copy the color data in the cases where we
  9. * need to during two-sided operation. This is not the common case, and even
  10. * in the case where the color data needs to be copied to colors[0] (and back),
  11. * the copy only needs to be done for (on average) half the faces.
  12. *
  13. * Copyright (c) 1996 Microsoft Corporation
  14. \**************************************************************************/
  15. #include "precomp.h"
  16. #include "mcdhw.h"
  17. #include "mcdutil.h"
  18. #include "mcdmath.h"
  19. #include "math.h"
  20. #if _X86_
  21. #define GET_HALF_AREA(pRc, a, b, c)\
  22. \
  23. __asm{ mov ecx, c };\
  24. __asm{ mov eax, a };\
  25. __asm{ mov ebx, b };\
  26. __asm{ mov edx, pRc };\
  27. __asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ecx] };\
  28. __asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][eax] /* dxAC */ };\
  29. __asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ecx] };\
  30. __asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ebx] /* dyBC dxAC */ };\
  31. __asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ecx] /* dxBC dyBC dxAC */ };\
  32. __asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ebx] };\
  33. __asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ecx] };\
  34. __asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][eax] /* dyAC dxBC dyBC dxAC */ };\
  35. __asm{ fxch ST(2) /* dyBC dxBC dyAC dxAC */ };\
  36. __asm{ fst DWORD PTR [OFFSET(DEVRC.dyBC)][edx] };\
  37. __asm{ fmul ST, ST(3) /* dxACdyBC dxBC dyAC dxAC */ };\
  38. __asm{ fxch ST(2) /* dyAC dxBC dxACdyBC dxAC */ };\
  39. __asm{ fst DWORD PTR [OFFSET(DEVRC.dyAC)][edx] };\
  40. __asm{ fmul ST, ST(1) /* dxBCdyAC dxBC dxACdyBC dxAC */ };\
  41. __asm{ fxch ST(1) /* dxBC dxBCdyAC dxACdyBC dxAC */ };\
  42. __asm{ fstp DWORD PTR [OFFSET(DEVRC.dxBC)][edx] /* dxBCdyAC dxACdyBC dxAC */ };\
  43. __asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][ebx] };\
  44. __asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.x)][eax] /* dxAB dxBCdyAC dxACdyBC dxAC */ };\
  45. __asm{ fxch ST(1) /* dxBCdyAC dxAB dxACdyBC dxAC */ };\
  46. __asm{ fsubp ST(2), ST /* dxAB area dxAC */ };\
  47. __asm{ fld DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][ebx] };\
  48. __asm{ fsub DWORD PTR [OFFSET(MCDVERTEX.windowCoord.y)][eax] /* dyAB dxAB area dxAC */ };\
  49. __asm{ fxch ST(3) /* dxAC dxAB area dyAB */ };\
  50. __asm{ fstp DWORD PTR [OFFSET(DEVRC.dxAC)][edx] /* dxAB area dyAB */ };\
  51. __asm{ fstp DWORD PTR [OFFSET(DEVRC.dxAB)][edx] /* area dyAB */ };\
  52. __asm{ fstp DWORD PTR [OFFSET(DEVRC.halfArea)][edx] /* dyAB */ };\
  53. __asm{ fstp DWORD PTR [OFFSET(DEVRC.dyAB)][edx] /* (empty) */ };
  54. #else
  55. #define GET_HALF_AREA(pRc, a, b, c)\
  56. /* Compute signed half-area of the triangle */ \
  57. (pRc)->dxAC = (c)->windowCoord.x - (a)->windowCoord.x; \
  58. (pRc)->dxBC = (c)->windowCoord.x - (b)->windowCoord.x; \
  59. (pRc)->dyAC = (c)->windowCoord.y - (a)->windowCoord.y; \
  60. (pRc)->dyBC = (c)->windowCoord.y - (b)->windowCoord.y; \
  61. (pRc)->dxAB = (b)->windowCoord.x - (a)->windowCoord.x; \
  62. (pRc)->dyAB = (b)->windowCoord.y - (a)->windowCoord.y; \
  63. \
  64. (pRc)->halfArea = (pRc)->dxAC * (pRc)->dyBC - (pRc)->dxBC * (pRc)->dyAC;
  65. #endif
  66. #define SORT_AND_CULL_FACE(a, b, c, face, ccw)\
  67. { \
  68. LONG reversed; \
  69. MCDVERTEX *temp; \
  70. \
  71. \
  72. reversed = 0; \
  73. if (__MCD_VERTEX_COMPARE((a)->windowCoord.y, <, (b)->windowCoord.y)) { \
  74. if (__MCD_VERTEX_COMPARE((b)->windowCoord.y, <, (c)->windowCoord.y)) { \
  75. /* Already sorted */ \
  76. } else { \
  77. if (__MCD_VERTEX_COMPARE((a)->windowCoord.y, <, (c)->windowCoord.y)) {\
  78. temp=(b); (b)=(c); (c)=temp; \
  79. reversed = 1; \
  80. } else { \
  81. temp=(a); (a)=(c); (c)=(b); (b)=temp; \
  82. } \
  83. } \
  84. } else { \
  85. if (__MCD_VERTEX_COMPARE((b)->windowCoord.y, <, (c)->windowCoord.y)) { \
  86. if (__MCD_VERTEX_COMPARE((a)->windowCoord.y, <, (c)->windowCoord.y)) {\
  87. temp=(a); (a)=(b); (b)=temp; \
  88. reversed = 1; \
  89. } else { \
  90. temp=(a); (a)=(b); (b)=(c); (c)=temp; \
  91. } \
  92. } else { \
  93. temp=(a); (a)=(c); (c)=temp; \
  94. reversed = 1; \
  95. } \
  96. } \
  97. \
  98. GET_HALF_AREA(pRc, (a), (b), (c)); \
  99. \
  100. (ccw) = !__MCD_FLOAT_LTZ(pRc->halfArea); \
  101. \
  102. /* \
  103. ** Figure out if face is culled or not. The face check needs to be \
  104. ** based on the vertex winding before sorting. This code uses the \
  105. ** reversed flag to invert the sense of ccw - an xor accomplishes \
  106. ** this conversion without an if test. \
  107. ** \
  108. ** ccw reversed xor \
  109. ** --- -------- --- \
  110. ** 0 0 0 (remain !ccw) \
  111. ** 1 0 1 (remain ccw) \
  112. ** 0 1 1 (become ccw) \
  113. ** 1 1 0 (become cw) \
  114. */ \
  115. (face) = pRc->polygonFace[(ccw) ^ reversed]; \
  116. if ((face) == pRc->cullFlag) { \
  117. /* Culled */ \
  118. return; \
  119. } \
  120. }
  121. ////////////////////////////////////////////////////////////////////////
  122. //
  123. // VOID FASTCALL __MCDCalcZSlope(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c)
  124. //
  125. // Local helper routine to calculate z slopes for z-offseting primitives.
  126. //
  127. ////////////////////////////////////////////////////////////////////////
  128. VOID FASTCALL __MCDCalcZSlope(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b, MCDVERTEX *c)
  129. {
  130. MCDFLOAT oneOverArea, t1, t2, t3, t4;
  131. MCDFLOAT dzAC, dzBC;
  132. if (CASTINT(pRc->halfArea) == 0) {
  133. pRc->dzdx = __MCDZERO;
  134. pRc->dzdy = __MCDZERO;
  135. return;
  136. }
  137. oneOverArea = __MCDONE / pRc->halfArea;
  138. t1 = pRc->dyAC * oneOverArea;
  139. t2 = pRc->dyBC * oneOverArea;
  140. t3 = pRc->dxAC * oneOverArea;
  141. t4 = pRc->dxBC * oneOverArea;
  142. dzAC = c->windowCoord.z - a->windowCoord.z;
  143. dzBC = c->windowCoord.z - b->windowCoord.z;
  144. pRc->dzdx = (dzAC * t2 - dzBC * t1);
  145. pRc->dzdy = (dzBC * t3 - dzAC * t4);
  146. }
  147. ////////////////////////////////////////////////////////////////////////
  148. //
  149. // VOID FASTCALL __MCDGetZOffsetDelta(DEVRC *pRc)
  150. //
  151. // Returns required z offset value for current primitive. Assumes that
  152. // z deltas are already in RC.
  153. //
  154. ////////////////////////////////////////////////////////////////////////
  155. MCDFLOAT FASTCALL __MCDGetZOffsetDelta(DEVRC *pRc)
  156. {
  157. #define FABS(f) ((MCDFLOAT)fabs((double) (f)))
  158. MCDFLOAT maxdZ;
  159. // Find maximum x or y slope:
  160. if(FABS(pRc->dzdx) > FABS(pRc->dzdy))
  161. maxdZ = FABS(pRc->dzdx);
  162. else
  163. maxdZ = FABS(pRc->dzdy);
  164. return (pRc->MCDState.zOffsetFactor * maxdZ);
  165. }
  166. ////////////////////////////////////////////////////////////////////////
  167. //
  168. // VOID FASTCALL __MCDRenderGenTriangle(DEVRC *pRc, MCDVERTEX *a,
  169. // MCDVERTEX *b, MCDVERTEX *c)
  170. //
  171. //
  172. // This is the generic triangle-rendering routine. This is used if either
  173. // of the polygon faces are not GL_FILL.
  174. //
  175. ////////////////////////////////////////////////////////////////////////
  176. //!! Fix clipping logic, add startXXX logic
  177. VOID FASTCALL __MCDRenderGenTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  178. MCDVERTEX *c)
  179. {
  180. LONG ccw, face;
  181. MCDVERTEX *oa, *ob, *oc;
  182. RECTL *pClip;
  183. ULONG clipNum;
  184. MCDFLOAT zOffset;
  185. MCDCOLOR tempA, tempB, tempC;
  186. ULONG polygonMode;
  187. BOOL backFace;
  188. MCDVERTEX *pv;
  189. //!! MCDBG_PRINT("__MCDRenderGenTriangle");
  190. /*
  191. ** Save old vertex pointers in case we end up not doing a fill.
  192. */
  193. oa = a; ob = b; oc = c;
  194. SORT_AND_CULL_FACE(a, b, c, face, ccw);
  195. if ((clipNum = pRc->pEnumClip->c) > 1) {
  196. pClip = &pRc->pEnumClip->arcl[0];
  197. (*pRc->HWSetupClipRect)(pRc, pClip++);
  198. }
  199. polygonMode = pRc->polygonMode[face];
  200. backFace = (pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
  201. (face == __MCD_BACKFACE);
  202. // Pick correct face color and render the triangle:
  203. if (pRc->privateEnables & __MCDENABLE_SMOOTH) {
  204. if (backFace) {
  205. SWAP_COLOR(a);
  206. SWAP_COLOR(b);
  207. SWAP_COLOR(c);
  208. }
  209. } else { // Flat shading
  210. pv = pRc->pvProvoking;
  211. if (polygonMode == GL_FILL) {
  212. if (backFace) {
  213. SWAP_COLOR(pv);
  214. }
  215. } else {
  216. SAVE_COLOR(tempA, a);
  217. SAVE_COLOR(tempB, b);
  218. SAVE_COLOR(tempC, c);
  219. if (backFace) {
  220. SWAP_COLOR(pv);
  221. }
  222. a->colors[0] = pv->colors[0];
  223. b->colors[0] = pv->colors[0];
  224. c->colors[0] = pv->colors[0];
  225. }
  226. }
  227. // Render triangle using the current polygon mode for the face:
  228. switch (pRc->polygonMode[face]) {
  229. case GL_FILL:
  230. if (CASTINT(pRc->halfArea) != 0) {
  231. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  232. while (--clipNum) {
  233. (*pRc->HWSetupClipRect)(pRc, pClip++);
  234. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  235. }
  236. }
  237. break;
  238. case GL_POINT:
  239. (*pRc->beginPointDrawing)(pRc);
  240. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_POINT_ENABLE) {
  241. __MCDCalcZSlope(pRc, a, b, c);
  242. zOffset = __MCDGetZOffsetDelta(pRc) + pRc->MCDState.zOffsetUnits;
  243. oa->windowCoord.z += zOffset;
  244. ob->windowCoord.z += zOffset;
  245. oc->windowCoord.z += zOffset;
  246. }
  247. if (oa->flags & MCDVERTEX_EDGEFLAG) {
  248. (*pRc->drawPoint)(pRc, oa);
  249. }
  250. if (ob->flags & MCDVERTEX_EDGEFLAG) {
  251. (*pRc->drawPoint)(pRc, ob);
  252. }
  253. if (oc->flags & MCDVERTEX_EDGEFLAG) {
  254. (*pRc->drawPoint)(pRc, oc);
  255. }
  256. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_POINT_ENABLE) {
  257. oa->windowCoord.z -= zOffset;
  258. ob->windowCoord.z -= zOffset;
  259. oc->windowCoord.z -= zOffset;
  260. }
  261. break;
  262. case GL_LINE:
  263. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_LINE_ENABLE) {
  264. __MCDCalcZSlope(pRc, a, b, c);
  265. zOffset = __MCDGetZOffsetDelta(pRc) + pRc->MCDState.zOffsetUnits;
  266. oa->windowCoord.z += zOffset;
  267. ob->windowCoord.z += zOffset;
  268. oc->windowCoord.z += zOffset;
  269. }
  270. (*pRc->beginLineDrawing)(pRc);
  271. if ((oa->flags & MCDVERTEX_EDGEFLAG) &&
  272. (ob->flags & MCDVERTEX_EDGEFLAG) &&
  273. (oc->flags & MCDVERTEX_EDGEFLAG)) {
  274. (*pRc->drawLine)(pRc, oa, ob, TRUE);
  275. (*pRc->drawLine)(pRc, ob, oc, 0);
  276. (*pRc->drawLine)(pRc, oc, oa, 0);
  277. } else {
  278. if (oa->flags & MCDVERTEX_EDGEFLAG)
  279. (*pRc->drawLine)(pRc, oa, ob, TRUE);
  280. if (ob->flags & MCDVERTEX_EDGEFLAG)
  281. (*pRc->drawLine)(pRc, ob, oc, TRUE);
  282. if (oc->flags & MCDVERTEX_EDGEFLAG)
  283. (*pRc->drawLine)(pRc, oc, oa, TRUE);
  284. }
  285. (*pRc->endLineDrawing)(pRc);
  286. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_LINE_ENABLE) {
  287. oa->windowCoord.z -= zOffset;
  288. ob->windowCoord.z -= zOffset;
  289. oc->windowCoord.z -= zOffset;
  290. }
  291. break;
  292. default:
  293. break;
  294. }
  295. // Restore original colors if needed:
  296. if (pRc->privateEnables & __MCDENABLE_SMOOTH) {
  297. if (backFace) {
  298. SWAP_COLOR(a);
  299. SWAP_COLOR(b);
  300. SWAP_COLOR(c);
  301. }
  302. } else { // Flat shading
  303. if (polygonMode == GL_FILL) {
  304. if (backFace) {
  305. SWAP_COLOR(pv);
  306. }
  307. } else {
  308. if (backFace) {
  309. SWAP_COLOR(pv);
  310. }
  311. RESTORE_COLOR(tempA, a);
  312. RESTORE_COLOR(tempB, b);
  313. RESTORE_COLOR(tempC, c);
  314. }
  315. }
  316. }
  317. ////////////////////////////////////////////////////////////////////////
  318. //
  319. // VOID FASTCALL __MCDRenderFlatTriangle(DEVRC *pRc, MCDVERTEX *a,
  320. // MCDVERTEX *b, MCDVERTEX *c)
  321. //
  322. //
  323. // This is the top-level flat-shaded triangle renderer.
  324. //
  325. ////////////////////////////////////////////////////////////////////////
  326. VOID FASTCALL __MCDRenderFlatTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  327. MCDVERTEX *c)
  328. {
  329. LONG ccw, face;
  330. RECTL *pClip;
  331. ULONG clipNum;
  332. //!! MCDBG_PRINT("__MCDRenderFlatTriangle");
  333. SORT_AND_CULL_FACE(a, b, c, face, ccw);
  334. if (CASTINT(pRc->halfArea) == 0)
  335. return;
  336. if ((clipNum = pRc->pEnumClip->c) > 1) {
  337. pClip = &pRc->pEnumClip->arcl[0];
  338. (*pRc->HWSetupClipRect)(pRc, pClip++);
  339. }
  340. // Pick correct face color and render the triangle:
  341. if ((pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
  342. (face == __MCD_BACKFACE))
  343. {
  344. MCDVERTEX *pv = pRc->pvProvoking;
  345. SWAP_COLOR(pv);
  346. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  347. while (--clipNum) {
  348. (*pRc->HWSetupClipRect)(pRc, pClip++);
  349. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  350. }
  351. SWAP_COLOR(pv);
  352. }
  353. else
  354. {
  355. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  356. while (--clipNum) {
  357. (*pRc->HWSetupClipRect)(pRc, pClip++);
  358. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  359. }
  360. }
  361. }
  362. ////////////////////////////////////////////////////////////////////////
  363. //
  364. // VOID FASTCALL __MCDRenderSmoothTriangle(DEVRC *pRc, MCDVERTEX *a,
  365. // MCDVERTEX *b, MCDVERTEX *c)
  366. //
  367. //
  368. // This is the top-level smooth triangle renderer.
  369. //
  370. ////////////////////////////////////////////////////////////////////////
  371. VOID FASTCALL __MCDRenderSmoothTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  372. MCDVERTEX *c)
  373. {
  374. LONG ccw, face;
  375. RECTL *pClip;
  376. ULONG clipNum;
  377. //!! MCDBG_PRINT("__MCDRenderSmoothTriangle");
  378. SORT_AND_CULL_FACE(a, b, c, face, ccw);
  379. if (CASTINT(pRc->halfArea) == 0)
  380. return;
  381. if ((clipNum = pRc->pEnumClip->c) > 1) {
  382. pClip = &pRc->pEnumClip->arcl[0];
  383. (*pRc->HWSetupClipRect)(pRc, pClip++);
  384. }
  385. // Pick correct face color and render the triangle:
  386. if ((pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
  387. (face == __MCD_BACKFACE))
  388. {
  389. SWAP_COLOR(a);
  390. SWAP_COLOR(b);
  391. SWAP_COLOR(c);
  392. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  393. while (--clipNum) {
  394. (*pRc->HWSetupClipRect)(pRc, pClip++);
  395. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  396. }
  397. SWAP_COLOR(a);
  398. SWAP_COLOR(b);
  399. SWAP_COLOR(c);
  400. }
  401. else
  402. {
  403. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  404. while (--clipNum) {
  405. (*pRc->HWSetupClipRect)(pRc, pClip++);
  406. (*pRc->drawTri)(pRc, a, b, c, (BOOL) ccw);
  407. }
  408. }
  409. }
  410. VOID FASTCALL __MCDRenderFlatFogTriangle(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2,
  411. MCDVERTEX *pv3)
  412. {
  413. MCDCOLOR c1, c2, c3;
  414. MCDCOLOR bc1, bc2, bc3;
  415. MCDCOLOR cProvoking;
  416. c1 = pv1->colors[0];
  417. c2 = pv2->colors[0];
  418. c3 = pv3->colors[0];
  419. // We have to save a copy of the provoking color since we
  420. // can overwrite it!
  421. cProvoking = pRc->pvProvoking->colors[0];
  422. __MCDCalcFogColor(pRc, pv1, &pv1->colors[0], &cProvoking);
  423. __MCDCalcFogColor(pRc, pv2, &pv2->colors[0], &cProvoking);
  424. __MCDCalcFogColor(pRc, pv3, &pv3->colors[0], &cProvoking);
  425. if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
  426. cProvoking = pRc->pvProvoking->colors[1];
  427. bc1 = pv1->colors[1];
  428. bc2 = pv2->colors[1];
  429. bc3 = pv3->colors[1];
  430. __MCDCalcFogColor(pRc, pv1, &pv1->colors[1], &cProvoking);
  431. __MCDCalcFogColor(pRc, pv2, &pv2->colors[1], &cProvoking);
  432. __MCDCalcFogColor(pRc, pv3, &pv3->colors[1], &cProvoking);
  433. }
  434. (*pRc->renderTriX)(pRc, pv1, pv2, pv3);
  435. pv1->colors[0] = c1;
  436. pv2->colors[0] = c2;
  437. pv3->colors[0] = c3;
  438. if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
  439. pv1->colors[1] = bc1;
  440. pv2->colors[1] = bc2;
  441. pv3->colors[1] = bc3;
  442. }
  443. }