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.

1040 lines
34 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mcdclip.c
  3. *
  4. * Contains the line and polygon clipping routines for an MCD driver.
  5. *
  6. * Copyright (c) 1996 Microsoft Corporation
  7. \**************************************************************************/
  8. #include "precomp.h"
  9. #include "mcdhw.h"
  10. #include "mcdutil.h"
  11. #include "mcdmath.h"
  12. MCDCOORD __MCD_frustumClipPlanes[6] = {
  13. {(MCDFLOAT) 1.0, (MCDFLOAT) 0.0, (MCDFLOAT) 0.0, (MCDFLOAT) 1.0 }, // left
  14. {(MCDFLOAT)-1.0, (MCDFLOAT) 0.0, (MCDFLOAT) 0.0, (MCDFLOAT) 1.0 }, // right
  15. {(MCDFLOAT) 0.0, (MCDFLOAT) 1.0, (MCDFLOAT) 0.0, (MCDFLOAT) 1.0 }, // bottom
  16. {(MCDFLOAT) 0.0, (MCDFLOAT)-1.0, (MCDFLOAT) 0.0, (MCDFLOAT) 1.0 }, // top
  17. {(MCDFLOAT) 0.0, (MCDFLOAT) 0.0, (MCDFLOAT) 1.0, (MCDFLOAT) 1.0 }, // zNear
  18. {(MCDFLOAT) 0.0, (MCDFLOAT) 0.0, (MCDFLOAT)-1.0, (MCDFLOAT) 1.0 }, // zFar
  19. };
  20. ////////////////////////////////////////////////////////////////////////
  21. // Clipping macros used to build clip functions below.
  22. ////////////////////////////////////////////////////////////////////////
  23. #define __MCD_CLIP_POS(v, a, b, t) \
  24. v->clipCoord.x = t*(a->clipCoord.x - b->clipCoord.x) + b->clipCoord.x; \
  25. v->clipCoord.y = t*(a->clipCoord.y - b->clipCoord.y) + b->clipCoord.y; \
  26. v->clipCoord.z = t*(a->clipCoord.z - b->clipCoord.z) + b->clipCoord.z; \
  27. v->clipCoord.w = t*(a->clipCoord.w - b->clipCoord.w) + b->clipCoord.w
  28. // Note that we compute the values needed for both "cheap" fog only...
  29. #define __MCD_CLIP_FOG(v, a, b, t) \
  30. v->fog = t * (a->fog - b->fog) + b->fog;
  31. #define __MCD_CLIP_COLOR(v, a, b, t) \
  32. v->colors[__MCD_FRONTFACE].r = t*(a->colors[__MCD_FRONTFACE].r \
  33. - b->colors[__MCD_FRONTFACE].r) + b->colors[__MCD_FRONTFACE].r; \
  34. v->colors[__MCD_FRONTFACE].g = t*(a->colors[__MCD_FRONTFACE].g \
  35. - b->colors[__MCD_FRONTFACE].g) + b->colors[__MCD_FRONTFACE].g; \
  36. v->colors[__MCD_FRONTFACE].b = t*(a->colors[__MCD_FRONTFACE].b \
  37. - b->colors[__MCD_FRONTFACE].b) + b->colors[__MCD_FRONTFACE].b; \
  38. v->colors[__MCD_FRONTFACE].a = t*(a->colors[__MCD_FRONTFACE].a \
  39. - b->colors[__MCD_FRONTFACE].a) + b->colors[__MCD_FRONTFACE].a
  40. #define __MCD_CLIP_BACKCOLOR(v, a, b, t) \
  41. v->colors[__MCD_BACKFACE].r = t*(a->colors[__MCD_BACKFACE].r \
  42. - b->colors[__MCD_BACKFACE].r) + b->colors[__MCD_BACKFACE].r; \
  43. v->colors[__MCD_BACKFACE].g = t*(a->colors[__MCD_BACKFACE].g \
  44. - b->colors[__MCD_BACKFACE].g) + b->colors[__MCD_BACKFACE].g; \
  45. v->colors[__MCD_BACKFACE].b = t*(a->colors[__MCD_BACKFACE].b \
  46. - b->colors[__MCD_BACKFACE].b) + b->colors[__MCD_BACKFACE].b; \
  47. v->colors[__MCD_BACKFACE].a = t*(a->colors[__MCD_BACKFACE].a \
  48. - b->colors[__MCD_BACKFACE].a) + b->colors[__MCD_BACKFACE].a
  49. #define __MCD_CLIP_INDEX(v, a, b, t) \
  50. v->colors[__MCD_FRONTFACE].r = t*(a->colors[__MCD_FRONTFACE].r \
  51. - b->colors[__MCD_FRONTFACE].r) + b->colors[__MCD_FRONTFACE].r
  52. #define __MCD_CLIP_BACKINDEX(v, a, b, t) \
  53. v->colors[__MCD_BACKFACE].r = t*(a->colors[__MCD_BACKFACE].r \
  54. - b->colors[__MCD_BACKFACE].r) + b->colors[__MCD_BACKFACE].r
  55. #define __MCD_CLIP_TEXTURE(v, a, b, t) \
  56. v->texCoord.x = t*(a->texCoord.x - b->texCoord.x) + b->texCoord.x; \
  57. v->texCoord.y = t*(a->texCoord.y - b->texCoord.y) + b->texCoord.y;
  58. #ifdef CLIP_TEXTURE_XFORM
  59. v->texCoord.z = t*(a->texCoord.z - b->texCoord.z) + b->texCoord.z; \
  60. v->texCoord.w = t*(a->texCoord.w - b->texCoord.w) + b->texCoord.w
  61. #endif
  62. ////////////////////////////////////////////////////////////////////////
  63. // Clipping functions to clip vertices:
  64. ////////////////////////////////////////////////////////////////////////
  65. static VOID FASTCALL Clip(MCDVERTEX *dst, const MCDVERTEX *a,
  66. const MCDVERTEX *b, MCDFLOAT t)
  67. {
  68. __MCD_CLIP_POS(dst,a,b,t);
  69. }
  70. static VOID FASTCALL ClipC(MCDVERTEX *dst, const MCDVERTEX *a,
  71. const MCDVERTEX *b, MCDFLOAT t)
  72. {
  73. __MCD_CLIP_POS(dst,a,b,t);
  74. __MCD_CLIP_COLOR(dst,a,b,t);
  75. }
  76. static VOID FASTCALL ClipI(MCDVERTEX *dst, const MCDVERTEX *a,
  77. const MCDVERTEX *b, MCDFLOAT t)
  78. {
  79. __MCD_CLIP_POS(dst,a,b,t);
  80. __MCD_CLIP_INDEX(dst,a,b,t);
  81. }
  82. static VOID FASTCALL ClipBC(MCDVERTEX *dst, const MCDVERTEX *a,
  83. const MCDVERTEX *b, MCDFLOAT t)
  84. {
  85. __MCD_CLIP_POS(dst,a,b,t);
  86. __MCD_CLIP_COLOR(dst,a,b,t);
  87. __MCD_CLIP_BACKCOLOR(dst,a,b,t);
  88. }
  89. static VOID FASTCALL ClipBI(MCDVERTEX *dst, const MCDVERTEX *a,
  90. const MCDVERTEX *b, MCDFLOAT t)
  91. {
  92. __MCD_CLIP_POS(dst,a,b,t);
  93. __MCD_CLIP_INDEX(dst,a,b,t);
  94. __MCD_CLIP_BACKINDEX(dst,a,b,t);
  95. }
  96. static VOID FASTCALL ClipT(MCDVERTEX *dst, const MCDVERTEX *a,
  97. const MCDVERTEX *b, MCDFLOAT t)
  98. {
  99. __MCD_CLIP_POS(dst,a,b,t);
  100. __MCD_CLIP_TEXTURE(dst,a,b,t);
  101. }
  102. static VOID FASTCALL ClipIT(MCDVERTEX *dst, const MCDVERTEX *a,
  103. const MCDVERTEX *b, MCDFLOAT t)
  104. {
  105. __MCD_CLIP_POS(dst,a,b,t);
  106. __MCD_CLIP_INDEX(dst,a,b,t);
  107. __MCD_CLIP_TEXTURE(dst,a,b,t);
  108. }
  109. static VOID FASTCALL ClipBIT(MCDVERTEX *dst, const MCDVERTEX *a,
  110. const MCDVERTEX *b, MCDFLOAT t)
  111. {
  112. __MCD_CLIP_POS(dst,a,b,t);
  113. __MCD_CLIP_INDEX(dst,a,b,t);
  114. __MCD_CLIP_BACKINDEX(dst,a,b,t);
  115. __MCD_CLIP_TEXTURE(dst,a,b,t);
  116. }
  117. static VOID FASTCALL ClipCT(MCDVERTEX *dst, const MCDVERTEX *a,
  118. const MCDVERTEX *b, MCDFLOAT t)
  119. {
  120. __MCD_CLIP_POS(dst,a,b,t);
  121. __MCD_CLIP_COLOR(dst,a,b,t);
  122. __MCD_CLIP_TEXTURE(dst,a,b,t);
  123. }
  124. static VOID FASTCALL ClipBCT(MCDVERTEX *dst, const MCDVERTEX *a,
  125. const MCDVERTEX *b, MCDFLOAT t)
  126. {
  127. __MCD_CLIP_POS(dst,a,b,t);
  128. __MCD_CLIP_COLOR(dst,a,b,t);
  129. __MCD_CLIP_BACKCOLOR(dst,a,b,t);
  130. __MCD_CLIP_TEXTURE(dst,a,b,t);
  131. }
  132. static VOID FASTCALL ClipF(MCDVERTEX *dst, const MCDVERTEX *a,
  133. const MCDVERTEX *b, MCDFLOAT t)
  134. {
  135. __MCD_CLIP_POS(dst,a,b,t);
  136. __MCD_CLIP_FOG(dst,a,b,t);
  137. }
  138. static VOID FASTCALL ClipIF(MCDVERTEX *dst, const MCDVERTEX *a,
  139. const MCDVERTEX *b, MCDFLOAT t)
  140. {
  141. __MCD_CLIP_POS(dst,a,b,t);
  142. __MCD_CLIP_INDEX(dst,a,b,t);
  143. __MCD_CLIP_FOG(dst,a,b,t);
  144. }
  145. static VOID FASTCALL ClipCF(MCDVERTEX *dst, const MCDVERTEX *a,
  146. const MCDVERTEX *b, MCDFLOAT t)
  147. {
  148. __MCD_CLIP_POS(dst,a,b,t);
  149. __MCD_CLIP_COLOR(dst,a,b,t);
  150. __MCD_CLIP_FOG(dst,a,b,t);
  151. }
  152. static VOID FASTCALL ClipBCF(MCDVERTEX *dst, const MCDVERTEX *a,
  153. const MCDVERTEX *b, MCDFLOAT t)
  154. {
  155. __MCD_CLIP_POS(dst,a,b,t);
  156. __MCD_CLIP_COLOR(dst,a,b,t);
  157. __MCD_CLIP_BACKCOLOR(dst,a,b,t);
  158. __MCD_CLIP_FOG(dst,a,b,t);
  159. }
  160. static VOID FASTCALL ClipBIF(MCDVERTEX *dst, const MCDVERTEX *a,
  161. const MCDVERTEX *b, MCDFLOAT t)
  162. {
  163. __MCD_CLIP_POS(dst,a,b,t);
  164. __MCD_CLIP_INDEX(dst,a,b,t);
  165. __MCD_CLIP_BACKINDEX(dst,a,b,t);
  166. __MCD_CLIP_FOG(dst,a,b,t);
  167. }
  168. static VOID FASTCALL ClipFT(MCDVERTEX *dst, const MCDVERTEX *a,
  169. const MCDVERTEX *b, MCDFLOAT t)
  170. {
  171. __MCD_CLIP_POS(dst,a,b,t);
  172. __MCD_CLIP_FOG(dst,a,b,t);
  173. __MCD_CLIP_TEXTURE(dst,a,b,t);
  174. }
  175. static VOID FASTCALL ClipIFT(MCDVERTEX *dst, const MCDVERTEX *a,
  176. const MCDVERTEX *b, MCDFLOAT t)
  177. {
  178. __MCD_CLIP_POS(dst,a,b,t);
  179. __MCD_CLIP_INDEX(dst,a,b,t);
  180. __MCD_CLIP_FOG(dst,a,b,t);
  181. __MCD_CLIP_TEXTURE(dst,a,b,t);
  182. }
  183. static VOID FASTCALL ClipBIFT(MCDVERTEX *dst, const MCDVERTEX *a,
  184. const MCDVERTEX *b, MCDFLOAT t)
  185. {
  186. __MCD_CLIP_POS(dst,a,b,t);
  187. __MCD_CLIP_INDEX(dst,a,b,t);
  188. __MCD_CLIP_BACKINDEX(dst,a,b,t);
  189. __MCD_CLIP_FOG(dst,a,b,t);
  190. __MCD_CLIP_TEXTURE(dst,a,b,t);
  191. }
  192. static VOID FASTCALL ClipCFT(MCDVERTEX *dst, const MCDVERTEX *a,
  193. const MCDVERTEX *b, MCDFLOAT t)
  194. {
  195. __MCD_CLIP_POS(dst,a,b,t);
  196. __MCD_CLIP_COLOR(dst,a,b,t);
  197. __MCD_CLIP_FOG(dst,a,b,t);
  198. __MCD_CLIP_TEXTURE(dst,a,b,t);
  199. }
  200. static VOID FASTCALL ClipBCFT(MCDVERTEX *dst, const MCDVERTEX *a,
  201. const MCDVERTEX *b, MCDFLOAT t)
  202. {
  203. __MCD_CLIP_POS(dst,a,b,t);
  204. __MCD_CLIP_COLOR(dst,a,b,t);
  205. __MCD_CLIP_BACKCOLOR(dst,a,b,t);
  206. __MCD_CLIP_FOG(dst,a,b,t);
  207. __MCD_CLIP_TEXTURE(dst,a,b,t);
  208. }
  209. static VOID (FASTCALL *clipProcs[20])(MCDVERTEX*, const MCDVERTEX*,
  210. const MCDVERTEX*, MCDFLOAT) =
  211. {
  212. Clip, ClipI, ClipC, ClipBI, ClipBC,
  213. ClipF, ClipIF, ClipCF, ClipBIF, ClipBCF,
  214. ClipT, ClipIT, ClipCT, ClipBIT, ClipBCT,
  215. ClipFT, ClipIFT, ClipCFT, ClipBIFT, ClipBCFT,
  216. };
  217. VOID FASTCALL __MCDPickClipFuncs(DEVRC *pRc)
  218. {
  219. LONG line = 0, poly = 0;
  220. BOOL twoSided = (pRc->MCDState.enables & MCD_LIGHTING_ENABLE) &&
  221. (pRc->MCDState.twoSided);
  222. if (pRc->MCDState.shadeModel != GL_FLAT) {
  223. line = 2;
  224. poly = (twoSided ? 4 : 2);
  225. }
  226. if (pRc->privateEnables & __MCDENABLE_FOG)
  227. {
  228. line += 5;
  229. poly += 5;
  230. }
  231. if (pRc->MCDState.textureEnabled)
  232. {
  233. line += 10;
  234. poly += 10;
  235. }
  236. pRc->lineClipParam = clipProcs[line];
  237. pRc->polyClipParam = clipProcs[poly];
  238. }
  239. ////////////////////////////////////////////////////////////////////////
  240. // The real primitive clippers:
  241. ////////////////////////////////////////////////////////////////////////
  242. /*
  243. ** The following is a discussion of the math used to do edge clipping against
  244. ** a clipping plane.
  245. **
  246. ** P1 is an end point of the edge
  247. ** P2 is the other end point of the edge
  248. **
  249. ** Q = t*P1 + (1 - t)*P2
  250. ** That is, Q lies somewhere on the line formed by P1 and P2.
  251. **
  252. ** 0 <= t <= 1
  253. ** This constrains Q to lie between P1 and P2.
  254. **
  255. ** C is the plane equation for the clipping plane
  256. **
  257. ** D1 = P1 dot C
  258. ** D1 is the distance between P1 and C. If P1 lies on the plane
  259. ** then D1 will be zero. The sign of D1 will determine which side
  260. ** of the plane that P1 is on, with negative being outside.
  261. **
  262. ** D2 = P2 dot C
  263. ** D2 is the distance between P2 and C. If P2 lies on the plane
  264. ** then D2 will be zero. The sign of D2 will determine which side
  265. ** of the plane that P2 is on, with negative being outside.
  266. **
  267. ** Because we are trying to find the intersection of the P1 P2 line
  268. ** segment with the clipping plane we require that:
  269. **
  270. ** Q dot C = 0
  271. **
  272. ** Therefore
  273. **
  274. ** (t*P1 + (1 - t)*P2) dot C = 0
  275. **
  276. ** (t*P1 + P2 - t*P2) dot C = 0
  277. **
  278. ** t*P1 dot C + P2 dot C - t*P2 dot C = 0
  279. **
  280. ** Substituting D1 and D2 in
  281. **
  282. ** t*D1 + D2 - t*D2 = 0
  283. **
  284. ** Solving for t
  285. **
  286. ** t = -D2 / (D1 - D2)
  287. **
  288. ** t = D2 / (D2 - D1)
  289. */
  290. static LONG clipToPlane(DEVRC *pRc, MCDVERTEX **iv, LONG niv,
  291. MCDVERTEX **ov, MCDCOORD *plane)
  292. {
  293. LONG i, nout, generated;
  294. MCDVERTEX *s, *p, *newVertex, *temp;
  295. MCDFLOAT pDist, sDist, t;
  296. MCDFLOAT zero = ZERO;
  297. VOID (FASTCALL *clip)(MCDVERTEX*, const MCDVERTEX*, const MCDVERTEX*, MCDFLOAT);
  298. nout = 0;
  299. generated = 0;
  300. temp = pRc->pNextClipTemp;
  301. clip = pRc->polyClipParam;
  302. s = iv[niv-1];
  303. sDist = (s->clipCoord.x * plane->x) + (s->clipCoord.y * plane->y) +
  304. (s->clipCoord.z * plane->z) + (s->clipCoord.w * plane->w);
  305. for (i = 0; i < niv; i++) {
  306. p = iv[i];
  307. pDist = (p->clipCoord.x * plane->x) + (p->clipCoord.y * plane->y) +
  308. (p->clipCoord.z * plane->z) + (p->clipCoord.w * plane->w);
  309. if (pDist >= zero) {
  310. /* p is inside the clipping plane half space */
  311. if (sDist >= zero) {
  312. /* s is inside the clipping plane half space */
  313. *ov++ = p;
  314. nout++;
  315. } else {
  316. /* s is outside the clipping plane half space */
  317. t = pDist / (pDist - sDist);
  318. newVertex = temp++;
  319. (*clip)(newVertex, s, p, t);
  320. newVertex->flags = s->flags;
  321. newVertex->clipCode = s->clipCode | __MCD_CLIPPED_VTX;
  322. *ov++ = newVertex;
  323. *ov++ = p;
  324. nout += 2;
  325. if (++generated >= 3) {
  326. /* Toss the non-convex polygon */
  327. return 0;
  328. }
  329. }
  330. } else {
  331. /* p is outside the clipping plane half space */
  332. if (sDist >= zero) {
  333. /*
  334. ** s is inside the clipping plane half space
  335. **
  336. ** NOTE: To avoid cracking in polygons with shared
  337. ** clipped edges we always compute "t" from the out
  338. ** vertex to the in vertex. The above clipping code gets
  339. ** this for free (p is in and s is out). In this code p
  340. ** is out and s is in, so we reverse the t computation
  341. ** and the argument order to __MCDDoClip.
  342. */
  343. t = sDist / (sDist - pDist);
  344. newVertex = temp++;
  345. (*clip)(newVertex, p, s, t);
  346. newVertex->flags = s->flags | MCDVERTEX_EDGEFLAG;
  347. newVertex->clipCode = p->clipCode | __MCD_CLIPPED_VTX;
  348. *ov++ = newVertex;
  349. nout++;
  350. if (++generated >= 3) {
  351. /* Toss the non-convex polygon */
  352. return 0;
  353. }
  354. } else {
  355. /* both points are outside */
  356. }
  357. }
  358. s = p;
  359. sDist = pDist;
  360. }
  361. pRc->pNextClipTemp = temp;
  362. return nout;
  363. }
  364. /*
  365. ** Identical to clipToPlane(), except that the clipping is done in eye
  366. ** space.
  367. */
  368. static LONG clipToPlaneEye(DEVRC *pRc, MCDVERTEX **iv, LONG niv,
  369. MCDVERTEX **ov, MCDCOORD *plane)
  370. {
  371. LONG i, nout, generated;
  372. MCDVERTEX *s, *p, *newVertex, *temp;
  373. MCDFLOAT pDist, sDist, t;
  374. MCDFLOAT zero = __MCDZERO;
  375. VOID (FASTCALL *clip)(MCDVERTEX*, const MCDVERTEX*, const MCDVERTEX*, MCDFLOAT);
  376. nout = 0;
  377. generated = 0;
  378. temp = pRc->pNextClipTemp;
  379. clip = pRc->polyClipParam;
  380. s = iv[niv-1];
  381. sDist = (s->eyeCoord.x * plane->x) +
  382. (s->eyeCoord.y * plane->y) +
  383. (s->eyeCoord.z * plane->z) +
  384. (s->eyeCoord.w * plane->w);
  385. for (i = 0; i < niv; i++) {
  386. p = iv[i];
  387. pDist = (p->eyeCoord.x * plane->x) +
  388. (p->eyeCoord.y * plane->y) +
  389. (p->eyeCoord.z * plane->z) +
  390. (p->eyeCoord.w * plane->w);
  391. if (pDist >= zero) {
  392. /* p is inside the clipping plane half space */
  393. if (sDist >= zero) {
  394. /* s is inside the clipping plane half space */
  395. *ov++ = p;
  396. nout++;
  397. } else {
  398. /* s is outside the clipping plane half space */
  399. t = pDist / (pDist - sDist);
  400. newVertex = temp++;
  401. (*clip)(newVertex, s, p, t);
  402. newVertex->eyeCoord.x = t*(s->eyeCoord.x - p->eyeCoord.x) + p->eyeCoord.x;
  403. newVertex->eyeCoord.y = t*(s->eyeCoord.y - p->eyeCoord.y) + p->eyeCoord.y;
  404. newVertex->eyeCoord.z = t*(s->eyeCoord.z - p->eyeCoord.z) + p->eyeCoord.z;
  405. newVertex->eyeCoord.w = t*(s->eyeCoord.w - p->eyeCoord.w) + p->eyeCoord.w;
  406. newVertex->flags = s->flags;
  407. newVertex->clipCode = s->clipCode | __MCD_CLIPPED_VTX;
  408. *ov++ = newVertex;
  409. *ov++ = p;
  410. nout += 2;
  411. if (++generated >= 3) {
  412. /* Toss the non-convex polygon */
  413. return 0;
  414. }
  415. }
  416. } else {
  417. /* p is outside the clipping plane half space */
  418. if (sDist >= zero) {
  419. /*
  420. ** s is inside the clipping plane half space
  421. **
  422. ** NOTE: To avoid cracking in polygons with shared
  423. ** clipped edges we always compute "t" from the out
  424. ** vertex to the in vertex. The above clipping code gets
  425. ** this for free (p is in and s is out). In this code p
  426. ** is out and s is in, so we reverse the t computation
  427. ** and the argument order to __MCDDoClip.
  428. */
  429. t = sDist / (sDist - pDist);
  430. newVertex = temp++;
  431. (*clip)(newVertex, p, s, t);
  432. newVertex->eyeCoord.x = t*(p->eyeCoord.x - s->eyeCoord.x) + s->eyeCoord.x;
  433. newVertex->eyeCoord.y = t*(p->eyeCoord.y - s->eyeCoord.y) + s->eyeCoord.y;
  434. newVertex->eyeCoord.z = t*(p->eyeCoord.z - s->eyeCoord.z) + s->eyeCoord.z;
  435. newVertex->eyeCoord.w = t*(p->eyeCoord.w - s->eyeCoord.w) + s->eyeCoord.w;
  436. newVertex->flags = s->flags | MCDVERTEX_EDGEFLAG;
  437. newVertex->clipCode = p->clipCode | __MCD_CLIPPED_VTX;
  438. *ov++ = newVertex;
  439. nout++;
  440. if (++generated >= 3) {
  441. /* Toss the non-convex polygon */
  442. return 0;
  443. }
  444. } else {
  445. /* both points are outside */
  446. }
  447. }
  448. s = p;
  449. sDist = pDist;
  450. }
  451. pRc->pNextClipTemp = temp;
  452. return nout;
  453. }
  454. /*
  455. ** Each clipping plane can add at most one vertex to a convex polygon (it may
  456. ** remove up to all of the vertices). The clipping will leave a polygon
  457. ** convex. Because of this the maximum number of verticies output from
  458. ** the clipToPlane procedure will be total number of clip planes (assuming
  459. ** each plane adds one new vertex) plus the original number of verticies
  460. ** (3 since this if for triangles).
  461. */
  462. #define __MCD_TOTAL_CLIP_PLANES 6 + MCD_MAX_USER_CLIP_PLANES
  463. #define __MCD_MAX_POLYGON_CLIP_SIZE 256
  464. #define __MCD_MAX_CLIP_VERTEX (__MCD_TOTAL_CLIP_PLANES + __MCD_MAX_POLYGON_CLIP_SIZE)
  465. void FASTCALL __MCDDoClippedPolygon(DEVRC *pRc, MCDVERTEX **iv, LONG nout,
  466. ULONG allClipCodes)
  467. {
  468. MCDVERTEX *ov[__MCD_TOTAL_CLIP_PLANES][__MCD_MAX_CLIP_VERTEX];
  469. MCDVERTEX **ivp;
  470. MCDVERTEX **ovp;
  471. MCDVERTEX *p0, *p1, *p2;
  472. MCDCOORD *plane;
  473. LONG i;
  474. MCDFLOAT one;
  475. VOID (FASTCALL *rt)(DEVRC*, MCDVERTEX*, MCDVERTEX*, MCDVERTEX*);
  476. MCDFLOAT llx, lly, urx, ury;
  477. MCDFLOAT winx, winy;
  478. ULONG clipCodes;
  479. /*
  480. ** Reset nextClipTemp pointer for any new verticies that are generated
  481. ** during the clipping.
  482. */
  483. pRc->pNextClipTemp = &pRc->clipTemp[0];
  484. ivp = &iv[0];
  485. /*
  486. ** Check each of the clipping planes by examining the allClipCodes
  487. ** mask. Note that no bits will be set in allClipCodes for clip
  488. ** planes that are not enabled.
  489. */
  490. if (allClipCodes) {
  491. /* Now clip against the clipping planes */
  492. ovp = &ov[0][0];
  493. /*
  494. ** Do user clip planes first, because we will maintain eye coordinates
  495. ** only while doing user clip planes. They are ignored for the
  496. ** frustum clipping planes.
  497. */
  498. clipCodes = (allClipCodes >> 6) & __MCD_USER_CLIP_MASK;
  499. if (clipCodes) {
  500. plane = &pRc->MCDState.userClipPlanes[0];
  501. do {
  502. if (clipCodes & 1) {
  503. nout = clipToPlaneEye(pRc, ivp, nout, ovp, plane);
  504. if (nout < 3) {
  505. return;
  506. }
  507. ivp = ovp;
  508. ovp += __MCD_MAX_CLIP_VERTEX;
  509. }
  510. clipCodes >>= 1;
  511. plane++;
  512. } while (clipCodes);
  513. }
  514. allClipCodes &= MCD_CLIP_MASK;
  515. if (allClipCodes) {
  516. plane = &__MCD_frustumClipPlanes[0];
  517. do {
  518. if (allClipCodes & 1) {
  519. nout = clipToPlane(pRc, ivp, nout, ovp, plane);
  520. if (nout < 3) {
  521. return;
  522. }
  523. ivp = ovp;
  524. ovp += __MCD_MAX_CLIP_VERTEX;
  525. }
  526. allClipCodes >>= 1;
  527. plane++;
  528. } while (allClipCodes);
  529. }
  530. /*
  531. ** Calculate final screen coordinates. Next phase of polygon
  532. ** processing assumes that window coordinates are already computed.
  533. */
  534. ovp = ivp;
  535. one = __MCDONE;
  536. llx = pRc->MCDViewport.xCenter - pRc->MCDViewport.xScale;
  537. urx = pRc->MCDViewport.xCenter + pRc->MCDViewport.xScale;
  538. if (pRc->MCDViewport.yScale > 0) {
  539. lly = pRc->MCDViewport.yCenter - pRc->MCDViewport.yScale;
  540. ury = pRc->MCDViewport.yCenter + pRc->MCDViewport.yScale;
  541. } else {
  542. lly = pRc->MCDViewport.yCenter + pRc->MCDViewport.yScale;
  543. ury = pRc->MCDViewport.yCenter - pRc->MCDViewport.yScale;
  544. }
  545. for (i = nout; --i >= 0; ) {
  546. MCDFLOAT wInv;
  547. p0 = *ovp++;
  548. // change to original DDK code - only recompute windowCoord data if
  549. // this vertex actually an intersection found during clipping.
  550. // Or is one that had non-zero clipcode - meaning window coords may not be correct
  551. // If this is an original unclipped vertex, then windowCoord data should
  552. // be OK as is, and don't want to recompute. Recomputing can give
  553. // slightly different result than original. When neighboring triangles
  554. // share a vertex, if 1 triangle clipped, and the other not, the clipped
  555. // one's unclipped vertices can be altered slightly by this computation,
  556. // resulting in cracks when subpixel-precision triangle rendering is enabled.
  557. // __MCD_CLIPPED_VTX is OR'd into clipcode for vertices resulting from clip
  558. // so clipCode is non-zero
  559. if (p0->clipCode)
  560. {
  561. if (p0->clipCoord.w == (MCDFLOAT) 0.0)
  562. wInv = (MCDFLOAT) 0.0;
  563. else
  564. wInv = one / p0->clipCoord.w;
  565. winx = p0->clipCoord.x * pRc->MCDViewport.xScale * wInv +
  566. pRc->MCDViewport.xCenter;
  567. winy = p0->clipCoord.y * pRc->MCDViewport.yScale * wInv +
  568. pRc->MCDViewport.yCenter;
  569. /*
  570. ** Check if these window coordinates are legal. At this
  571. ** point, it is quite possible that they are not. Trivially
  572. ** pull them into the legal viewport region if necessary.
  573. */
  574. if (winx < llx) winx = llx;
  575. else if (winx > urx) winx = urx;
  576. if (winy < lly) winy = lly;
  577. else if (winy > ury) winy = ury;
  578. p0->windowCoord.x = winx;
  579. p0->windowCoord.y = winy;
  580. p0->windowCoord.z = p0->clipCoord.z * pRc->MCDViewport.zScale * wInv +
  581. pRc->MCDViewport.zCenter;
  582. p0->windowCoord.w = wInv;
  583. }
  584. }
  585. }
  586. /*
  587. ** Subdivide the clipped polygon into triangles. Only convex polys
  588. ** are supported so this is okay to do. Non-convex polys will do
  589. ** something odd here, but thats the clients fault.
  590. */
  591. p0 = *ivp++;
  592. p1 = *ivp++;
  593. p2 = *ivp++;
  594. rt = pRc->renderTri;
  595. if (nout == 3) {
  596. (*rt)(pRc, p0, p1, p2);
  597. } else {
  598. for (i = 0; i < nout - 2; i++) {
  599. ULONG t1, t2;
  600. if (i == 0) {
  601. /*
  602. ** Third edge of first sub-triangle is always non-boundary
  603. */
  604. t1 = p2->flags & MCDVERTEX_EDGEFLAG;
  605. p2->flags &= ~MCDVERTEX_EDGEFLAG;
  606. (*rt)(pRc, p0, p1, p2);
  607. p2->flags |= t1;
  608. } else
  609. if (i == nout - 3) {
  610. /*
  611. ** First edge of last sub-triangle is always non-boundary
  612. */
  613. t1 = p0->flags & MCDVERTEX_EDGEFLAG;
  614. p0->flags &= ~MCDVERTEX_EDGEFLAG;
  615. (*rt)(pRc, p0, p1, p2);
  616. p0->flags |= t1;
  617. } else {
  618. /*
  619. ** Interior sub-triangles have the first and last edge
  620. ** marked non-boundary
  621. */
  622. t1 = p0->flags & MCDVERTEX_EDGEFLAG;
  623. t2 = p2->flags & MCDVERTEX_EDGEFLAG;
  624. p0->flags &= ~MCDVERTEX_EDGEFLAG;
  625. p2->flags &= ~MCDVERTEX_EDGEFLAG;
  626. (*rt)(pRc, p0, p1, p2);
  627. p0->flags |= t1;
  628. p2->flags |= t2;
  629. }
  630. p1 = p2;
  631. p2 = (MCDVERTEX *) *ivp++;
  632. }
  633. }
  634. }
  635. VOID FASTCALL __MCDClipPolygon(DEVRC *pRc, MCDVERTEX *v0, LONG nv)
  636. {
  637. MCDVERTEX *iv[__MCD_MAX_POLYGON_CLIP_SIZE];
  638. MCDVERTEX **ivp;
  639. LONG i;
  640. ULONG andCodes, orCodes;
  641. pRc->pvProvoking = v0;
  642. /*
  643. ** Generate array of addresses of the verticies. And all the
  644. ** clip codes together while we are at it.
  645. */
  646. ivp = &iv[0];
  647. andCodes = 0;
  648. orCodes = 0;
  649. for (i = nv; --i >= 0; ) {
  650. andCodes &= v0->clipCode;
  651. orCodes |= v0->clipCode;
  652. *ivp++ = v0++;
  653. }
  654. if (andCodes != 0) {
  655. /*
  656. ** Trivially reject the polygon. If andCodes is non-zero then
  657. ** every vertex in the polygon is outside of the same set of
  658. ** clipping planes (at least one).
  659. */
  660. return;
  661. }
  662. __MCDDoClippedPolygon(pRc, &iv[0], nv, orCodes);
  663. }
  664. void FASTCALL __MCDClipTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  665. MCDVERTEX *c, ULONG orCodes)
  666. {
  667. MCDVERTEX *iv[3];
  668. iv[0] = a;
  669. iv[1] = b;
  670. iv[2] = c;
  671. __MCDDoClippedPolygon(pRc, &iv[0], 3, orCodes);
  672. }
  673. ////////////////////////////////////////////////////////////////////////
  674. // Line clipping:
  675. ////////////////////////////////////////////////////////////////////////
  676. //
  677. // Clip a line against the frustum clip planes and any user clipping planes.
  678. // If an edge remains after clipping then compute the window coordinates
  679. // and invoke the renderer.
  680. //
  681. // Notice: This algorithim is an example of an implementation that is
  682. // different than what the spec says. This is equivalent in functionality
  683. // and meets the spec, but doesn't clip in eye space. This clipper clips
  684. // in NTVP (clip) space.
  685. //
  686. // Trivial accept/reject has already been dealt with.
  687. //
  688. VOID FASTCALL __MCDClipLine(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  689. BOOL bResetLine)
  690. {
  691. MCDVERTEX *provokingA = a;
  692. MCDVERTEX *provokingB = b;
  693. MCDVERTEX np1, np2;
  694. MCDCOORD *plane;
  695. ULONG needs, allClipCodes, clipCodes;
  696. VOID (FASTCALL *clip)(MCDVERTEX*, const MCDVERTEX*, const MCDVERTEX*, MCDFLOAT);
  697. MCDFLOAT zero;
  698. MCDFLOAT winx, winy;
  699. MCDFLOAT vpXCenter, vpYCenter, vpZCenter;
  700. MCDFLOAT vpXScale, vpYScale, vpZScale;
  701. MCDVIEWPORT *vp;
  702. MCDFLOAT x, y, z, wInv;
  703. allClipCodes = a->clipCode | b->clipCode;
  704. /*
  705. ** For each clipping plane that something is out on, clip
  706. ** check the verticies. Note that no bits will be set in
  707. ** allClipCodes for clip planes that are not enabled.
  708. */
  709. zero = __MCDZERO;
  710. clip = pRc->lineClipParam;
  711. /*
  712. ** Do user clip planes first, because we will maintain eye coordinates
  713. ** only while doing user clip planes. They are ignored for the
  714. ** frustum clipping planes.
  715. */
  716. clipCodes = (allClipCodes >> 6) & __MCD_USER_CLIP_MASK;
  717. if (clipCodes) {
  718. plane = &pRc->MCDState.userClipPlanes[0];
  719. do {
  720. /*
  721. ** See if this clip plane has anything out of it. If not,
  722. ** press onward to check the next plane. Note that we
  723. ** shift this mask to the right at the bottom of the loop.
  724. */
  725. if (clipCodes & 1) {
  726. MCDFLOAT t, d1, d2;
  727. d1 = (plane->x * a->eyeCoord.x) +
  728. (plane->y * a->eyeCoord.y) +
  729. (plane->z * a->eyeCoord.z) +
  730. (plane->w * a->eyeCoord.w);
  731. d2 = (plane->x * b->eyeCoord.x) +
  732. (plane->y * b->eyeCoord.y) +
  733. (plane->z * b->eyeCoord.z) +
  734. (plane->w * b->eyeCoord.w);
  735. if (d1 < zero) {
  736. /* a is out */
  737. if (d2 < zero) {
  738. /* a & b are out */
  739. return;
  740. }
  741. /*
  742. ** A is out and B is in. Compute new A coordinate
  743. ** clipped to the plane.
  744. */
  745. t = d2 / (d2 - d1);
  746. (*clip)(&np1, a, b, t);
  747. (&np1)->eyeCoord.x =
  748. t*(a->eyeCoord.x - b->eyeCoord.x) + b->eyeCoord.x;
  749. (&np1)->eyeCoord.y =
  750. t*(a->eyeCoord.y - b->eyeCoord.y) + b->eyeCoord.y;
  751. (&np1)->eyeCoord.z =
  752. t*(a->eyeCoord.z - b->eyeCoord.z) + b->eyeCoord.z;
  753. (&np1)->eyeCoord.w =
  754. t*(a->eyeCoord.w - b->eyeCoord.w) + b->eyeCoord.w;
  755. a = &np1;
  756. a->flags = b->flags;
  757. if (pRc->MCDState.shadeModel == GL_FLAT)
  758. {
  759. COPY_COLOR(a->colors[0], provokingA->colors[0]);
  760. }
  761. } else {
  762. /* a is in */
  763. if (d2 < zero) {
  764. /*
  765. ** A is in and B is out. Compute new B
  766. ** coordinate clipped to the plane.
  767. **
  768. ** NOTE: To avoid cracking in polygons with
  769. ** shared clipped edges we always compute "t"
  770. ** from the out vertex to the in vertex. The
  771. ** above clipping code gets this for free (b is
  772. ** in and a is out). In this code b is out and a
  773. ** is in, so we reverse the t computation and the
  774. ** argument order to (*clip).
  775. */
  776. t = d1 / (d1 - d2);
  777. (*clip)(&np2, b, a, t);
  778. (&np2)->eyeCoord.x =
  779. t*(b->eyeCoord.x - a->eyeCoord.x) + a->eyeCoord.x;
  780. (&np2)->eyeCoord.y =
  781. t*(b->eyeCoord.y - a->eyeCoord.y) + a->eyeCoord.y;
  782. (&np2)->eyeCoord.z =
  783. t*(b->eyeCoord.z - a->eyeCoord.z) + a->eyeCoord.z;
  784. (&np2)->eyeCoord.w =
  785. t*(b->eyeCoord.w - a->eyeCoord.w) + a->eyeCoord.w;
  786. b = &np2;
  787. b->flags = a->flags;
  788. if (pRc->MCDState.shadeModel == GL_FLAT)
  789. {
  790. COPY_COLOR(b->colors[0], provokingB->colors[0]);
  791. }
  792. } else {
  793. /* A and B are in */
  794. }
  795. }
  796. }
  797. plane++;
  798. clipCodes >>= 1;
  799. } while (clipCodes);
  800. }
  801. allClipCodes &= MCD_CLIP_MASK;
  802. if (allClipCodes) {
  803. plane = &__MCD_frustumClipPlanes[0];
  804. do {
  805. /*
  806. ** See if this clip plane has anything out of it. If not,
  807. ** press onward to check the next plane. Note that we
  808. ** shift this mask to the right at the bottom of the loop.
  809. */
  810. if (allClipCodes & 1) {
  811. MCDFLOAT t, d1, d2;
  812. d1 = (plane->x * a->clipCoord.x) + (plane->y * a->clipCoord.y) +
  813. (plane->z * a->clipCoord.z) + (plane->w * a->clipCoord.w);
  814. d2 = (plane->x * b->clipCoord.x) + (plane->y * b->clipCoord.y) +
  815. (plane->z * b->clipCoord.z) + (plane->w * b->clipCoord.w);
  816. if (d1 < zero) {
  817. /* a is out */
  818. if (d2 < zero) {
  819. /* a & b are out */
  820. return;
  821. }
  822. /*
  823. ** A is out and B is in. Compute new A coordinate
  824. ** clipped to the plane.
  825. */
  826. t = d2 / (d2 - d1);
  827. (*clip)(&np1, a, b, t);
  828. a = &np1;
  829. a->flags = b->flags;
  830. if (pRc->MCDState.shadeModel == GL_FLAT)
  831. {
  832. COPY_COLOR(a->colors[0], provokingA->colors[0]);
  833. }
  834. } else {
  835. /* a is in */
  836. if (d2 < zero) {
  837. /*
  838. ** A is in and B is out. Compute new B
  839. ** coordinate clipped to the plane.
  840. **
  841. ** NOTE: To avoid cracking in polygons with
  842. ** shared clipped edges we always compute "t"
  843. ** from the out vertex to the in vertex. The
  844. ** above clipping code gets this for free (b is
  845. ** in and a is out). In this code b is out and a
  846. ** is in, so we reverse the t computation and the
  847. ** argument order to (*clip).
  848. */
  849. t = d1 / (d1 - d2);
  850. (*clip)(&np2, b, a, t);
  851. b = &np2;
  852. b->flags = a->flags;
  853. if (pRc->MCDState.shadeModel == GL_FLAT)
  854. {
  855. COPY_COLOR(b->colors[0], provokingB->colors[0]);
  856. }
  857. } else {
  858. /* A and B are in */
  859. }
  860. }
  861. }
  862. plane++;
  863. allClipCodes >>= 1;
  864. } while (allClipCodes);
  865. }
  866. vp = &pRc->MCDViewport;
  867. vpXCenter = vp->xCenter;
  868. vpYCenter = vp->yCenter;
  869. vpZCenter = vp->zCenter;
  870. vpXScale = vp->xScale;
  871. vpYScale = vp->yScale;
  872. vpZScale = vp->zScale;
  873. /* Compute window coordinates for both vertices. */
  874. wInv = __MCDONE / a->clipCoord.w;
  875. x = a->clipCoord.x;
  876. y = a->clipCoord.y;
  877. z = a->clipCoord.z;
  878. winx = x * vpXScale * wInv + vpXCenter;
  879. winy = y * vpYScale * wInv + vpYCenter;
  880. a->windowCoord.z = z * vpZScale * wInv + vpZCenter;
  881. a->windowCoord.w = wInv;
  882. a->windowCoord.x = winx;
  883. a->windowCoord.y = winy;
  884. wInv = __MCDONE / b->clipCoord.w;
  885. x = b->clipCoord.x;
  886. y = b->clipCoord.y;
  887. z = b->clipCoord.z;
  888. winx = x * vpXScale * wInv + vpXCenter;
  889. winy = y * vpYScale * wInv + vpYCenter;
  890. b->windowCoord.z = z * vpZScale * wInv + vpZCenter;
  891. b->windowCoord.w = wInv;
  892. b->windowCoord.x = winx;
  893. b->windowCoord.y = winy;
  894. /* Validate line state */
  895. if (pRc->MCDState.shadeModel == GL_FLAT) {
  896. // Add the vertices then restore the b color pointer
  897. //
  898. // Note that although b is the only new vertex, up
  899. // to two vertices can be added because each new vertex
  900. // generated by clipping must be added. For a line where
  901. // both endpoints are out of the clipping region, both
  902. // an entry and an exit vertex must be added
  903. if (provokingA->clipCode != 0)
  904. {
  905. // a was out so a new vertex was added at the point of
  906. // entry
  907. bResetLine = TRUE;
  908. }
  909. // b is always added since either:
  910. // b was in and is new so it needs to be added
  911. // b was out so a new vertex was added at the exit point
  912. (*pRc->renderLine)(pRc, a, b, bResetLine);
  913. } else {
  914. if (provokingA->clipCode != 0)
  915. {
  916. bResetLine = TRUE;
  917. }
  918. (*pRc->renderLine)(pRc, a, b, bResetLine);
  919. }
  920. }