Leaked source code of windows server 2003
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.

508 lines
19 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mcdrend.c
  3. *
  4. * This file contains routines to do high-level triangle rendering for the
  5. * Cirrus Logic 546X 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. * Copyright (c) 1997 Cirrus Logic, Inc.
  15. \**************************************************************************/
  16. #include "precomp.h"
  17. #include "mcdhw.h"
  18. #include "mcdutil.h"
  19. #include "mcdmath.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 __MCDRenderSmoothTriangle(DEVRC *pRc, MCDVERTEX *a,
  169. // MCDVERTEX *b, MCDVERTEX *c)
  170. //
  171. //
  172. // This is the top-level smooth triangle renderer.
  173. //
  174. ////////////////////////////////////////////////////////////////////////
  175. VOID FASTCALL __MCDRenderSmoothTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  176. MCDVERTEX *c)
  177. {
  178. LONG ccw, face;
  179. RECTL *pClip;
  180. ULONG clipNum;
  181. // MCDBG_PRINT("__MCDRenderSmoothTriangle");
  182. SORT_AND_CULL_FACE(a, b, c, face, ccw);
  183. if (CASTINT(pRc->halfArea) == 0)
  184. return;
  185. if ((clipNum = pRc->pEnumClip->c) > 1) {
  186. pClip = &pRc->pEnumClip->arcl[0];
  187. (*pRc->HWSetupClipRect)(pRc, pClip++);
  188. }
  189. // Pick correct face color and render the triangle:
  190. if ((pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
  191. (face == __MCD_BACKFACE))
  192. {
  193. SWAP_COLOR(a);
  194. SWAP_COLOR(b);
  195. SWAP_COLOR(c);
  196. (*pRc->drawTri)(pRc, a, b, c, 1);
  197. while (--clipNum) {
  198. (*pRc->HWSetupClipRect)(pRc, pClip++);
  199. (*pRc->drawTri)(pRc, a, b, c, 1);
  200. }
  201. SWAP_COLOR(a);
  202. SWAP_COLOR(b);
  203. SWAP_COLOR(c);
  204. }
  205. else
  206. {
  207. (*pRc->drawTri)(pRc, a, b, c, 1);
  208. while (--clipNum) {
  209. (*pRc->HWSetupClipRect)(pRc, pClip++);
  210. (*pRc->drawTri)(pRc, a, b, c, 1);
  211. }
  212. }
  213. }
  214. ////////////////////////////////////////////////////////////////////////
  215. //
  216. // VOID FASTCALL __MCDRenderGenTriangle(DEVRC *pRc, MCDVERTEX *a,
  217. // MCDVERTEX *b, MCDVERTEX *c)
  218. //
  219. //
  220. // This is the generic triangle-rendering routine. This is used if either
  221. // of the polygon faces are not GL_FILL.
  222. //
  223. ////////////////////////////////////////////////////////////////////////
  224. //!! Fix clipping logic, add startXXX logic
  225. VOID FASTCALL __MCDRenderGenTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  226. MCDVERTEX *c)
  227. {
  228. LONG ccw, face;
  229. MCDVERTEX *oa, *ob, *oc;
  230. RECTL *pClip;
  231. ULONG clipNum;
  232. MCDFLOAT zOffset;
  233. MCDCOLOR tempA, tempB, tempC;
  234. ULONG polygonMode;
  235. BOOL backFace;
  236. MCDVERTEX *pv;
  237. MCDBG_PRINT("__MCDRenderGenTriangle");
  238. /*
  239. ** Save old vertex pointers in case we end up not doing a fill.
  240. */
  241. oa = a; ob = b; oc = c;
  242. SORT_AND_CULL_FACE(a, b, c, face, ccw);
  243. if ((clipNum = pRc->pEnumClip->c) > 1) {
  244. pClip = &pRc->pEnumClip->arcl[0];
  245. (*pRc->HWSetupClipRect)(pRc, pClip++);
  246. }
  247. polygonMode = pRc->polygonMode[face];
  248. backFace = (pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
  249. (face == __MCD_BACKFACE);
  250. // Pick correct face color and render the triangle:
  251. if (pRc->privateEnables & __MCDENABLE_SMOOTH) {
  252. if (backFace) {
  253. SWAP_COLOR(a);
  254. SWAP_COLOR(b);
  255. SWAP_COLOR(c);
  256. }
  257. } else { // Flat shading
  258. pv = pRc->pvProvoking;
  259. if (polygonMode == GL_FILL) {
  260. if (backFace) {
  261. SWAP_COLOR(pv);
  262. }
  263. } else {
  264. SAVE_COLOR(tempA, a);
  265. SAVE_COLOR(tempB, b);
  266. SAVE_COLOR(tempC, c);
  267. if (backFace) {
  268. SWAP_COLOR(pv);
  269. }
  270. a->colors[0] = pv->colors[0];
  271. b->colors[0] = pv->colors[0];
  272. c->colors[0] = pv->colors[0];
  273. }
  274. }
  275. // Render triangle using the current polygon mode for the face:
  276. switch (pRc->polygonMode[face]) {
  277. case GL_FILL:
  278. if (CASTINT(pRc->halfArea) != 0) {
  279. (*pRc->drawTri)(pRc, a, b, c, 1);
  280. while (--clipNum) {
  281. (*pRc->HWSetupClipRect)(pRc, pClip++);
  282. (*pRc->drawTri)(pRc, a, b, c, 1);
  283. }
  284. }
  285. break;
  286. case GL_POINT:
  287. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_POINT_ENABLE) {
  288. __MCDCalcZSlope(pRc, a, b, c);
  289. zOffset = __MCDGetZOffsetDelta(pRc) + pRc->MCDState.zOffsetUnits;
  290. oa->windowCoord.z += zOffset;
  291. ob->windowCoord.z += zOffset;
  292. oc->windowCoord.z += zOffset;
  293. }
  294. {
  295. unsigned int *pdwNext = pRc->ppdev->LL_State.pDL->pdwNext;
  296. // set x/y counts for 1 by 1 point
  297. *pdwNext++ = write_register( Y_COUNT_3D, 1 );
  298. *pdwNext++ = 0;
  299. *pdwNext++ = write_register( WIDTH1_3D, 1 );
  300. *pdwNext++ = 0x10000;
  301. // render proc will output from startoutptr, not from pdwNext,
  302. // so this will be sent in proc called below
  303. pRc->ppdev->LL_State.pDL->pdwNext = pdwNext;
  304. }
  305. if (oa->flags & MCDVERTEX_EDGEFLAG) {
  306. (*pRc->drawPoint)(pRc, oa);
  307. }
  308. if (ob->flags & MCDVERTEX_EDGEFLAG) {
  309. (*pRc->drawPoint)(pRc, ob);
  310. }
  311. if (oc->flags & MCDVERTEX_EDGEFLAG) {
  312. (*pRc->drawPoint)(pRc, oc);
  313. }
  314. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_POINT_ENABLE) {
  315. oa->windowCoord.z -= zOffset;
  316. ob->windowCoord.z -= zOffset;
  317. oc->windowCoord.z -= zOffset;
  318. }
  319. break;
  320. case GL_LINE:
  321. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_LINE_ENABLE) {
  322. __MCDCalcZSlope(pRc, a, b, c);
  323. zOffset = __MCDGetZOffsetDelta(pRc) + pRc->MCDState.zOffsetUnits;
  324. oa->windowCoord.z += zOffset;
  325. ob->windowCoord.z += zOffset;
  326. oc->windowCoord.z += zOffset;
  327. }
  328. if ((oa->flags & MCDVERTEX_EDGEFLAG) &&
  329. (ob->flags & MCDVERTEX_EDGEFLAG) &&
  330. (oc->flags & MCDVERTEX_EDGEFLAG)) {
  331. (*pRc->drawLine)(pRc, oa, ob, TRUE);
  332. (*pRc->drawLine)(pRc, ob, oc, 0);
  333. (*pRc->drawLine)(pRc, oc, oa, 0);
  334. } else {
  335. if (oa->flags & MCDVERTEX_EDGEFLAG)
  336. (*pRc->drawLine)(pRc, oa, ob, TRUE);
  337. if (ob->flags & MCDVERTEX_EDGEFLAG)
  338. (*pRc->drawLine)(pRc, ob, oc, TRUE);
  339. if (oc->flags & MCDVERTEX_EDGEFLAG)
  340. (*pRc->drawLine)(pRc, oc, oa, TRUE);
  341. }
  342. if (pRc->MCDState.enables & MCD_POLYGON_OFFSET_LINE_ENABLE) {
  343. oa->windowCoord.z -= zOffset;
  344. ob->windowCoord.z -= zOffset;
  345. oc->windowCoord.z -= zOffset;
  346. }
  347. break;
  348. default:
  349. break;
  350. }
  351. // Restore original colors if needed:
  352. if (pRc->privateEnables & __MCDENABLE_SMOOTH) {
  353. if (backFace) {
  354. SWAP_COLOR(a);
  355. SWAP_COLOR(b);
  356. SWAP_COLOR(c);
  357. }
  358. } else { // Flat shading
  359. if (polygonMode == GL_FILL) {
  360. if (backFace) {
  361. SWAP_COLOR(pv);
  362. }
  363. } else {
  364. if (backFace) {
  365. SWAP_COLOR(pv);
  366. }
  367. RESTORE_COLOR(tempA, a);
  368. RESTORE_COLOR(tempB, b);
  369. RESTORE_COLOR(tempC, c);
  370. }
  371. }
  372. }
  373. ////////////////////////////////////////////////////////////////////////
  374. //
  375. // VOID FASTCALL __MCDRenderFlatTriangle(DEVRC *pRc, MCDVERTEX *a,
  376. // MCDVERTEX *b, MCDVERTEX *c)
  377. //
  378. //
  379. // This is the top-level flat-shaded triangle renderer.
  380. //
  381. ////////////////////////////////////////////////////////////////////////
  382. VOID FASTCALL __MCDRenderFlatTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  383. MCDVERTEX *c)
  384. {
  385. LONG ccw, face;
  386. RECTL *pClip;
  387. ULONG clipNum;
  388. // MCDBG_PRINT("__MCDRenderFlatTriangle");
  389. SORT_AND_CULL_FACE(a, b, c, face, ccw);
  390. if (CASTINT(pRc->halfArea) == 0)
  391. return;
  392. if ((clipNum = pRc->pEnumClip->c) > 1) {
  393. pClip = &pRc->pEnumClip->arcl[0];
  394. (*pRc->HWSetupClipRect)(pRc, pClip++);
  395. }
  396. // Pick correct face color and render the triangle:
  397. if ((pRc->privateEnables & __MCDENABLE_TWOSIDED) &&
  398. (face == __MCD_BACKFACE))
  399. {
  400. MCDVERTEX *pv = pRc->pvProvoking;
  401. SWAP_COLOR(pv);
  402. (*pRc->drawTri)(pRc, a, b, c, 1);
  403. while (--clipNum) {
  404. (*pRc->HWSetupClipRect)(pRc, pClip++);
  405. (*pRc->drawTri)(pRc, a, b, c, 1);
  406. }
  407. SWAP_COLOR(pv);
  408. }
  409. else
  410. {
  411. (*pRc->drawTri)(pRc, a, b, c, 1);
  412. while (--clipNum) {
  413. (*pRc->HWSetupClipRect)(pRc, pClip++);
  414. (*pRc->drawTri)(pRc, a, b, c, 1);
  415. }
  416. }
  417. }