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.

404 lines
12 KiB

  1. /*
  2. ** Copyright 1991, Silicon Graphics, Inc.
  3. ** All Rights Reserved.
  4. **
  5. ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6. ** the contents of this file may not be disclosed to third parties, copied or
  7. ** duplicated in any form, in whole or in part, without the prior written
  8. ** permission of Silicon Graphics, Inc.
  9. **
  10. ** RESTRICTED RIGHTS LEGEND:
  11. ** Use, duplication or disclosure by the Government is subject to restrictions
  12. ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13. ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14. ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15. ** rights reserved under the Copyright Laws of the United States.
  16. */
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. /*
  20. ** The following is a discussion of the math used to do edge clipping against
  21. ** a clipping plane.
  22. **
  23. ** P1 is an end point of the edge
  24. ** P2 is the other end point of the edge
  25. **
  26. ** Q = t*P1 + (1 - t)*P2
  27. ** That is, Q lies somewhere on the line formed by P1 and P2.
  28. **
  29. ** 0 <= t <= 1
  30. ** This constrains Q to lie between P1 and P2.
  31. **
  32. ** C is the plane equation for the clipping plane
  33. **
  34. ** D1 = P1 dot C
  35. ** D1 is the distance between P1 and C. If P1 lies on the plane
  36. ** then D1 will be zero. The sign of D1 will determine which side
  37. ** of the plane that P1 is on, with negative being outside.
  38. **
  39. ** D2 = P2 dot C
  40. ** D2 is the distance between P2 and C. If P2 lies on the plane
  41. ** then D2 will be zero. The sign of D2 will determine which side
  42. ** of the plane that P2 is on, with negative being outside.
  43. **
  44. ** Because we are trying to find the intersection of the P1 P2 line
  45. ** segment with the clipping plane we require that:
  46. **
  47. ** Q dot C = 0
  48. **
  49. ** Therefore
  50. **
  51. ** (t*P1 + (1 - t)*P2) dot C = 0
  52. **
  53. ** (t*P1 + P2 - t*P2) dot C = 0
  54. **
  55. ** t*P1 dot C + P2 dot C - t*P2 dot C = 0
  56. **
  57. ** Substituting D1 and D2 in
  58. **
  59. ** t*D1 + D2 - t*D2 = 0
  60. **
  61. ** Solving for t
  62. **
  63. ** t = -D2 / (D1 - D2)
  64. **
  65. ** t = D2 / (D2 - D1)
  66. */
  67. /*
  68. ** Clip a line against the frustum clip planes and any user clipping planes.
  69. ** If an edge remains after clipping then compute the window coordinates
  70. ** and invoke the renderer.
  71. **
  72. ** Notice: This algorithim is an example of an implementation that is
  73. ** different than what the spec says. This is equivalent in functionality
  74. ** and meets the spec, but doesn't clip in eye space. This clipper clips
  75. ** in NTVP (clip) space.
  76. **
  77. ** Trivial accept/reject has already been dealt with.
  78. */
  79. #ifdef NT
  80. void FASTCALL __glClipLine(__GLcontext *gc, __GLvertex *a, __GLvertex *b,
  81. GLuint flags)
  82. #else
  83. void __glClipLine(__GLcontext *gc, __GLvertex *a, __GLvertex *b)
  84. #endif
  85. {
  86. #ifdef NT
  87. __GLvertex *provokingA = a;
  88. __GLvertex *provokingB = b;
  89. #else
  90. __GLvertex *provoking = b;
  91. #endif
  92. __GLvertex np1, np2;
  93. __GLcoord *plane;
  94. GLuint needs, allClipCodes, clipCodes;
  95. PFN_VERTEX_CLIP_PROC clip;
  96. __GLfloat zero;
  97. __GLfloat winx, winy;
  98. __GLfloat vpXCenter, vpYCenter, vpZCenter;
  99. __GLfloat vpXScale, vpYScale, vpZScale;
  100. __GLviewport *vp;
  101. __GLfloat x, y, z, wInv;
  102. GLint i;
  103. // We have to turn rounding on. Otherwise, the fast FP-comparison
  104. // routines below can fail:
  105. FPU_SAVE_MODE();
  106. FPU_ROUND_ON_PREC_HI();
  107. /* Check for trivial pass of the line */
  108. allClipCodes = a->clipCode | b->clipCode;
  109. /*
  110. ** For each clippling plane that something is out on, clip
  111. ** check the verticies. Note that no bits will be set in
  112. ** allClipCodes for clip planes that are not enabled.
  113. */
  114. zero = __glZero;
  115. clip = gc->procs.lineClipParam;
  116. /*
  117. ** Do user clip planes first, because we will maintain eye coordinates
  118. ** only while doing user clip planes. They are ignored for the
  119. ** frustum clipping planes.
  120. */
  121. clipCodes = allClipCodes >> 6;
  122. if (clipCodes) {
  123. plane = &gc->state.transform.eyeClipPlanes[0];
  124. do {
  125. /*
  126. ** See if this clip plane has anything out of it. If not,
  127. ** press onward to check the next plane. Note that we
  128. ** shift this mask to the right at the bottom of the loop.
  129. */
  130. if (clipCodes & 1) {
  131. __GLfloat t, d1, d2;
  132. d1 = (plane->x * ((POLYDATA *)a)->eye.x) +
  133. (plane->y * ((POLYDATA *)a)->eye.y) +
  134. (plane->z * ((POLYDATA *)a)->eye.z) +
  135. (plane->w * ((POLYDATA *)a)->eye.w);
  136. d2 = (plane->x * ((POLYDATA *)b)->eye.x) +
  137. (plane->y * ((POLYDATA *)b)->eye.y) +
  138. (plane->z * ((POLYDATA *)b)->eye.z) +
  139. (plane->w * ((POLYDATA *)b)->eye.w);
  140. if (__GL_FLOAT_LTZ(d1)) {
  141. /* a is out */
  142. if (__GL_FLOAT_LTZ(d2)) {
  143. /* a & b are out */
  144. FPU_RESTORE_MODE();
  145. return;
  146. }
  147. /*
  148. ** A is out and B is in. Compute new A coordinate
  149. ** clipped to the plane.
  150. */
  151. t = d2 / (d2 - d1);
  152. (*clip)(&np1, a, b, t);
  153. ((POLYDATA *)&np1)->eye.x =
  154. t*(((POLYDATA *)a)->eye.x - ((POLYDATA *)b)->eye.x) +
  155. ((POLYDATA *)b)->eye.x;
  156. ((POLYDATA *)&np1)->eye.y =
  157. t*(((POLYDATA *)a)->eye.y - ((POLYDATA *)b)->eye.y) +
  158. ((POLYDATA *)b)->eye.y;
  159. ((POLYDATA *)&np1)->eye.z =
  160. t*(((POLYDATA *)a)->eye.z - ((POLYDATA *)b)->eye.z) +
  161. ((POLYDATA *)b)->eye.z;
  162. ((POLYDATA *)&np1)->eye.w =
  163. t*(((POLYDATA *)a)->eye.w - ((POLYDATA *)b)->eye.w) +
  164. ((POLYDATA *)b)->eye.w;
  165. a = &np1;
  166. a->has = b->has;
  167. ASSERTOPENGL(!(a->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
  168. } else {
  169. /* a is in */
  170. if (__GL_FLOAT_LTZ(d2)) {
  171. /*
  172. ** A is in and B is out. Compute new B
  173. ** coordinate clipped to the plane.
  174. **
  175. ** NOTE: To avoid cracking in polygons with
  176. ** shared clipped edges we always compute "t"
  177. ** from the out vertex to the in vertex. The
  178. ** above clipping code gets this for free (b is
  179. ** in and a is out). In this code b is out and a
  180. ** is in, so we reverse the t computation and the
  181. ** argument order to (*clip).
  182. */
  183. t = d1 / (d1 - d2);
  184. (*clip)(&np2, b, a, t);
  185. ((POLYDATA *)&np2)->eye.x =
  186. t*(((POLYDATA *)b)->eye.x - ((POLYDATA *)a)->eye.x)+
  187. ((POLYDATA *)a)->eye.x;
  188. ((POLYDATA *)&np2)->eye.y =
  189. t*(((POLYDATA *)b)->eye.y - ((POLYDATA *)a)->eye.y)+
  190. ((POLYDATA *)a)->eye.y;
  191. ((POLYDATA *)&np2)->eye.z =
  192. t*(((POLYDATA *)b)->eye.z - ((POLYDATA *)a)->eye.z)+
  193. ((POLYDATA *)a)->eye.z;
  194. ((POLYDATA *)&np2)->eye.w =
  195. t*(((POLYDATA *)b)->eye.w - ((POLYDATA *)a)->eye.w)+
  196. ((POLYDATA *)a)->eye.w;
  197. b = &np2;
  198. b->has = a->has;
  199. ASSERTOPENGL(!(b->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
  200. } else {
  201. /* A and B are in */
  202. }
  203. }
  204. }
  205. plane++;
  206. clipCodes >>= 1;
  207. } while (clipCodes);
  208. }
  209. allClipCodes &= __GL_FRUSTUM_CLIP_MASK;
  210. if (allClipCodes) {
  211. i = 0;
  212. do {
  213. /*
  214. ** See if this clip plane has anything out of it. If not,
  215. ** press onward to check the next plane. Note that we
  216. ** shift this mask to the right at the bottom of the loop.
  217. */
  218. if (allClipCodes & 1) {
  219. __GLfloat t, d1, d2;
  220. if (i & 1)
  221. {
  222. d1 = a->clip.w -
  223. *(__GLfloat *)((GLubyte *)a + __glFrustumOffsets[i]);
  224. d2 = b->clip.w -
  225. *(__GLfloat *)((GLubyte *)b + __glFrustumOffsets[i]);
  226. }
  227. else
  228. {
  229. d1 = *(__GLfloat *)((GLubyte *)a + __glFrustumOffsets[i]) +
  230. a->clip.w;
  231. d2 = *(__GLfloat *)((GLubyte *)b + __glFrustumOffsets[i]) +
  232. b->clip.w;
  233. }
  234. if (__GL_FLOAT_LTZ(d1)) {
  235. /* a is out */
  236. if (__GL_FLOAT_LTZ(d2)) {
  237. /* a & b are out */
  238. FPU_RESTORE_MODE();
  239. return;
  240. }
  241. /*
  242. ** A is out and B is in. Compute new A coordinate
  243. ** clipped to the plane.
  244. */
  245. t = d2 / (d2 - d1);
  246. (*clip)(&np1, a, b, t);
  247. a = &np1;
  248. a->has = b->has;
  249. ASSERTOPENGL(!(a->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
  250. } else {
  251. /* a is in */
  252. if (__GL_FLOAT_LTZ(d2)) {
  253. /*
  254. ** A is in and B is out. Compute new B
  255. ** coordinate clipped to the plane.
  256. **
  257. ** NOTE: To avoid cracking in polygons with
  258. ** shared clipped edges we always compute "t"
  259. ** from the out vertex to the in vertex. The
  260. ** above clipping code gets this for free (b is
  261. ** in and a is out). In this code b is out and a
  262. ** is in, so we reverse the t computation and the
  263. ** argument order to (*clip).
  264. */
  265. t = d1 / (d1 - d2);
  266. (*clip)(&np2, b, a, t);
  267. b = &np2;
  268. b->has = a->has;
  269. ASSERTOPENGL(!(b->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
  270. } else {
  271. /* A and B are in */
  272. }
  273. }
  274. }
  275. i++;
  276. allClipCodes >>= 1;
  277. } while (allClipCodes);
  278. }
  279. vp = &gc->state.viewport;
  280. vpXCenter = vp->xCenter;
  281. vpYCenter = vp->yCenter;
  282. vpZCenter = vp->zCenter;
  283. vpXScale = vp->xScale;
  284. vpYScale = vp->yScale;
  285. vpZScale = vp->zScale;
  286. /* Compute window coordinates for vertices generated by clipping */
  287. if (provokingA->clipCode != 0)
  288. {
  289. wInv = __glOne / a->clip.w;
  290. x = a->clip.x;
  291. y = a->clip.y;
  292. z = a->clip.z;
  293. winx = x * vpXScale * wInv + vpXCenter;
  294. winy = y * vpYScale * wInv + vpYCenter;
  295. if (winx < gc->transform.fminx)
  296. winx = gc->transform.fminx;
  297. else if (winx >= gc->transform.fmaxx)
  298. winx = gc->transform.fmaxx - gc->constants.viewportEpsilon;
  299. if (winy < gc->transform.fminy)
  300. winy = gc->transform.fminy;
  301. else if (winy >= gc->transform.fmaxy)
  302. winy = gc->transform.fmaxy - gc->constants.viewportEpsilon;
  303. a->window.z = z * vpZScale * wInv + vpZCenter;
  304. a->window.w = wInv;
  305. a->window.x = winx;
  306. a->window.y = winy;
  307. // Update color pointer since this vertex is a new one
  308. // generated by clipping
  309. if (gc->state.light.shadingModel == GL_FLAT)
  310. {
  311. a->color = &provokingA->colors[__GL_FRONTFACE];
  312. }
  313. else
  314. {
  315. a->color = &a->colors[__GL_FRONTFACE];
  316. }
  317. }
  318. if (provokingB->clipCode != 0)
  319. {
  320. wInv = __glOne / b->clip.w;
  321. x = b->clip.x;
  322. y = b->clip.y;
  323. z = b->clip.z;
  324. winx = x * vpXScale * wInv + vpXCenter;
  325. winy = y * vpYScale * wInv + vpYCenter;
  326. if (winx < gc->transform.fminx)
  327. winx = gc->transform.fminx;
  328. else if (winx >= gc->transform.fmaxx)
  329. winx = gc->transform.fmaxx - gc->constants.viewportEpsilon;
  330. if (winy < gc->transform.fminy)
  331. winy = gc->transform.fminy;
  332. else if (winy >= gc->transform.fmaxy)
  333. winy = gc->transform.fmaxy - gc->constants.viewportEpsilon;
  334. b->window.z = z * vpZScale * wInv + vpZCenter;
  335. b->window.w = wInv;
  336. b->window.x = winx;
  337. b->window.y = winy;
  338. if (gc->state.light.shadingModel == GL_FLAT)
  339. {
  340. b->color = &provokingB->colors[__GL_FRONTFACE];
  341. }
  342. else
  343. {
  344. b->color = &b->colors[__GL_FRONTFACE];
  345. }
  346. }
  347. // Restore the floating-point mode for rendering:
  348. FPU_RESTORE_MODE();
  349. /* Validate line state */
  350. if (gc->state.light.shadingModel == GL_FLAT) {
  351. // Add the vertices then restore the b color pointer
  352. //
  353. // Note that although b is the only new vertex, up
  354. // to two vertices can be added because each new vertex
  355. // generated by clipping must be added. For a line where
  356. // both endpoints are out of the clipping region, both
  357. // an entry and an exit vertex must be added
  358. if (provokingA->clipCode != 0)
  359. {
  360. // a was out so a new vertex was added at the point of
  361. // entry
  362. flags |= __GL_LVERT_FIRST;
  363. }
  364. // b is always added since either:
  365. // b was in and is new so it needs to be added
  366. // b was out so a new vertex was added at the exit point
  367. (*gc->procs.renderLine)(gc, a, b, flags);
  368. #ifndef NT
  369. b->color = &b->colors[__GL_FRONTFACE];
  370. #endif
  371. } else {
  372. if (provokingA->clipCode != 0)
  373. {
  374. flags |= __GL_LVERT_FIRST;
  375. }
  376. (*gc->procs.renderLine)(gc, a, b, flags);
  377. }
  378. }