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.

612 lines
21 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. //----------------------------------------------------------------------
  12. HRESULT D3DFE_PVFUNCSI::Clip(D3DFE_PROCESSVERTICES *pv, ClipVertex *cv1,
  13. ClipVertex *cv2,
  14. 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. cv1->clip |= CLIPPED_ENABLE;
  25. cv2->clip |= CLIPPED_ENABLE;
  26. cv3->clip |= CLIPPED_ENABLE;
  27. // For the flat shading mode we have to use first vertex color as
  28. // color for all vertices
  29. D3DCOLOR diffuse1; // Original colors
  30. D3DCOLOR specular1;
  31. D3DCOLOR diffuse2;
  32. D3DCOLOR specular2;
  33. if (pv->lpdwRStates[D3DRS_SHADEMODE] == D3DSHADE_FLAT)
  34. {
  35. // It is easier to set all vertices to the same color here
  36. D3DCOLOR diffuse = cv1->color;
  37. // Exclude fog factor
  38. D3DCOLOR specular = cv1->specular & 0x00FFFFFF;
  39. //Save original colors
  40. diffuse1 = cv2->color;
  41. specular1 = cv2->specular;
  42. diffuse2 = cv3->color;
  43. specular2 = cv3->specular;
  44. // Copy the same color to all vertices but preserve fog factor, because
  45. // fog factor should be interpolated
  46. cv2->color = diffuse;
  47. cv3->color = diffuse;
  48. cv2->specular = (cv2->specular & 0xFF000000) | specular;
  49. cv3->specular = (cv3->specular & 0xFF000000) | specular;
  50. }
  51. if (count = pv->pGeometryFuncs->ClipSingleTriangle(pv, &newtri, &ver))
  52. {
  53. int i;
  54. HRESULT ret;
  55. BYTE *pTLV = pv->ClipperState.clipBuf;
  56. BYTE *p = pTLV;
  57. for (i = 0; i < count; i++)
  58. {
  59. MAKE_TL_VERTEX_FVF(pv, p, ver[i]);
  60. p += pv->dwOutputSize;
  61. }
  62. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, pTLV, count, count-2);
  63. if (ret)
  64. return ret;
  65. }
  66. // CLIPPED_ENABLE bit could be set in the ClipSingleTriangle.
  67. // If this bit is not cleared, clipping will be wrong. Because, clip
  68. // vertices are re-used by next triangles.
  69. // This bit should be cleared *after* drawing command. Otherwise, edge flags
  70. // will be incorrect
  71. cv1->clip &= ~CLIPPED_ENABLE;
  72. cv2->clip &= ~CLIPPED_ENABLE;
  73. cv3->clip &= ~CLIPPED_ENABLE;
  74. if (pv->lpdwRStates[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
  75. {
  76. // Restore original colors
  77. cv2->color = diffuse1;
  78. cv2->specular = specular1;
  79. cv3->color = diffuse2;
  80. cv3->specular = specular2;
  81. }
  82. pv->lpvOut = saveVer;
  83. pv->dwNumVertices = numVer;
  84. return D3D_OK;
  85. }
  86. //----------------------------------------------------------------------
  87. HRESULT D3DFE_PVFUNCSI::ClipLine(D3DFE_PROCESSVERTICES *pv, ClipVertex *v1, ClipVertex *v2)
  88. {
  89. ClipTriangle newline;
  90. LPVOID saveVer = pv->lpvOut; // For indexed primitive
  91. DWORD numVer = pv->dwNumVertices; // For indexed primitive
  92. ClipVertex cv1 = *v1;
  93. ClipVertex cv2 = *v2;
  94. newline.v[0] = &cv1;
  95. newline.v[1] = &cv2;
  96. int count;
  97. ClipVertex** ver;
  98. if (pv->lpdwRStates[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
  99. {
  100. // Copy the same color to all vertices but preserve fog factor, because
  101. // fog factor should be interpolated
  102. cv2.color = cv1.color;
  103. cv2.specular = (cv2.specular & 0xFF000000)|(cv1.specular & 0x00FFFFFF);
  104. }
  105. if (ClipSingleLine(pv, &newline))
  106. {
  107. BYTE *pTLV = pv->ClipperState.clipBuf;
  108. BYTE *p = pTLV;
  109. MAKE_TL_VERTEX_FVF(pv, p, newline.v[0]);
  110. p += pv->dwOutputSize;
  111. MAKE_TL_VERTEX_FVF(pv, p, newline.v[1]);
  112. HRESULT ret = DRAW_CLIPPED_PRIM(pv, D3DPT_LINELIST, pTLV, 2, 1);
  113. if (ret)
  114. return ret;
  115. }
  116. pv->lpvOut = saveVer;
  117. pv->dwNumVertices = numVer;
  118. return D3D_OK;
  119. }
  120. //------------------------------------------------------------------------------
  121. HRESULT D3DFE_PVFUNCSI::ProcessClippedTriangleFan(D3DFE_PROCESSVERTICES *pv)
  122. {
  123. BYTE *p1;
  124. DWORD f1;
  125. D3DFE_CLIPCODE *clipCode;
  126. DWORD i;
  127. HRESULT ret;
  128. BYTE *vertex;
  129. BYTE *startVertex;
  130. int vertexCount;
  131. DWORD vertexSize;
  132. ClipVertex cv[3];
  133. BOOL vertexTransformed;
  134. vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;;
  135. clipCode = pv->lpClipFlags;
  136. vertex = (BYTE*)pv->lpvOut;
  137. startVertex = (BYTE*)pv->lpvOut;
  138. vertexSize = pv->dwOutputSize;
  139. vertexCount = 0;
  140. f1 = clipCode[0];
  141. p1 = vertex;
  142. clipCode++;
  143. vertex += vertexSize;
  144. // In the clipper color from the first vertex is propagated to all
  145. // vertices for FLAT shade mode. In triangle fans the second vertex defines
  146. // the color in FLAT shade mode. So we will make the vertex order: 1, 2, 0
  147. MAKE_CLIP_VERTEX_FVF(pv, cv[2], p1, f1, vertexTransformed);
  148. for (i = pv->dwNumVertices-2; i; i--)
  149. {
  150. DWORD f2, f3; // vertex clip flags
  151. f2 = clipCode[0];
  152. f3 = clipCode[1];
  153. BOOL needClip = FALSE;
  154. BOOL offFrustum = FALSE;
  155. if (f1 & f2 & f3)
  156. offFrustum = TRUE;
  157. else
  158. if ((f1 | f2 | f3) & pv->dwClipMaskOffScreen)
  159. needClip = TRUE;
  160. if (offFrustum || needClip)
  161. { // if this tri does need clipping
  162. if (vertexCount)
  163. { // first draw the ones that didn't need clipping
  164. BYTE tmp[__MAX_VERTEX_SIZE];
  165. BYTE *pStart = startVertex;
  166. if (startVertex != p1)
  167. {
  168. pStart -= vertexSize;
  169. memcpy (tmp, pStart, vertexSize);
  170. memcpy (pStart, p1, vertexSize);
  171. // Mark this call as gen by clipper, but set non clipped bit
  172. pv->dwFlags |= D3DPV_NONCLIPPED;
  173. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2,
  174. vertexCount);
  175. pv->dwFlags &= ~D3DPV_NONCLIPPED;
  176. }
  177. else
  178. {
  179. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  180. }
  181. if (startVertex != p1)
  182. memcpy (pStart, tmp, vertexSize);
  183. if (ret)
  184. return ret;
  185. }
  186. // reset count and start ptr
  187. vertexCount = 0;
  188. startVertex = vertex + vertexSize;
  189. // now deal with the single clipped triangle
  190. // first check if it should just be tossed or if it should be clipped
  191. if (!offFrustum)
  192. {
  193. BYTE *p2 = vertex;
  194. BYTE *p3 = vertex + vertexSize;
  195. MAKE_CLIP_VERTEX_FVF(pv, cv[0], p2, f2, vertexTransformed);
  196. MAKE_CLIP_VERTEX_FVF(pv, cv[1], p3, f3, vertexTransformed);
  197. ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
  198. if (ret) return ret;
  199. }
  200. } else
  201. vertexCount++;
  202. clipCode++;
  203. vertex += vertexSize;
  204. }
  205. // draw final batch, if any
  206. if (vertexCount)
  207. {
  208. BYTE tmp[__MAX_VERTEX_SIZE];
  209. BYTE *pStart = startVertex;
  210. if (startVertex == p1)
  211. {
  212. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  213. }
  214. else
  215. {
  216. pStart -= vertexSize;
  217. memcpy(tmp, pStart, vertexSize);
  218. memcpy(pStart, p1, vertexSize);
  219. // Mark this call as gen by clipper
  220. pv->dwFlags |= D3DPV_NONCLIPPED;
  221. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2, vertexCount);
  222. pv->dwFlags &= ~D3DPV_NONCLIPPED;
  223. }
  224. if (startVertex != p1)
  225. memcpy(pStart, tmp, vertexSize);
  226. if (ret)
  227. return ret;
  228. }
  229. return D3D_OK;
  230. }
  231. //------------------------------------------------------------------------------
  232. HRESULT
  233. D3DFE_PVFUNCSI::ProcessClippedIndexedTriangleFan(D3DFE_PROCESSVERTICES *pv)
  234. {
  235. DWORD f1; // Clip code for the first vertex
  236. D3DFE_CLIPCODE *clipCode;
  237. DWORD i;
  238. HRESULT ret;
  239. // Vertex array
  240. BYTE *vertex;
  241. // Start indexed of the current in-screen triangle batch
  242. LPBYTE startIndex;
  243. // Pointer to second index of the current triangle
  244. LPBYTE index = (LPBYTE)pv->lpwIndices;
  245. int vertexCount;
  246. DWORD vertexSize;
  247. ClipVertex cv[3];
  248. DWORD dwIndexSize = pv->dwIndexSize;
  249. DWORD dwFirstIndex; // First index of the primitive
  250. BOOL vertexTransformed;
  251. // If there was a off-screen or clipped triangle we copy the first primitive
  252. // index to the start of the next in-screen triangle batch
  253. BOOL bWasClipping = FALSE;
  254. vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;
  255. clipCode = pv->lpClipFlags;
  256. vertex = (BYTE*)pv->lpvOut;
  257. startIndex = (LPBYTE)pv->lpwIndices;
  258. vertexSize = pv->dwOutputSize;
  259. vertexCount = 0;
  260. // Update the address of the vertex array to handle the index base
  261. if (pv->dwIndexOffset != 0)
  262. {
  263. vertex -= pv->dwIndexOffset * vertexSize;
  264. clipCode -= pv->dwIndexOffset;
  265. }
  266. if (dwIndexSize == 2)
  267. dwFirstIndex = *(WORD*)index;
  268. else
  269. dwFirstIndex = *(DWORD*)index;
  270. f1 = clipCode[dwFirstIndex];
  271. LPBYTE ver; // First vertex
  272. ver = vertex + dwFirstIndex * vertexSize;
  273. index += dwIndexSize;
  274. // In the clipper color from the first vertex is propagated to all
  275. // vertices for FLAT shade mode. In triangle fans the second vertex defines
  276. // the color in FLAT shade mode. So we will make the vertex order: 1, 2, 0
  277. MAKE_CLIP_VERTEX_FVF(pv, cv[2], ver, f1, vertexTransformed);
  278. for (i = pv->dwNumPrimitives; i; i--)
  279. {
  280. DWORD f2, f3; // vertex clip flags
  281. DWORD v1, v2;
  282. if (dwIndexSize == 2)
  283. {
  284. v1 = *(WORD*)index;
  285. v2 = *(WORD*)(index + 2);
  286. }
  287. else
  288. {
  289. v1 = *(DWORD*)index;
  290. v2 = *(DWORD*)(index + 4);
  291. }
  292. f2 = clipCode[v1];
  293. f3 = clipCode[v2];
  294. BOOL needClip = FALSE;
  295. BOOL offFrustum = FALSE;
  296. if (f1 & f2 & f3)
  297. offFrustum = TRUE;
  298. else
  299. if ((f1 | f2 | f3) & pv->dwClipMaskOffScreen)
  300. needClip = TRUE;
  301. if (offFrustum || needClip)
  302. { // if this tri does need clipping
  303. if (vertexCount)
  304. { // first draw the ones that didn't need clipping
  305. WORD* pStart = (WORD*)startIndex;
  306. DWORD tmp;
  307. if (bWasClipping)
  308. {
  309. // Save old value of the index before the current start
  310. // index and copy the first primitive index there. This
  311. // will the start of the current unclipped batch
  312. if (dwIndexSize == 2)
  313. {
  314. pStart--;
  315. tmp = *pStart;
  316. *pStart = (WORD)dwFirstIndex;
  317. }
  318. else
  319. {
  320. pStart -= 2;
  321. tmp = *(DWORD*)pStart;
  322. *(DWORD*)pStart = dwFirstIndex;
  323. }
  324. }
  325. ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2,
  326. vertexCount);
  327. if (bWasClipping)
  328. { // Restore old value
  329. if (dwIndexSize == 2)
  330. *pStart = (WORD)tmp;
  331. else
  332. *(DWORD*)pStart = tmp;
  333. }
  334. if (ret)
  335. return ret;
  336. }
  337. bWasClipping = TRUE;
  338. // reset count and start ptr
  339. vertexCount = 0;
  340. startIndex = index + dwIndexSize;
  341. // now deal with the single clipped triangle
  342. // first check if it should just be tossed or if it should be clipped
  343. if (!offFrustum)
  344. {
  345. BYTE *p2 = vertex + v1*vertexSize;
  346. BYTE *p3 = vertex + v2*vertexSize;
  347. MAKE_CLIP_VERTEX_FVF(pv, cv[0], p2, f2, vertexTransformed);
  348. MAKE_CLIP_VERTEX_FVF(pv, cv[1], p3, f3, vertexTransformed);
  349. ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
  350. if (ret) return ret;
  351. }
  352. }
  353. else
  354. vertexCount++;
  355. index += dwIndexSize;
  356. }
  357. // draw final batch, if any
  358. if (vertexCount)
  359. {
  360. WORD* pStart = (WORD*)startIndex;
  361. DWORD tmp;
  362. if (bWasClipping)
  363. {
  364. // Save old value of the index before the current start
  365. // index and copy the first primitive index there. This
  366. // will the start of the current unclipped batch
  367. if (dwIndexSize == 2)
  368. {
  369. pStart--;
  370. tmp = *pStart;
  371. *pStart = (WORD)dwFirstIndex;
  372. }
  373. else
  374. {
  375. pStart -= 2;
  376. tmp = *(DWORD*)pStart;
  377. *(DWORD*)pStart = dwFirstIndex;
  378. }
  379. }
  380. ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLEFAN, pStart, vertexCount+2,
  381. vertexCount);
  382. if (bWasClipping)
  383. { // Restore old value
  384. if (dwIndexSize == 2)
  385. *pStart = (WORD)tmp;
  386. else
  387. *(DWORD*)pStart = tmp;
  388. }
  389. if (ret)
  390. return ret;
  391. }
  392. return D3D_OK;
  393. }
  394. #define __PROCESS_LINE_NAME ProcessClippedLine
  395. #define __PROCESS_TRI_LIST_NAME ProcessClippedTriangleList
  396. #define __PROCESS_TRI_STRIP_NAME ProcessClippedTriangleStrip
  397. #include "clipprim.h"
  398. #define __INDEX_PRIM
  399. #define __PROCESS_TRI_LIST_NAME ProcessClippedIndexedTriangleList
  400. #define __PROCESS_TRI_STRIP_NAME ProcessClippedIndexedTriangleStrip
  401. #define __PROCESS_LINE_NAME ProcessClippedIndexedLine
  402. #include "clipprim.h"
  403. //---------------------------------------------------------------------
  404. HRESULT D3DFE_PVFUNCSI::ProcessClippedPoints(D3DFE_PROCESSVERTICES *pv)
  405. {
  406. DWORD i;
  407. WORD count;
  408. BYTE *lpStartVertex;
  409. BYTE *lpCurVertex;
  410. HRESULT ret;
  411. D3DFE_CLIPCODE *clipCode;
  412. const DWORD nVertices = pv->dwNumVertices;
  413. clipCode = pv->lpClipFlags;
  414. count = 0;
  415. lpStartVertex = lpCurVertex = (BYTE*)pv->lpvOut;
  416. for (i=0; i < nVertices; i++)
  417. {
  418. if (clipCode[i])
  419. { // if this point is clipped
  420. if (count)
  421. { // first draw the ones that didn't need clipping
  422. ret = DRAW_PRIM(pv, D3DPT_POINTLIST, lpStartVertex, count, count);
  423. if (ret)
  424. return ret;
  425. }
  426. // reset count and start ptr
  427. count = 0;
  428. lpCurVertex += pv->dwOutputSize;
  429. lpStartVertex = lpCurVertex;
  430. pv->pDDI->SkipVertices(1);
  431. }
  432. else
  433. {
  434. count++;
  435. lpCurVertex += pv->dwOutputSize;
  436. }
  437. }
  438. // draw final batch, if any
  439. if (count)
  440. {
  441. ret = DRAW_PRIM(pv, D3DPT_POINTLIST, lpStartVertex, count, count);
  442. if (ret)
  443. return ret;
  444. }
  445. return D3D_OK;
  446. }
  447. //---------------------------------------------------------------------
  448. // We do not throw away point sprites which centers are off screeen.
  449. // We detect this case and compute screen coordinates for those sprites
  450. //
  451. HRESULT ProcessClippedPointSprites(D3DFE_PROCESSVERTICES *pv)
  452. {
  453. DWORD i;
  454. WORD count;
  455. BYTE *lpStartVertex;
  456. BYTE *lpCurVertex;
  457. HRESULT ret;
  458. D3DFE_CLIPCODE *clipCode;
  459. const DWORD nVertices = pv->dwNumVertices;
  460. clipCode = pv->lpClipFlags;
  461. count = 0;
  462. lpStartVertex = lpCurVertex = (BYTE*)pv->lpvOut;
  463. for (i=0; i < nVertices; i++)
  464. {
  465. // If a point is outside screen or guard band, the sprite could still
  466. // be visible (when the guard band is small enough
  467. if (clipCode[i] & ~(D3DCS_LEFT | D3DCS_RIGHT |
  468. D3DCS_TOP | D3DCS_BOTTOM |
  469. __D3DCLIPGB_ALL))
  470. {
  471. // This point is off viewing frustum
  472. if (count)
  473. { // first draw the ones that didn't need clipping
  474. ret = DRAW_PRIM(pv, D3DPT_POINTLIST, lpStartVertex, count, count);
  475. if (ret)
  476. return ret;
  477. }
  478. // reset count and start ptr
  479. count = 0;
  480. lpCurVertex += pv->dwOutputSize;
  481. lpStartVertex = lpCurVertex;
  482. if (!(pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION))
  483. pv->pDDI->SkipVertices(1);
  484. }
  485. else
  486. {
  487. if (clipCode[i])
  488. {
  489. // When we are here, the point sprite center is off-screen, but
  490. // could be visible
  491. // Non zero when the point is outside guard band
  492. DWORD gbBits = clipCode[i] & __D3DCLIPGB_ALL;
  493. // Screen coordinates were not computed for the point if there is
  494. // no guard band or the point is outside the guard band
  495. if (!(pv->dwDeviceFlags & D3DDEV_GUARDBAND) ||
  496. (pv->dwDeviceFlags & D3DDEV_GUARDBAND) && gbBits)
  497. {
  498. D3DVECTORH* p = (D3DVECTORH*)lpCurVertex;
  499. float w = 1.0f/p->w;
  500. p->x = p->x * w * pv->vcache.scaleX + pv->vcache.offsetX;
  501. p->y = p->y * w * pv->vcache.scaleY + pv->vcache.offsetY;
  502. p->z = p->z * w * pv->vcache.scaleZ + pv->vcache.offsetZ;
  503. p->w = w;
  504. }
  505. }
  506. count++;
  507. lpCurVertex += pv->dwOutputSize;
  508. }
  509. }
  510. // draw final batch, if any
  511. if (count)
  512. {
  513. ret = DRAW_PRIM(pv, D3DPT_POINTLIST, lpStartVertex, count, count);
  514. if (ret)
  515. return ret;
  516. }
  517. return D3D_OK;
  518. }
  519. //---------------------------------------------------------------------
  520. HRESULT D3DFE_PVFUNCSI::ProcessClippedIndexedPoints(D3DFE_PROCESSVERTICES *pv)
  521. {
  522. DWORD i;
  523. WORD count;
  524. BYTE *lpStartIndex;
  525. BYTE *lpCurIndex;
  526. HRESULT ret;
  527. D3DFE_CLIPCODE *clipCode;
  528. const DWORD nIndices = pv->dwNumIndices;
  529. DWORD dwIndexSize = pv->dwIndexSize;
  530. LPBYTE pIndices = (LPBYTE)pv->lpwIndices;
  531. clipCode = pv->lpClipFlags;
  532. count = 0;
  533. lpStartIndex = lpCurIndex = (BYTE*)pv->lpwIndices;
  534. // Update the address of the vertex array to handle the index base
  535. clipCode -= pv->dwIndexOffset;
  536. for (i=0; i < nIndices; i++)
  537. {
  538. DWORD index;
  539. if (dwIndexSize == 2)
  540. index = *(WORD*)pIndices;
  541. else
  542. index = *(DWORD*)pIndices;
  543. pIndices += dwIndexSize;
  544. if (clipCode[index])
  545. { // if this point is clipped
  546. if (count)
  547. { // first draw the ones that didn't need clipping
  548. ret = DRAW_INDEX_PRIM(pv, D3DPT_POINTLIST, (WORD*)lpStartIndex,
  549. count, count);
  550. if (ret)
  551. return ret;
  552. }
  553. // reset count and start ptr
  554. count = 0;
  555. lpCurIndex += pv->dwIndexSize;
  556. lpStartIndex = lpCurIndex;
  557. }
  558. else
  559. {
  560. count++;
  561. lpCurIndex += pv->dwIndexSize;
  562. }
  563. }
  564. // draw final batch, if any
  565. if (count)
  566. {
  567. ret = DRAW_INDEX_PRIM(pv, D3DPT_POINTLIST, (WORD*)lpStartIndex, count,
  568. count);
  569. if (ret)
  570. return ret;
  571. }
  572. return D3D_OK;
  573. }