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.

1032 lines
32 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->bRGBMode) {
  223. if (pRc->MCDState.shadeModel != GL_FLAT) {
  224. line = 2;
  225. poly = (twoSided ? 4 : 2);
  226. }
  227. } else {
  228. if (pRc->MCDState.shadeModel != GL_FLAT) {
  229. line = 1;
  230. poly = (twoSided ? 3 : 1);
  231. }
  232. }
  233. if ((pRc->bCheapFog) && !(pRc->MCDState.shadeModel == GL_SMOOTH)) {
  234. {
  235. line += 5;
  236. poly += 5;
  237. }
  238. }
  239. if (pRc->MCDState.textureEnabled) {
  240. line += 10;
  241. poly += 10;
  242. }
  243. pRc->lineClipParam = clipProcs[line];
  244. pRc->polyClipParam = clipProcs[poly];
  245. }
  246. ////////////////////////////////////////////////////////////////////////
  247. // The real primitive clippers:
  248. ////////////////////////////////////////////////////////////////////////
  249. /*
  250. ** The following is a discussion of the math used to do edge clipping against
  251. ** a clipping plane.
  252. **
  253. ** P1 is an end point of the edge
  254. ** P2 is the other end point of the edge
  255. **
  256. ** Q = t*P1 + (1 - t)*P2
  257. ** That is, Q lies somewhere on the line formed by P1 and P2.
  258. **
  259. ** 0 <= t <= 1
  260. ** This constrains Q to lie between P1 and P2.
  261. **
  262. ** C is the plane equation for the clipping plane
  263. **
  264. ** D1 = P1 dot C
  265. ** D1 is the distance between P1 and C. If P1 lies on the plane
  266. ** then D1 will be zero. The sign of D1 will determine which side
  267. ** of the plane that P1 is on, with negative being outside.
  268. **
  269. ** D2 = P2 dot C
  270. ** D2 is the distance between P2 and C. If P2 lies on the plane
  271. ** then D2 will be zero. The sign of D2 will determine which side
  272. ** of the plane that P2 is on, with negative being outside.
  273. **
  274. ** Because we are trying to find the intersection of the P1 P2 line
  275. ** segment with the clipping plane we require that:
  276. **
  277. ** Q dot C = 0
  278. **
  279. ** Therefore
  280. **
  281. ** (t*P1 + (1 - t)*P2) dot C = 0
  282. **
  283. ** (t*P1 + P2 - t*P2) dot C = 0
  284. **
  285. ** t*P1 dot C + P2 dot C - t*P2 dot C = 0
  286. **
  287. ** Substituting D1 and D2 in
  288. **
  289. ** t*D1 + D2 - t*D2 = 0
  290. **
  291. ** Solving for t
  292. **
  293. ** t = -D2 / (D1 - D2)
  294. **
  295. ** t = D2 / (D2 - D1)
  296. */
  297. static LONG clipToPlane(DEVRC *pRc, MCDVERTEX **iv, LONG niv,
  298. MCDVERTEX **ov, MCDCOORD *plane)
  299. {
  300. LONG i, nout, generated;
  301. MCDVERTEX *s, *p, *newVertex, *temp;
  302. MCDFLOAT pDist, sDist, t;
  303. MCDFLOAT zero = ZERO;
  304. VOID (FASTCALL *clip)(MCDVERTEX*, const MCDVERTEX*, const MCDVERTEX*, MCDFLOAT);
  305. nout = 0;
  306. generated = 0;
  307. temp = pRc->pNextClipTemp;
  308. clip = pRc->polyClipParam;
  309. s = iv[niv-1];
  310. sDist = (s->clipCoord.x * plane->x) + (s->clipCoord.y * plane->y) +
  311. (s->clipCoord.z * plane->z) + (s->clipCoord.w * plane->w);
  312. for (i = 0; i < niv; i++) {
  313. p = iv[i];
  314. pDist = (p->clipCoord.x * plane->x) + (p->clipCoord.y * plane->y) +
  315. (p->clipCoord.z * plane->z) + (p->clipCoord.w * plane->w);
  316. if (pDist >= zero) {
  317. /* p is inside the clipping plane half space */
  318. if (sDist >= zero) {
  319. /* s is inside the clipping plane half space */
  320. *ov++ = p;
  321. nout++;
  322. } else {
  323. /* s is outside the clipping plane half space */
  324. t = pDist / (pDist - sDist);
  325. newVertex = temp++;
  326. (*clip)(newVertex, s, p, t);
  327. newVertex->flags = s->flags;
  328. newVertex->clipCode = s->clipCode;
  329. *ov++ = newVertex;
  330. *ov++ = p;
  331. nout += 2;
  332. if (++generated >= 3) {
  333. /* Toss the non-convex polygon */
  334. return 0;
  335. }
  336. }
  337. } else {
  338. /* p is outside the clipping plane half space */
  339. if (sDist >= zero) {
  340. /*
  341. ** s is inside the clipping plane half space
  342. **
  343. ** NOTE: To avoid cracking in polygons with shared
  344. ** clipped edges we always compute "t" from the out
  345. ** vertex to the in vertex. The above clipping code gets
  346. ** this for free (p is in and s is out). In this code p
  347. ** is out and s is in, so we reverse the t computation
  348. ** and the argument order to __MCDDoClip.
  349. */
  350. t = sDist / (sDist - pDist);
  351. newVertex = temp++;
  352. (*clip)(newVertex, p, s, t);
  353. newVertex->flags = s->flags | MCDVERTEX_EDGEFLAG;
  354. newVertex->clipCode = p->clipCode;
  355. *ov++ = newVertex;
  356. nout++;
  357. if (++generated >= 3) {
  358. /* Toss the non-convex polygon */
  359. return 0;
  360. }
  361. } else {
  362. /* both points are outside */
  363. }
  364. }
  365. s = p;
  366. sDist = pDist;
  367. }
  368. pRc->pNextClipTemp = temp;
  369. return nout;
  370. }
  371. /*
  372. ** Identical to clipToPlane(), except that the clipping is done in eye
  373. ** space.
  374. */
  375. static LONG clipToPlaneEye(DEVRC *pRc, MCDVERTEX **iv, LONG niv,
  376. MCDVERTEX **ov, MCDCOORD *plane)
  377. {
  378. LONG i, nout, generated;
  379. MCDVERTEX *s, *p, *newVertex, *temp;
  380. MCDFLOAT pDist, sDist, t;
  381. MCDFLOAT zero = __MCDZERO;
  382. VOID (FASTCALL *clip)(MCDVERTEX*, const MCDVERTEX*, const MCDVERTEX*, MCDFLOAT);
  383. nout = 0;
  384. generated = 0;
  385. temp = pRc->pNextClipTemp;
  386. clip = pRc->polyClipParam;
  387. s = iv[niv-1];
  388. sDist = (s->eyeCoord.x * plane->x) +
  389. (s->eyeCoord.y * plane->y) +
  390. (s->eyeCoord.z * plane->z) +
  391. (s->eyeCoord.w * plane->w);
  392. for (i = 0; i < niv; i++) {
  393. p = iv[i];
  394. pDist = (p->eyeCoord.x * plane->x) +
  395. (p->eyeCoord.y * plane->y) +
  396. (p->eyeCoord.z * plane->z) +
  397. (p->eyeCoord.w * plane->w);
  398. if (pDist >= zero) {
  399. /* p is inside the clipping plane half space */
  400. if (sDist >= zero) {
  401. /* s is inside the clipping plane half space */
  402. *ov++ = p;
  403. nout++;
  404. } else {
  405. /* s is outside the clipping plane half space */
  406. t = pDist / (pDist - sDist);
  407. newVertex = temp++;
  408. (*clip)(newVertex, s, p, t);
  409. newVertex->eyeCoord.x = t*(s->eyeCoord.x - p->eyeCoord.x) + p->eyeCoord.x;
  410. newVertex->eyeCoord.y = t*(s->eyeCoord.y - p->eyeCoord.y) + p->eyeCoord.y;
  411. newVertex->eyeCoord.z = t*(s->eyeCoord.z - p->eyeCoord.z) + p->eyeCoord.z;
  412. newVertex->eyeCoord.w = t*(s->eyeCoord.w - p->eyeCoord.w) + p->eyeCoord.w;
  413. newVertex->flags = s->flags;
  414. newVertex->clipCode = s->clipCode; //!!!!
  415. *ov++ = newVertex;
  416. *ov++ = p;
  417. nout += 2;
  418. if (++generated >= 3) {
  419. /* Toss the non-convex polygon */
  420. return 0;
  421. }
  422. }
  423. } else {
  424. /* p is outside the clipping plane half space */
  425. if (sDist >= zero) {
  426. /*
  427. ** s is inside the clipping plane half space
  428. **
  429. ** NOTE: To avoid cracking in polygons with shared
  430. ** clipped edges we always compute "t" from the out
  431. ** vertex to the in vertex. The above clipping code gets
  432. ** this for free (p is in and s is out). In this code p
  433. ** is out and s is in, so we reverse the t computation
  434. ** and the argument order to __MCDDoClip.
  435. */
  436. t = sDist / (sDist - pDist);
  437. newVertex = temp++;
  438. (*clip)(newVertex, p, s, t);
  439. newVertex->eyeCoord.x = t*(p->eyeCoord.x - s->eyeCoord.x) + s->eyeCoord.x;
  440. newVertex->eyeCoord.y = t*(p->eyeCoord.y - s->eyeCoord.y) + s->eyeCoord.y;
  441. newVertex->eyeCoord.z = t*(p->eyeCoord.z - s->eyeCoord.z) + s->eyeCoord.z;
  442. newVertex->eyeCoord.w = t*(p->eyeCoord.w - s->eyeCoord.w) + s->eyeCoord.w;
  443. newVertex->flags = s->flags | MCDVERTEX_EDGEFLAG;
  444. newVertex->clipCode = p->clipCode;
  445. *ov++ = newVertex;
  446. nout++;
  447. if (++generated >= 3) {
  448. /* Toss the non-convex polygon */
  449. return 0;
  450. }
  451. } else {
  452. /* both points are outside */
  453. }
  454. }
  455. s = p;
  456. sDist = pDist;
  457. }
  458. pRc->pNextClipTemp = temp;
  459. return nout;
  460. }
  461. /*
  462. ** Each clipping plane can add at most one vertex to a convex polygon (it may
  463. ** remove up to all of the vertices). The clipping will leave a polygon
  464. ** convex. Because of this the maximum number of verticies output from
  465. ** the clipToPlane procedure will be total number of clip planes (assuming
  466. ** each plane adds one new vertex) plus the original number of verticies
  467. ** (3 since this if for triangles).
  468. */
  469. #define __MCD_TOTAL_CLIP_PLANES 6 + MCD_MAX_USER_CLIP_PLANES
  470. #define __MCD_MAX_POLYGON_CLIP_SIZE 256
  471. #define __MCD_MAX_CLIP_VERTEX (__MCD_TOTAL_CLIP_PLANES + __MCD_MAX_POLYGON_CLIP_SIZE)
  472. void FASTCALL __MCDDoClippedPolygon(DEVRC *pRc, MCDVERTEX **iv, ULONG nout,
  473. ULONG allClipCodes)
  474. {
  475. MCDVERTEX *ov[__MCD_TOTAL_CLIP_PLANES][__MCD_MAX_CLIP_VERTEX];
  476. MCDVERTEX **ivp;
  477. MCDVERTEX **ovp;
  478. MCDVERTEX *p0, *p1, *p2;
  479. MCDCOORD *plane;
  480. LONG i;
  481. MCDFLOAT one;
  482. VOID (FASTCALL *rt)(DEVRC*, MCDVERTEX*, MCDVERTEX*, MCDVERTEX*);
  483. MCDFLOAT llx, lly, urx, ury;
  484. MCDFLOAT winx, winy;
  485. ULONG clipCodes;
  486. /*
  487. ** Reset nextClipTemp pointer for any new verticies that are generated
  488. ** during the clipping.
  489. */
  490. pRc->pNextClipTemp = &pRc->clipTemp[0];
  491. ivp = &iv[0];
  492. /*
  493. ** Check each of the clipping planes by examining the allClipCodes
  494. ** mask. Note that no bits will be set in allClipCodes for clip
  495. ** planes that are not enabled.
  496. */
  497. if (allClipCodes) {
  498. /* Now clip against the clipping planes */
  499. ovp = &ov[0][0];
  500. /*
  501. ** Do user clip planes first, because we will maintain eye coordinates
  502. ** only while doing user clip planes. They are ignored for the
  503. ** frustum clipping planes.
  504. */
  505. clipCodes = (allClipCodes >> 6) & __MCD_USER_CLIP_MASK;
  506. if (clipCodes) {
  507. plane = &pRc->MCDState.userClipPlanes[0];
  508. do {
  509. if (clipCodes & 1) {
  510. nout = clipToPlaneEye(pRc, ivp, nout, ovp, plane);
  511. if (nout < 3) {
  512. return;
  513. }
  514. ivp = ovp;
  515. ovp += __MCD_MAX_CLIP_VERTEX;
  516. }
  517. clipCodes >>= 1;
  518. plane++;
  519. } while (clipCodes);
  520. }
  521. allClipCodes &= MCD_CLIP_MASK;
  522. if (allClipCodes) {
  523. plane = &__MCD_frustumClipPlanes[0];
  524. do {
  525. if (allClipCodes & 1) {
  526. nout = clipToPlane(pRc, ivp, nout, ovp, plane);
  527. if (nout < 3) {
  528. return;
  529. }
  530. ivp = ovp;
  531. ovp += __MCD_MAX_CLIP_VERTEX;
  532. }
  533. allClipCodes >>= 1;
  534. plane++;
  535. } while (allClipCodes);
  536. }
  537. /*
  538. ** Calculate final screen coordinates. Next phase of polygon
  539. ** processing assumes that window coordinates are already computed.
  540. */
  541. ovp = ivp;
  542. one = __MCDONE;
  543. llx = pRc->MCDViewport.xCenter - pRc->MCDViewport.xScale;
  544. urx = pRc->MCDViewport.xCenter + pRc->MCDViewport.xScale;
  545. if (pRc->MCDViewport.yScale > 0) {
  546. lly = pRc->MCDViewport.yCenter - pRc->MCDViewport.yScale;
  547. ury = pRc->MCDViewport.yCenter + pRc->MCDViewport.yScale;
  548. } else {
  549. lly = pRc->MCDViewport.yCenter + pRc->MCDViewport.yScale;
  550. ury = pRc->MCDViewport.yCenter - pRc->MCDViewport.yScale;
  551. }
  552. for (i = nout; --i >= 0; ) {
  553. MCDFLOAT wInv;
  554. p0 = *ovp++;
  555. if (p0->clipCoord.w == (MCDFLOAT) 0.0)
  556. wInv = (MCDFLOAT) 0.0;
  557. else
  558. wInv = one / p0->clipCoord.w;
  559. winx = p0->clipCoord.x * pRc->MCDViewport.xScale * wInv +
  560. pRc->MCDViewport.xCenter;
  561. winy = p0->clipCoord.y * pRc->MCDViewport.yScale * wInv +
  562. pRc->MCDViewport.yCenter;
  563. /*
  564. ** Check if these window coordinates are legal. At this
  565. ** point, it is quite possible that they are not. Trivially
  566. ** pull them into the legal viewport region if necessary.
  567. */
  568. if (winx < llx) winx = llx;
  569. else if (winx > urx) winx = urx;
  570. if (winy < lly) winy = lly;
  571. else if (winy > ury) winy = ury;
  572. p0->windowCoord.x = winx;
  573. p0->windowCoord.y = winy;
  574. p0->windowCoord.z = p0->clipCoord.z * pRc->MCDViewport.zScale * wInv +
  575. pRc->MCDViewport.zCenter;
  576. p0->windowCoord.w = wInv;
  577. }
  578. }
  579. /*
  580. ** Subdivide the clipped polygon into triangles. Only convex polys
  581. ** are supported so this is okay to do. Non-convex polys will do
  582. ** something odd here, but thats the clients fault.
  583. */
  584. p0 = *ivp++;
  585. p1 = *ivp++;
  586. p2 = *ivp++;
  587. rt = pRc->renderTri;
  588. if (nout == 3) {
  589. (*rt)(pRc, p0, p1, p2);
  590. } else {
  591. for (i = 0; i < (LONG)nout - 2; i++) {
  592. ULONG t1, t2;
  593. if (i == 0) {
  594. /*
  595. ** Third edge of first sub-triangle is always non-boundary
  596. */
  597. t1 = p2->flags & MCDVERTEX_EDGEFLAG;
  598. p2->flags &= ~MCDVERTEX_EDGEFLAG;
  599. (*rt)(pRc, p0, p1, p2);
  600. p2->flags |= t1;
  601. } else
  602. if (i == (LONG)nout - 3) {
  603. /*
  604. ** First edge of last sub-triangle is always non-boundary
  605. */
  606. t1 = p0->flags & MCDVERTEX_EDGEFLAG;
  607. p0->flags &= ~MCDVERTEX_EDGEFLAG;
  608. (*rt)(pRc, p0, p1, p2);
  609. p0->flags |= t1;
  610. } else {
  611. /*
  612. ** Interior sub-triangles have the first and last edge
  613. ** marked non-boundary
  614. */
  615. t1 = p0->flags & MCDVERTEX_EDGEFLAG;
  616. t2 = p2->flags & MCDVERTEX_EDGEFLAG;
  617. p0->flags &= ~MCDVERTEX_EDGEFLAG;
  618. p2->flags &= ~MCDVERTEX_EDGEFLAG;
  619. (*rt)(pRc, p0, p1, p2);
  620. p0->flags |= t1;
  621. p2->flags |= t2;
  622. }
  623. p1 = p2;
  624. p2 = (MCDVERTEX *) *ivp++;
  625. }
  626. }
  627. }
  628. VOID FASTCALL __MCDClipPolygon(DEVRC *pRc, MCDVERTEX *v0, ULONG nv)
  629. {
  630. MCDVERTEX *iv[__MCD_MAX_POLYGON_CLIP_SIZE];
  631. MCDVERTEX **ivp;
  632. LONG i;
  633. ULONG andCodes, orCodes;
  634. pRc->pvProvoking = v0;
  635. /*
  636. ** Generate array of addresses of the verticies. And all the
  637. ** clip codes together while we are at it.
  638. */
  639. ivp = &iv[0];
  640. andCodes = 0;
  641. orCodes = 0;
  642. for (i = nv; --i >= 0; ) {
  643. andCodes &= v0->clipCode;
  644. orCodes |= v0->clipCode;
  645. *ivp++ = v0++;
  646. }
  647. if (andCodes != 0) {
  648. /*
  649. ** Trivially reject the polygon. If andCodes is non-zero then
  650. ** every vertex in the polygon is outside of the same set of
  651. ** clipping planes (at least one).
  652. */
  653. return;
  654. }
  655. __MCDDoClippedPolygon(pRc, &iv[0], nv, orCodes);
  656. }
  657. void FASTCALL __MCDClipTriangle(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  658. MCDVERTEX *c, ULONG orCodes)
  659. {
  660. MCDVERTEX *iv[3];
  661. iv[0] = a;
  662. iv[1] = b;
  663. iv[2] = c;
  664. __MCDDoClippedPolygon(pRc, &iv[0], 3, orCodes);
  665. }
  666. ////////////////////////////////////////////////////////////////////////
  667. // Line clipping:
  668. ////////////////////////////////////////////////////////////////////////
  669. //
  670. // Clip a line against the frustum clip planes and any user clipping planes.
  671. // If an edge remains after clipping then compute the window coordinates
  672. // and invoke the renderer.
  673. //
  674. // Notice: This algorithim is an example of an implementation that is
  675. // different than what the spec says. This is equivalent in functionality
  676. // and meets the spec, but doesn't clip in eye space. This clipper clips
  677. // in NTVP (clip) space.
  678. //
  679. // Trivial accept/reject has already been dealt with.
  680. //
  681. VOID FASTCALL __MCDClipLine(DEVRC *pRc, MCDVERTEX *a, MCDVERTEX *b,
  682. BOOL bResetLine)
  683. {
  684. MCDVERTEX *provokingA = a;
  685. MCDVERTEX *provokingB = b;
  686. MCDVERTEX np1, np2;
  687. MCDCOORD *plane;
  688. ULONG needs, allClipCodes, clipCodes;
  689. VOID (FASTCALL *clip)(MCDVERTEX*, const MCDVERTEX*, const MCDVERTEX*, MCDFLOAT);
  690. MCDFLOAT zero;
  691. MCDFLOAT winx, winy;
  692. MCDFLOAT vpXCenter, vpYCenter, vpZCenter;
  693. MCDFLOAT vpXScale, vpYScale, vpZScale;
  694. MCDVIEWPORT *vp;
  695. MCDFLOAT x, y, z, wInv;
  696. allClipCodes = a->clipCode | b->clipCode;
  697. /*
  698. ** For each clipping plane that something is out on, clip
  699. ** check the verticies. Note that no bits will be set in
  700. ** allClipCodes for clip planes that are not enabled.
  701. */
  702. zero = __MCDZERO;
  703. clip = pRc->lineClipParam;
  704. /*
  705. ** Do user clip planes first, because we will maintain eye coordinates
  706. ** only while doing user clip planes. They are ignored for the
  707. ** frustum clipping planes.
  708. */
  709. clipCodes = (allClipCodes >> 6) & __MCD_USER_CLIP_MASK;
  710. if (clipCodes) {
  711. plane = &pRc->MCDState.userClipPlanes[0];
  712. do {
  713. /*
  714. ** See if this clip plane has anything out of it. If not,
  715. ** press onward to check the next plane. Note that we
  716. ** shift this mask to the right at the bottom of the loop.
  717. */
  718. if (clipCodes & 1) {
  719. MCDFLOAT t, d1, d2;
  720. d1 = (plane->x * a->eyeCoord.x) +
  721. (plane->y * a->eyeCoord.y) +
  722. (plane->z * a->eyeCoord.z) +
  723. (plane->w * a->eyeCoord.w);
  724. d2 = (plane->x * b->eyeCoord.x) +
  725. (plane->y * b->eyeCoord.y) +
  726. (plane->z * b->eyeCoord.z) +
  727. (plane->w * b->eyeCoord.w);
  728. if (d1 < zero) {
  729. /* a is out */
  730. if (d2 < zero) {
  731. /* a & b are out */
  732. return;
  733. }
  734. /*
  735. ** A is out and B is in. Compute new A coordinate
  736. ** clipped to the plane.
  737. */
  738. t = d2 / (d2 - d1);
  739. (*clip)(&np1, a, b, t);
  740. (&np1)->eyeCoord.x =
  741. t*(a->eyeCoord.x - b->eyeCoord.x) + b->eyeCoord.x;
  742. (&np1)->eyeCoord.y =
  743. t*(a->eyeCoord.y - b->eyeCoord.y) + b->eyeCoord.y;
  744. (&np1)->eyeCoord.z =
  745. t*(a->eyeCoord.z - b->eyeCoord.z) + b->eyeCoord.z;
  746. (&np1)->eyeCoord.w =
  747. t*(a->eyeCoord.w - b->eyeCoord.w) + b->eyeCoord.w;
  748. a = &np1;
  749. a->flags = b->flags;
  750. if (pRc->MCDState.shadeModel == GL_FLAT)
  751. {
  752. COPY_COLOR(a->colors[0], provokingA->colors[0]);
  753. }
  754. } else {
  755. /* a is in */
  756. if (d2 < zero) {
  757. /*
  758. ** A is in and B is out. Compute new B
  759. ** coordinate clipped to the plane.
  760. **
  761. ** NOTE: To avoid cracking in polygons with
  762. ** shared clipped edges we always compute "t"
  763. ** from the out vertex to the in vertex. The
  764. ** above clipping code gets this for free (b is
  765. ** in and a is out). In this code b is out and a
  766. ** is in, so we reverse the t computation and the
  767. ** argument order to (*clip).
  768. */
  769. t = d1 / (d1 - d2);
  770. (*clip)(&np2, b, a, t);
  771. (&np2)->eyeCoord.x =
  772. t*(b->eyeCoord.x - a->eyeCoord.x) + a->eyeCoord.x;
  773. (&np2)->eyeCoord.y =
  774. t*(b->eyeCoord.y - a->eyeCoord.y) + a->eyeCoord.y;
  775. (&np2)->eyeCoord.z =
  776. t*(b->eyeCoord.z - a->eyeCoord.z) + a->eyeCoord.z;
  777. (&np2)->eyeCoord.w =
  778. t*(b->eyeCoord.w - a->eyeCoord.w) + a->eyeCoord.w;
  779. b = &np2;
  780. b->flags = a->flags;
  781. if (pRc->MCDState.shadeModel == GL_FLAT)
  782. {
  783. COPY_COLOR(b->colors[0], provokingB->colors[0]);
  784. }
  785. } else {
  786. /* A and B are in */
  787. }
  788. }
  789. }
  790. plane++;
  791. clipCodes >>= 1;
  792. } while (clipCodes);
  793. }
  794. allClipCodes &= MCD_CLIP_MASK;
  795. if (allClipCodes) {
  796. plane = &__MCD_frustumClipPlanes[0];
  797. do {
  798. /*
  799. ** See if this clip plane has anything out of it. If not,
  800. ** press onward to check the next plane. Note that we
  801. ** shift this mask to the right at the bottom of the loop.
  802. */
  803. if (allClipCodes & 1) {
  804. MCDFLOAT t, d1, d2;
  805. d1 = (plane->x * a->clipCoord.x) + (plane->y * a->clipCoord.y) +
  806. (plane->z * a->clipCoord.z) + (plane->w * a->clipCoord.w);
  807. d2 = (plane->x * b->clipCoord.x) + (plane->y * b->clipCoord.y) +
  808. (plane->z * b->clipCoord.z) + (plane->w * b->clipCoord.w);
  809. if (d1 < zero) {
  810. /* a is out */
  811. if (d2 < zero) {
  812. /* a & b are out */
  813. return;
  814. }
  815. /*
  816. ** A is out and B is in. Compute new A coordinate
  817. ** clipped to the plane.
  818. */
  819. t = d2 / (d2 - d1);
  820. (*clip)(&np1, a, b, t);
  821. a = &np1;
  822. a->flags = b->flags;
  823. if (pRc->MCDState.shadeModel == GL_FLAT)
  824. {
  825. COPY_COLOR(a->colors[0], provokingA->colors[0]);
  826. }
  827. } else {
  828. /* a is in */
  829. if (d2 < zero) {
  830. /*
  831. ** A is in and B is out. Compute new B
  832. ** coordinate clipped to the plane.
  833. **
  834. ** NOTE: To avoid cracking in polygons with
  835. ** shared clipped edges we always compute "t"
  836. ** from the out vertex to the in vertex. The
  837. ** above clipping code gets this for free (b is
  838. ** in and a is out). In this code b is out and a
  839. ** is in, so we reverse the t computation and the
  840. ** argument order to (*clip).
  841. */
  842. t = d1 / (d1 - d2);
  843. (*clip)(&np2, b, a, t);
  844. b = &np2;
  845. b->flags = a->flags;
  846. if (pRc->MCDState.shadeModel == GL_FLAT)
  847. {
  848. COPY_COLOR(b->colors[0], provokingB->colors[0]);
  849. }
  850. } else {
  851. /* A and B are in */
  852. }
  853. }
  854. }
  855. plane++;
  856. allClipCodes >>= 1;
  857. } while (allClipCodes);
  858. }
  859. vp = &pRc->MCDViewport;
  860. vpXCenter = vp->xCenter;
  861. vpYCenter = vp->yCenter;
  862. vpZCenter = vp->zCenter;
  863. vpXScale = vp->xScale;
  864. vpYScale = vp->yScale;
  865. vpZScale = vp->zScale;
  866. /* Compute window coordinates for both vertices. */
  867. wInv = __MCDONE / a->clipCoord.w;
  868. x = a->clipCoord.x;
  869. y = a->clipCoord.y;
  870. z = a->clipCoord.z;
  871. winx = x * vpXScale * wInv + vpXCenter;
  872. winy = y * vpYScale * wInv + vpYCenter;
  873. a->windowCoord.z = z * vpZScale * wInv + vpZCenter;
  874. a->windowCoord.w = wInv;
  875. a->windowCoord.x = winx;
  876. a->windowCoord.y = winy;
  877. wInv = __MCDONE / b->clipCoord.w;
  878. x = b->clipCoord.x;
  879. y = b->clipCoord.y;
  880. z = b->clipCoord.z;
  881. winx = x * vpXScale * wInv + vpXCenter;
  882. winy = y * vpYScale * wInv + vpYCenter;
  883. b->windowCoord.z = z * vpZScale * wInv + vpZCenter;
  884. b->windowCoord.w = wInv;
  885. b->windowCoord.x = winx;
  886. b->windowCoord.y = winy;
  887. /* Validate line state */
  888. if (pRc->MCDState.shadeModel == GL_FLAT) {
  889. // Add the vertices then restore the b color pointer
  890. //
  891. // Note that although b is the only new vertex, up
  892. // to two vertices can be added because each new vertex
  893. // generated by clipping must be added. For a line where
  894. // both endpoints are out of the clipping region, both
  895. // an entry and an exit vertex must be added
  896. if (provokingA->clipCode != 0)
  897. {
  898. // a was out so a new vertex was added at the point of
  899. // entry
  900. bResetLine = TRUE;
  901. }
  902. // b is always added since either:
  903. // b was in and is new so it needs to be added
  904. // b was out so a new vertex was added at the exit point
  905. (*pRc->renderLine)(pRc, a, b, bResetLine);
  906. } else {
  907. if (provokingA->clipCode != 0)
  908. {
  909. bResetLine = TRUE;
  910. }
  911. (*pRc->renderLine)(pRc, a, b, bResetLine);
  912. }
  913. }