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.

424 lines
15 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dpclip.c
  6. * Content: DrawPrimitive clipper
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. #include "clipfunc.h"
  12. #include "drawprim.hpp"
  13. //----------------------------------------------------------------------
  14. HRESULT Clip(D3DFE_PROCESSVERTICES *pv, ClipVertex *cv1, ClipVertex *cv2, ClipVertex *cv3)
  15. {
  16. ClipTriangle newtri;
  17. LPVOID saveVer = pv->lpvOut; // For indexed primitive
  18. DWORD numVer = pv->dwNumVertices; // For indexed primitive
  19. newtri.v[0] = cv1;
  20. newtri.v[1] = cv2;
  21. newtri.v[2] = cv3;
  22. int count;
  23. ClipVertex** ver;
  24. LPDIRECT3DDEVICEI lpDevI = static_cast<LPDIRECT3DDEVICEI>(pv);
  25. cv1->clip |= CLIPPED_ENABLE;
  26. cv2->clip |= CLIPPED_ENABLE;
  27. cv3->clip |= CLIPPED_ENABLE;
  28. // For the flat shading mode we have to use first vertex color as
  29. // color for all vertices
  30. D3DCOLOR diffuse1; // Original colors
  31. D3DCOLOR specular1;
  32. D3DCOLOR diffuse2;
  33. D3DCOLOR specular2;
  34. if (pv->lpdwRStates[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
  35. {
  36. // It is easier to set all vertices to the same color here
  37. D3DCOLOR diffuse = cv1->color;
  38. D3DCOLOR specular = cv1->specular;
  39. //Save original colors
  40. diffuse1 = cv2->color;
  41. specular1 = cv2->specular;
  42. diffuse2 = cv3->color;
  43. specular2 = cv3->specular;
  44. cv2->color= diffuse;
  45. cv2->specular = specular;
  46. cv3->color = diffuse;
  47. cv3->specular = specular;
  48. }
  49. if (count = lpDevI->pGeometryFuncs->ClipSingleTriangle(pv, &newtri, &ver))
  50. {
  51. int i;
  52. HRESULT ret;
  53. BYTE *pTLV = (BYTE*)pv->ClipperState.clipBuf.GetAddress();
  54. BYTE *p = pTLV;
  55. for (i = 0; i < count; i++)
  56. {
  57. MAKE_TL_VERTEX_FVF(pv, p, ver[i]);
  58. p += pv->dwOutputSize;
  59. }
  60. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, pTLV, count, count-2);
  61. if (ret)
  62. return ret;
  63. }
  64. // CLIPPED_ENABLE bit could be set in the ClipSingleTriangle.
  65. // If this bit is not cleared, clipping will be wrong. Because, clip
  66. // vertices are re-used by next triangles.
  67. // This bit should be cleared *after* drawing command. Otherwise, edge flags
  68. // will be incorrect
  69. cv1->clip &= ~CLIPPED_ENABLE;
  70. cv2->clip &= ~CLIPPED_ENABLE;
  71. cv3->clip &= ~CLIPPED_ENABLE;
  72. if (pv->lpdwRStates[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
  73. {
  74. // Restore original colors
  75. cv2->color = diffuse1;
  76. cv2->specular = specular1;
  77. cv3->color = diffuse2;
  78. cv3->specular = specular2;
  79. }
  80. pv->lpvOut = saveVer;
  81. pv->dwNumVertices = numVer;
  82. return D3D_OK;
  83. }
  84. //----------------------------------------------------------------------
  85. HRESULT ClipLine(D3DFE_PROCESSVERTICES *pv, ClipVertex *v1, ClipVertex *v2)
  86. {
  87. ClipTriangle newline;
  88. LPVOID saveVer = pv->lpvOut; // For indexed primitive
  89. DWORD numVer = pv->dwNumVertices; // For indexed primitive
  90. ClipVertex cv1 = *v1;
  91. ClipVertex cv2 = *v2;
  92. newline.v[0] = &cv1;
  93. newline.v[1] = &cv2;
  94. int count;
  95. ClipVertex** ver;
  96. LPDIRECT3DDEVICEI lpDevI = static_cast<LPDIRECT3DDEVICEI>(pv);
  97. if (pv->lpdwRStates[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
  98. {
  99. cv2.color = cv1.color;
  100. cv2.specular = cv1.specular;
  101. }
  102. if (ClipSingleLine(pv, &newline, &pv->rExtents))
  103. {
  104. BYTE *pTLV = (BYTE*)pv->ClipperState.clipBuf.GetAddress();
  105. BYTE *p = pTLV;
  106. MAKE_TL_VERTEX_FVF(pv, p, newline.v[0]);
  107. p += pv->dwOutputSize;
  108. MAKE_TL_VERTEX_FVF(pv, p, newline.v[1]);
  109. HRESULT ret = DRAW_CLIPPED_PRIM(pv, D3DPT_LINELIST, pTLV, 2, 1);
  110. if (ret)
  111. return ret;
  112. }
  113. pv->lpvOut = saveVer;
  114. pv->dwNumVertices = numVer;
  115. return D3D_OK;
  116. }
  117. //------------------------------------------------------------------------------
  118. HRESULT ProcessClippedTriangleFan(D3DFE_PROCESSVERTICES *pv)
  119. {
  120. BYTE *p1;
  121. DWORD f1;
  122. D3DFE_CLIPCODE *clipCode;
  123. DWORD i;
  124. HRESULT ret;
  125. BYTE *vertex;
  126. BYTE *startVertex;
  127. int vertexCount;
  128. DWORD vertexSize;
  129. ClipVertex cv[3];
  130. BOOL vertexTransformed;
  131. vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;;
  132. clipCode = pv->lpClipFlags;
  133. vertex = (BYTE*)pv->lpvOut;
  134. startVertex = (BYTE*)pv->lpvOut;
  135. vertexSize = pv->dwOutputSize;
  136. vertexCount = 0;
  137. f1 = clipCode[0];
  138. p1 = vertex;
  139. clipCode++;
  140. vertex += vertexSize;
  141. // In the clipper color from the first vertex is propagated to all
  142. // vertices for FLAT shade mode. In triangle fans the second vertex defines
  143. // the color in FLAT shade mode. So we will make the vertex order: 1, 2, 0
  144. MAKE_CLIP_VERTEX_FVF(pv, cv[2], p1, f1, vertexTransformed);
  145. for (i = pv->dwNumVertices-2; i; i--)
  146. {
  147. DWORD f2, f3; // vertex clip flags
  148. f2 = clipCode[0];
  149. f3 = clipCode[1];
  150. BOOL needClip = FALSE;
  151. BOOL offFrustum = FALSE;
  152. if (f1 & f2 & f3)
  153. offFrustum = TRUE;
  154. else
  155. if ((f1 | f2 | f3) & pv->dwClipMaskOffScreen)
  156. needClip = TRUE;
  157. if (offFrustum || needClip)
  158. { // if this tri does need clipping
  159. if (vertexCount)
  160. { // first draw the ones that didn't need clipping
  161. BYTE tmp[__MAX_VERTEX_SIZE];
  162. BYTE *pStart = startVertex;
  163. if (startVertex != p1)
  164. {
  165. pStart -= vertexSize;
  166. memcpy (tmp, pStart, vertexSize);
  167. memcpy (pStart, p1, vertexSize);
  168. // Mark this call as gen by clipper, but set non clipped bit
  169. pv->dwFlags |= D3DPV_NONCLIPPED;
  170. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2,
  171. vertexCount);
  172. pv->dwFlags &= ~D3DPV_NONCLIPPED;
  173. }
  174. else
  175. {
  176. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  177. }
  178. if (ret)
  179. return ret;
  180. if (startVertex != p1)
  181. memcpy (pStart, tmp, vertexSize);
  182. if (ret)
  183. return ret;
  184. }
  185. // reset count and start ptr
  186. vertexCount = 0;
  187. startVertex = vertex + vertexSize;
  188. // now deal with the single clipped triangle
  189. // first check if it should just be tossed or if it should be clipped
  190. if (!offFrustum)
  191. {
  192. BYTE *p2 = vertex;
  193. BYTE *p3 = vertex + vertexSize;
  194. MAKE_CLIP_VERTEX_FVF(pv, cv[0], p2, f2, vertexTransformed);
  195. MAKE_CLIP_VERTEX_FVF(pv, cv[1], p3, f3, vertexTransformed);
  196. ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
  197. if (ret) return ret;
  198. }
  199. } else
  200. vertexCount++;
  201. clipCode++;
  202. vertex += vertexSize;
  203. }
  204. // draw final batch, if any
  205. if (vertexCount)
  206. {
  207. BYTE tmp[__MAX_VERTEX_SIZE];
  208. BYTE *pStart = startVertex;
  209. if (startVertex == p1)
  210. {
  211. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  212. }
  213. else
  214. {
  215. pStart -= vertexSize;
  216. memcpy(tmp, pStart, vertexSize);
  217. memcpy(pStart, p1, vertexSize);
  218. // Mark this call as gen by clipper
  219. pv->dwFlags |= D3DPV_NONCLIPPED;
  220. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  221. pv->dwFlags &= ~D3DPV_NONCLIPPED;
  222. }
  223. if (ret)
  224. return ret;
  225. if (startVertex != p1)
  226. memcpy(pStart, tmp, vertexSize);
  227. if (ret)
  228. return ret;
  229. }
  230. return D3D_OK;
  231. }
  232. //------------------------------------------------------------------------------
  233. HRESULT ProcessClippedIndexedTriangleFan(D3DFE_PROCESSVERTICES *pv)
  234. {
  235. WORD *p1;
  236. DWORD f1;
  237. D3DFE_CLIPCODE *clipCode;
  238. DWORD i;
  239. HRESULT ret;
  240. BYTE *vertex;
  241. LPWORD startVertex;
  242. LPWORD index = pv->lpwIndices; \
  243. int vertexCount;
  244. DWORD vertexSize;
  245. ClipVertex cv[3];
  246. BOOL vertexTransformed;
  247. vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;
  248. clipCode = pv->lpClipFlags;
  249. vertex = (BYTE*)pv->lpvOut;
  250. startVertex = pv->lpwIndices;
  251. vertexSize = pv->dwOutputSize;
  252. vertexCount = 0;
  253. f1 = clipCode[index[0]];
  254. p1 = index;
  255. index++;
  256. BYTE *ver = vertex + p1[0]*vertexSize;
  257. // In the clipper color from the first vertex is propagated to all
  258. // vertices for FLAT shade mode. In triangle fans the second vertex defines
  259. // the color in FLAT shade mode. So we will make the vertex order: 1, 2, 0
  260. MAKE_CLIP_VERTEX_FVF(pv, cv[2], ver, f1, vertexTransformed);
  261. for (i = pv->dwNumPrimitives; i; i--)
  262. {
  263. DWORD f2, f3; // vertex clip flags
  264. WORD v1, v2;
  265. v1 = index[0];
  266. v2 = index[1];
  267. f2 = clipCode[v1];
  268. f3 = clipCode[v2];
  269. BOOL needClip = FALSE;
  270. BOOL offFrustum = FALSE;
  271. if (f1 & f2 & f3)
  272. offFrustum = TRUE;
  273. else
  274. if ((f1 | f2 | f3) & pv->dwClipMaskOffScreen)
  275. needClip = TRUE;
  276. if (offFrustum || needClip)
  277. { // if this tri does need clipping
  278. if (vertexCount)
  279. { // first draw the ones that didn't need clipping
  280. WORD tmp;
  281. WORD *pStart = startVertex;
  282. if (startVertex != p1)
  283. {
  284. pStart--;
  285. tmp = *pStart; // Save old value to restore later
  286. *pStart = *p1;
  287. }
  288. ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2,
  289. vertexCount);
  290. if (ret)
  291. return ret;
  292. if (startVertex != p1)
  293. *pStart = tmp; // Restore old value
  294. if (ret)
  295. return ret;
  296. }
  297. // reset count and start ptr
  298. vertexCount = 0;
  299. startVertex = &index[1];
  300. // now deal with the single clipped triangle
  301. // first check if it should just be tossed or if it should be clipped
  302. if (!offFrustum)
  303. {
  304. BYTE *p2 = vertex + v1*vertexSize;
  305. BYTE *p3 = vertex + v2*vertexSize;
  306. MAKE_CLIP_VERTEX_FVF(pv, cv[0], p2, f2, vertexTransformed);
  307. MAKE_CLIP_VERTEX_FVF(pv, cv[1], p3, f3, vertexTransformed);
  308. ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
  309. if (ret) return ret;
  310. }
  311. }
  312. else
  313. vertexCount++;
  314. index++;
  315. }
  316. // draw final batch, if any
  317. if (vertexCount)
  318. {
  319. WORD tmp;
  320. WORD *pStart = startVertex;
  321. if (startVertex != p1)
  322. {
  323. pStart--;
  324. tmp = *pStart; // Save old value to restore later
  325. *pStart = *p1;
  326. }
  327. ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  328. if (ret)
  329. return ret;
  330. if (startVertex != p1)
  331. *pStart = tmp; // Restore old value
  332. if (ret)
  333. return ret;
  334. }
  335. return D3D_OK;
  336. }
  337. #define __PROCESS_LINE_NAME ProcessClippedLine
  338. #define __PROCESS_TRI_LIST_NAME ProcessClippedTriangleList
  339. #define __PROCESS_TRI_STRIP_NAME ProcessClippedTriangleStrip
  340. #include "clipprim.h"
  341. #define __INDEX_PRIM
  342. #define __PROCESS_TRI_LIST_NAME ProcessClippedIndexedTriangleList
  343. #define __PROCESS_TRI_STRIP_NAME ProcessClippedIndexedTriangleStrip
  344. #define __PROCESS_LINE_NAME ProcessClippedIndexedLine
  345. #include "clipprim.h"
  346. //---------------------------------------------------------------------
  347. HRESULT ProcessClippedPoints(D3DFE_PROCESSVERTICES *pv)
  348. {
  349. DWORD i;
  350. WORD count;
  351. BYTE *lpStartVertex;
  352. BYTE *lpCurVertex;
  353. HRESULT ret;
  354. D3DFE_CLIPCODE *clipCode;
  355. const DWORD nVertices = pv->dwNumVertices;
  356. clipCode = pv->lpClipFlags;
  357. count = 0;
  358. lpStartVertex = lpCurVertex = (BYTE*)pv->lpvOut;
  359. DWORD dwVertexBaseOrg = pv->dwVertexBase;
  360. for (i=0; i < nVertices; i++)
  361. {
  362. if (clipCode[i])
  363. { // if this point is clipped
  364. pv->dwVertexBase = dwVertexBaseOrg + i - count;
  365. if (count)
  366. { // first draw the ones that didn't need clipping
  367. ret = DRAW_PRIM(pv, D3DPT_POINTLIST, lpStartVertex, count, count);
  368. if (ret)
  369. return ret;
  370. }
  371. // reset count and start ptr
  372. count = 0;
  373. lpCurVertex += pv->dwOutputSize;
  374. lpStartVertex = lpCurVertex;
  375. }
  376. else
  377. {
  378. count++;
  379. lpCurVertex += pv->dwOutputSize;
  380. }
  381. }
  382. // draw final batch, if any
  383. if (count)
  384. {
  385. pv->dwVertexBase = dwVertexBaseOrg + nVertices - count;
  386. ret = DRAW_PRIM(pv, D3DPT_POINTLIST, lpStartVertex, count, count);
  387. if (ret)
  388. return ret;
  389. }
  390. return D3D_OK;
  391. }