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.

1429 lines
53 KiB

  1. /*============================ ==============================================;
  2. *
  3. * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: pvone.mcp
  6. * Content: Clipping and vertex processing in one loop
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. include(`pvvid.mh') dnl
  12. extern DWORD g_DebugFlags; // defined in pvvid.mcp
  13. //--------------------------------------------------------------------------
  14. // Bits describing a vertex
  15. // Set if vertex participates in a completely inside triangle
  16. const __VERTEX_IN_INSIDETRIANGLE = 1;
  17. const __2_VERTEX_IN_INSIDETRIANGLE = 1 << 5;
  18. const __3_VERTEX_IN_INSIDETRIANGLE = 1 << 10;
  19. // Set if vertex participates in a triangle, which requires clipping
  20. const __VERTEX_IN_CLIPTRIANGLE = 2;
  21. const __2_VERTEX_IN_CLIPTRIANGLE = 2 << 5;
  22. const __3_VERTEX_IN_CLIPTRIANGLE = 2 << 10;
  23. // The following two bits are set for the first vertex of every triangle
  24. // in the triangle strip.
  25. const __TRIANGLE_OUTSIDE = 4;
  26. const __TRIANGLE_CLIP = 8;
  27. const __TRIANGLE_INSIDE = 16;
  28. const __3_TRIANGLE_OUTSIDE = 4 << 10;
  29. const __3_TRIANGLE_CLIP = 8 << 10;
  30. const __2_TRIANGLE_OUTSIDE = 4 << 5;
  31. const __2_TRIANGLE_CLIP = 8 << 5;
  32. const __3_TRIANGLE_INSIDE = 16 << 10;
  33. const __2_TRIANGLE_INSIDE = 16 << 5;
  34. //--------------------------------------------------------------------------
  35. // TransformVertexMakeClipCode
  36. //
  37. // Transforms vertex coordinates to the clipping space and computes clip code
  38. //
  39. // Arguments:
  40. // pInp - input pointer (D3DVERTEX)
  41. // pOut - output pointer (ClipVertex)
  42. // Output:
  43. // Returns clip code
  44. // Transformed coordinates are written to the clip vertex (hx, hy, hz, hw, clip)
  45. //
  46. DWORD TransformVertexMakeClipCode(D3DFE_PROCESSVERTICES *pv, D3DVERTEX* pInp,
  47. D3DVALUE* pWeights, BYTE* pMatrixIndices, ClipVertex* pOut)
  48. {
  49. D3DVALUE x,y,z,w;
  50. DWORD clip;
  51. d_TransformVertex(1, pInp, (&pv->mCTM[0]), x,y,z,w, pWeights, pMatrixIndices)
  52. d_ComputeClipCode(1)
  53. if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
  54. {
  55. d_ComputeClipCodeGB(2)
  56. }
  57. pOut->hx = x;
  58. pOut->hy = y;
  59. pOut->hz = z;
  60. pOut->hw = w;
  61. pOut->clip = clip;
  62. return clip;
  63. }
  64. //--------------------------------------------------------------------------
  65. // ComputeScreenCoordinates
  66. //
  67. // Computes screen coordinates for the ClipVertex
  68. // Arguments:
  69. // pOut - pointer to the ClipVertex
  70. //
  71. inline void ComputeScreenCoordinates(D3DFE_PROCESSVERTICES *pv, ClipVertex* pInp, D3DVECTORH *pOut)
  72. {
  73. D3DVALUE xs, ys, zs, w;
  74. w = D3DVAL(1)/pInp->hw;
  75. d_ComputeScreenCoordinatesNoOutput(1,pInp->hx,pInp->hy,pInp->hz,w,xs,ys,zs)
  76. pOut->x = xs;
  77. pOut->y = ys;
  78. pOut->z = zs;
  79. pOut->w = w;
  80. }
  81. //--------------------------------------------------------------------------
  82. // Update input and output pointers to start from dwStartVertexIndex
  83. //
  84. inline void SetInputAndOutputPointers(D3DFE_PROCESSVERTICES *pv, DWORD dwStartVertexIndex)
  85. {
  86. // Update output pointer
  87. pv->lpvOut = (char*)pv->lpvOut + dwStartVertexIndex * pv->dwOutputSize;
  88. // Update input pointers
  89. pv->position.lpvData = (char*)pv->position.lpvData + dwStartVertexIndex * pv->position.dwStride;
  90. if (pv->dwDeviceFlags & D3DDEV_STRIDE)
  91. {
  92. pv->normal.lpvData = (char*)pv->normal.lpvData + dwStartVertexIndex * pv->normal.dwStride;
  93. pv->diffuse.lpvData = (char*)pv->diffuse.lpvData + dwStartVertexIndex * pv->diffuse.dwStride;
  94. pv->specular.lpvData = (char*)pv->specular.lpvData + dwStartVertexIndex * pv->specular.dwStride;
  95. for (DWORD i=0; i < pv->nTexCoord; i++)
  96. pv->textures[i].lpvData = (char*)pv->textures[i].lpvData +
  97. dwStartVertexIndex * pv->textures[i].dwStride;
  98. }
  99. }
  100. dnl//--------------------------------------------------------------------------
  101. dnl// d_TransformVertexMakeClipCode
  102. dnl//
  103. dnl// Transforms vertex coordinates to the clipping space and computes clip code
  104. dnl//
  105. dnl// Arguments:
  106. dnl// $1 - margin count
  107. dnl// $2 - input pointer (D3DVERTEX)
  108. dnl// $3 - output pointer (ClipVertex)
  109. dnl// $4 - pointer to weights
  110. dnl// $5 - pointer to matrix indices
  111. dnl// Output:
  112. dnl// x,y,z,w should be defined as float
  113. dnl// clip should be defined as DWORD
  114. dnl//
  115. define(`d_TransformVertexMakeClipCode',`dnl
  116. d_empty_($1)d_TransformVertex($1, $2, m, x,y,z,w, $4, $5)
  117. d_margin($1)d_ComputeClipCode($1)
  118. d_margin($1)if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
  119. d_margin($1){
  120. d_margin($1) d_ComputeClipCodeGB($1+1)
  121. d_margin($1)}
  122. d_margin($1)$3->hx = x;
  123. d_margin($1)$3->hy = y;
  124. d_margin($1)$3->hz = z;
  125. d_margin($1)$3->hw = w;
  126. d_margin($1)$3->clip = clip;') dnl
  127. dnl//--------------------------------------------------------------------------
  128. dnl// Copies processed vertex to the output FVF buffer
  129. dnl//
  130. dnl// Input:
  131. dnl// $1 - Margin count
  132. dnl// $2 - output buffer
  133. dnl// Notes:
  134. dnl// Output vertex pointer is moved to the next vertex
  135. dnl//
  136. define(`d_CopyToOutputVertex',`dnl
  137. d_empty_($1)// copy to the output vertex
  138. d_margin($1)$2->sx = x;
  139. d_margin($1)$2->sy = y;
  140. d_margin($1)$2->sz = z;
  141. d_margin($1)$2->rhw = w;
  142. d_margin($1)DWORD *pOut = (DWORD*)((char*)$2 + pv->diffuseOffsetOut);
  143. d_margin($1)if (pv->dwVIDOut & D3DFVF_DIFFUSE)
  144. d_margin($1) *pOut++ = pv->lighting.outDiffuse;
  145. d_margin($1)if (pv->dwVIDOut & D3DFVF_SPECULAR)
  146. d_margin($1) *pOut++ = pv->lighting.outSpecular;
  147. d_margin($1)d_CopyTextureCoord($1, pOut)
  148. d_margin($1)$2 = (D3DTLVERTEX*)((BYTE*)$2 + pv->dwOutputSize);')dnl
  149. dnl//--------------------------------------------------------------------------
  150. dnl// Copies processed vertex to the clip vertex
  151. dnl//
  152. dnl// Input:
  153. dnl// $1 - Margin count
  154. dnl// $2 - clip vertex address
  155. dnl//
  156. define(`d_CopyToClipVertex',`dnl
  157. d_empty_($1)if (($2->clip & pv->dwClipMaskOffScreen) == 0)
  158. d_margin($1){ // Copy screen coordinates
  159. d_margin($1) $2->sx = x;
  160. d_margin($1) $2->sy = y;
  161. d_margin($1) $2->sz = z;
  162. d_margin($1) $2->rhw = w;
  163. d_margin($1)}
  164. d_margin($1)$2->color = pv->lighting.outDiffuse;
  165. d_margin($1)$2->specular= pv->lighting.outSpecular;
  166. d_margin($1)d_CopyTextureCoord($1, $2->tex)') dnl
  167. dnl//--------------------------------------------------------------------------
  168. define(`d_ProcessPrimitive',`dnl
  169. d_empty_($1){
  170. d_margin($1) pv->pGeometryFuncs->ProcessVertices(pv);
  171. d_margin($1) if (pv->dwClipIntersection)
  172. d_margin($1) return D3D_OK;
  173. d_margin($1) return (DoDrawPrimitive(pv));
  174. d_margin($1)}')dnl
  175. //---------------------------------------------------------------------
  176. // Clipping and lighting a non-indexed triangle list in one pass
  177. //
  178. HRESULT D3DFE_PVFUNCSI::ProcessTriangleList(D3DFE_PROCESSVERTICES *pv)
  179. {
  180. #ifdef DEBUG_PIPELINE
  181. if (g_DebugFlags & __DEBUG_ONEPASS)
  182. d_ProcessPrimitive(1)
  183. #endif
  184. if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
  185. d_ProcessPrimitive(1)
  186. pv->dwFirstClippedVertex = 0xFFFFFFFF;
  187. pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
  188. pv->pGeometryFuncs->ProcessVertices(pv);
  189. int primitiveCount = 0; // Number of triangles in the current unclipped part
  190. BYTE *startVertex = (BYTE*)pv->lpvOut;
  191. if (pv->dwFirstClippedVertex != 0xFFFFFFFF)
  192. {
  193. if (pv->dwFirstClippedVertex > 3)
  194. {
  195. // Compute number of unclipped primitives
  196. primitiveCount = pv->dwFirstClippedVertex / 3;
  197. // Index of the first vertex to process
  198. DWORD dwStartVertexIndex = primitiveCount * 3;
  199. DWORD dwVertexCount = dwStartVertexIndex;
  200. // Compute new number of primitives to process
  201. pv->dwNumPrimitives = pv->dwNumPrimitives - primitiveCount;
  202. SetInputAndOutputPointers(pv, dwStartVertexIndex);
  203. }
  204. }
  205. else
  206. {
  207. pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
  208. if (pv->dwClipIntersection)
  209. return D3D_OK;
  210. return (DoDrawPrimitive(pv));
  211. }
  212. HRESULT ret = D3D_OK;
  213. D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
  214. ClipVertex cv[3];
  215. DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen;
  216. LPD3DMATRIXI m = &pv->mCTM[0];
  217. D3DLIGHTINGELEMENT EyeSpaceData;
  218. d_Setup()
  219. cv[0].next = &cv[1];
  220. cv[1].next = &cv[2];
  221. for (DWORD i = pv->dwNumPrimitives; i; i--)
  222. {
  223. ClipVertex *out = cv;
  224. D3DVERTEX *lpInpVer = (D3DVERTEX*)in;
  225. D3DVALUE *pWeights = inWeights;
  226. BYTE *pMatrixIndices = inMatrixIndices;
  227. // First we transform three vertices and compute the clip codes
  228. dwClipUnion = 0;
  229. dwClipIntersection = ~0;
  230. for (DWORD i=3; i; i--)
  231. {
  232. DWORD clip = TransformVertexMakeClipCode(pv, lpInpVer, pWeights, pMatrixIndices, out);
  233. out++;
  234. dwClipUnion |= clip;
  235. dwClipIntersection &= clip;
  236. lpInpVer = (D3DVERTEX*)((BYTE*)lpInpVer + dwInpVerSize);
  237. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  238. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  239. }
  240. pv->dwClipUnion |= dwClipUnion;
  241. pv->dwClipIntersection &= dwClipIntersection;
  242. // Now we can check where the triangle is
  243. if (!dwClipIntersection)
  244. {
  245. if (!(dwClipUnion & dwClipMaskOffScreen))
  246. { // The triangle does not require clipping
  247. ClipVertex *lpXfmVer = cv;
  248. primitiveCount++;
  249. for (DWORD i=3; i; i--)
  250. {
  251. D3DVALUE x,y,z,w;
  252. w = D3DVAL(1)/lpXfmVer->hw;
  253. d_ComputeScreenCoordinates(5, lpXfmVer->hx, lpXfmVer->hy, lpXfmVer->hz, w, lpOutVer)
  254. d_DoLightingAndFog(5, in, inNormal, inDiffuse, inSpecular, lpOutVer, inWeights, inMatrixIndices)
  255. D3DVALUE *pOutTexture = (D3DVALUE*)((BYTE*)lpOutVer + pv->texOffsetOut);
  256. d_CopyTextureCoordUpdateInputPointers(5, pOutTexture)
  257. lpXfmVer = lpXfmVer->next;
  258. lpOutVer = (D3DTLVERTEX*)((BYTE*)lpOutVer + dwOutVerSize);
  259. }
  260. }
  261. else
  262. { // The triangle requires clipping
  263. if (primitiveCount)
  264. { // first draw the ones that didn't need clipping
  265. DWORD vertexCount = primitiveCount*3;
  266. ret = DRAW_PRIM(pv, D3DPT_TRIANGLELIST, startVertex,
  267. vertexCount, primitiveCount);
  268. startVertex = (BYTE*)lpOutVer;
  269. if (ret)
  270. goto l_Exit;
  271. }
  272. primitiveCount = 0;
  273. ClipVertex *lpXfmVer = cv;
  274. for (DWORD i=3; i; i--)
  275. {
  276. if ((lpXfmVer->clip & dwClipMaskOffScreen) == 0)
  277. {
  278. float x,y,z;
  279. float w = D3DVAL(1)/lpXfmVer->hw;
  280. d_ComputeScreenCoordinates(6, lpXfmVer->hx, lpXfmVer->hy, lpXfmVer->hz, w, lpXfmVer)
  281. }
  282. d_ComputeOutputColors(5, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  283. if (pv->dwVIDOut & D3DFVF_DIFFUSE)
  284. lpXfmVer->color = pv->lighting.outDiffuse;
  285. if (pv->dwVIDOut & D3DFVF_SPECULAR)
  286. lpXfmVer->specular = pv->lighting.outSpecular;
  287. d_CopyTextureCoordUpdateInputPointers(5, lpXfmVer->tex)
  288. lpXfmVer++;
  289. }
  290. ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
  291. if (ret != D3D_OK)
  292. goto l_Exit;
  293. }
  294. }
  295. else
  296. { // Triangle is outside
  297. // Update input pointers
  298. d_UpdateInputPointers(3)
  299. d_UpdateInputPointers(3)
  300. d_UpdateInputPointers(3)
  301. }
  302. }
  303. // draw final batch, if any
  304. if (primitiveCount)
  305. {
  306. DWORD dwVertexCount = primitiveCount*3;
  307. ret = DRAW_PRIM(pv, D3DPT_TRIANGLELIST, startVertex,
  308. dwVertexCount, primitiveCount);
  309. }
  310. l_Exit:
  311. return ret;
  312. }
  313. //---------------------------------------------------------------------
  314. // Clipping and lighting a non-indexed triangle fan in one pass
  315. //
  316. HRESULT D3DFE_PVFUNCSI::ProcessTriangleFan(D3DFE_PROCESSVERTICES *pv)
  317. {
  318. #ifdef DEBUG_PIPELINE
  319. if (g_DebugFlags & __DEBUG_ONEPASS)
  320. d_ProcessPrimitive(1)
  321. #endif
  322. if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
  323. d_ProcessPrimitive(1)
  324. // TRUE, if the current triangle is the first in the unclipped part of the primitive
  325. BOOL bFirstInsideTriangle = TRUE;
  326. // Index of a vertex to start processing from
  327. DWORD dwStartVertexIndex = 0;
  328. int primitiveCount = 0; // Number of triangles in the current unclipped part
  329. // Start vertex for the current unclipped part of the triangle fan
  330. BYTE *startVertex = (BYTE*)pv->lpvOut;
  331. // Current pointer to the output vertex buffer
  332. D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)startVertex;
  333. DWORD dwVertexCount = 1; // Number of processed vertices (first vertex is processed
  334. // outside of the vretx loop)
  335. DWORD dwInsideVertexCount= 0; // Number of vertices, put to the lpVout buffer
  336. pv->dwFirstClippedVertex = 0xFFFFFFFF;
  337. pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
  338. pv->pGeometryFuncs->ProcessVertices(pv);
  339. if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
  340. {
  341. pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
  342. if (pv->dwClipIntersection)
  343. return D3D_OK;
  344. return (DoDrawPrimitive(pv));
  345. }
  346. else
  347. {
  348. if (pv->dwFirstClippedVertex >= 3)
  349. {
  350. bFirstInsideTriangle = FALSE; // First vertex is already copied to the output
  351. // We process again the last unclipped vertex
  352. dwStartVertexIndex = pv->dwFirstClippedVertex - 1;
  353. // Update output pointer
  354. pv->lpvOut = (char*)pv->lpvOut + dwStartVertexIndex * pv->dwOutputSize;
  355. lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
  356. primitiveCount = dwStartVertexIndex - 2;
  357. dwVertexCount += pv->dwFirstClippedVertex;
  358. dwInsideVertexCount += pv->dwFirstClippedVertex;
  359. }
  360. }
  361. HRESULT ret;
  362. ClipVertex cv1;
  363. ClipVertex *cv2; // Vertex to process
  364. ClipVertex *cv3; // Vertex to transform
  365. ClipVertex *cv; // Previous to cv2. Used for clipping
  366. D3DVERTEX *lpInpStart; // Next input vertex to transform
  367. D3DVALUE *pWeights; // Vertex weights. Should be in ssync with lpInpStart
  368. BYTE *pMatrixIndices; // Vertex weights. Should be in ssync with lpInpStart
  369. DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
  370. LPD3DMATRIXI m = &pv->mCTM[0];
  371. // Vertex flags has 5 bits per vertex
  372. // Bits 0 - 4 - vertex cv2
  373. // Bits 5 - 9 - vertex cv3
  374. DWORD vf = 0;
  375. D3DLIGHTINGELEMENT EyeSpaceData;
  376. d_Setup()
  377. lpInpStart = (D3DVERTEX*)in;
  378. pWeights = (D3DVALUE*)inWeights;
  379. pMatrixIndices = (BYTE*)inMatrixIndices;
  380. // This is the loop count. We use "+1", because the processed vertex is behind the
  381. // transformed one.
  382. DWORD i = pv->dwNumPrimitives + 1;
  383. {
  384. // Transform, process and keep the first vertex
  385. DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, &cv1);
  386. // PSGP could transform vertices with different precision. It is possible that
  387. // PSGP detects that a vertex is inside, but we here mark it as the outside.
  388. // We force the clipping code to be zero in case when we re-transform vertices
  389. if (pv->dwFirstClippedVertex >= 3)
  390. {
  391. clip = 0;
  392. }
  393. if ((clip & dwClipMaskOffScreen) == 0)
  394. {
  395. ComputeScreenCoordinates(pv, &cv1, (D3DVECTORH*)&cv1.sx);
  396. }
  397. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  398. cv1.color = pv->lighting.outDiffuse;
  399. cv1.specular = pv->lighting.outSpecular;
  400. d_CopyTextureCoordUpdateInputPointers(2, ((DWORD*)(cv1.tex)))
  401. lpInpStart = (D3DVERTEX*)in;
  402. pWeights = inWeights;
  403. pMatrixIndices = inMatrixIndices;
  404. }
  405. cv2 = &pv->clipVer[0]; // Next output vertex for process
  406. cv3 = &pv->clipVer[1]; // Next output vertex for transform
  407. // In case when there were unclipped part, we have to update pointers
  408. // to start from dwStartVertex
  409. if (pv->dwFirstClippedVertex >= 3)
  410. {
  411. // Update input pointers
  412. in = (D3DVECTOR*)((char*)pv->position.lpvData + dwStartVertexIndex * pv->position.dwStride);
  413. if (pv->dwDeviceFlags & D3DDEV_STRIDE)
  414. {
  415. inWeights = (D3DVALUE*)((char*)pv->weights.lpvData + dwStartVertexIndex * pv->weights.dwStride);
  416. inMatrixIndices = (BYTE*)pv->matrixIndices.lpvData + dwStartVertexIndex * pv->matrixIndices.dwStride;
  417. inNormal = (D3DVECTOR*)((char*)pv->normal.lpvData + dwStartVertexIndex * pv->normal.dwStride);
  418. inDiffuse = (DWORD*)((char*)pv->diffuse.lpvData + dwStartVertexIndex * pv->diffuse.dwStride);
  419. inSpecular = (DWORD*)((char*)pv->specular.lpvData + dwStartVertexIndex * pv->specular.dwStride);
  420. for (DWORD i=0; i < pv->nTexCoord; i++)
  421. inTexture[i] = (D3DVALUE*)((char*)pv->textures[i].lpvData +
  422. dwStartVertexIndex * pv->textures[i].dwStride);
  423. }
  424. else
  425. {
  426. inWeights = (D3DVALUE*) ((char*)in + 3*sizeof(float));
  427. inMatrixIndices = (BYTE*)(inWeights + pv->dwNumVerBlends - 1);
  428. inNormal = (D3DVECTOR*) ((char*)in + pv->normalOffset);
  429. inDiffuse = (DWORD*) ((char*)in + pv->diffuseOffset);
  430. inSpecular = (DWORD*) ((char*)in + pv->specularOffset);
  431. inTexture[0] = (D3DVALUE*) ((char*)in + pv->texOffset);
  432. }
  433. // Process the last unclipped vertex and copy it to the cv2
  434. // This vertex will be copied to the output buffer later
  435. TransformVertexMakeClipCode(pv, (D3DVERTEX*)in, inWeights, inMatrixIndices, cv2);
  436. // Transformed vertex is ahead by one vertex
  437. lpInpStart = (D3DVERTEX*)((BYTE*)in + dwInpVerSize);
  438. pWeights = (D3DVALUE*)((BYTE*)inWeights + pv->weights.dwStride);
  439. pMatrixIndices = inMatrixIndices + pv->matrixIndices.dwStride;
  440. i = i-pv->dwFirstClippedVertex + 2; // New loop count
  441. cv2->clip = 0; // Fixes potential PSGP precision problem
  442. goto l_InsideLoop;
  443. }
  444. // Transformed vertex will be ahead of the processed one, because we want
  445. // to know where is the triangle when processing a vertex
  446. {
  447. TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv2);
  448. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  449. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  450. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  451. }
  452. dwClipUnion |= cv1.clip | cv2->clip;
  453. dwClipIntersection &= cv1.clip & cv2->clip;
  454. float x,y,z,w;
  455. int clip;
  456. l_ClippedLoop:
  457. d_TransformVertexMakeClipCode(1, lpInpStart, cv3, pWeights, pMatrixIndices)
  458. dwClipUnion |= clip;
  459. dwClipIntersection &= clip;
  460. l_ClippedLoop2:
  461. // Set status for cv1, cv2, cv3 vertices based on their clip codes
  462. if (!(cv1.clip & cv2->clip & cv3->clip))
  463. {
  464. if (!((cv1.clip | cv2->clip | cv3->clip) & dwClipMaskOffScreen))
  465. vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
  466. __2_TRIANGLE_INSIDE;
  467. else
  468. vf |= __VERTEX_IN_CLIPTRIANGLE | __2_VERTEX_IN_CLIPTRIANGLE |
  469. __2_TRIANGLE_CLIP;
  470. }
  471. else
  472. vf |= __2_TRIANGLE_OUTSIDE;
  473. l_ClippedLoopProcessOnly:
  474. if ((cv2->clip & pv->dwClipMaskOffScreen) == 0)
  475. { // vertex is inside the guardband or frustum
  476. // Compute screen coordinates
  477. w = D3DVAL(1)/cv2->hw;
  478. d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
  479. }
  480. if (vf & (__VERTEX_IN_INSIDETRIANGLE | __VERTEX_IN_CLIPTRIANGLE))
  481. {
  482. // Compute colors
  483. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  484. }
  485. if (vf & __VERTEX_IN_INSIDETRIANGLE)
  486. {
  487. if (vf & __TRIANGLE_OUTSIDE)
  488. {
  489. if (primitiveCount > 0)
  490. {
  491. DWORD dwVerCount = primitiveCount+2;
  492. // Draw batched primitive
  493. if (dwInsideVertexCount < dwVertexCount)
  494. {
  495. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
  496. dwVerCount, primitiveCount);
  497. if (ret != D3D_OK)
  498. goto l_Exit;
  499. // Prepare for the next part of the primitive
  500. startVertex += dwVerCount * pv->dwOutputSize;
  501. }
  502. else
  503. {
  504. // Suppose we have a fan with 5 vertices. When there is the
  505. // following sequence of triangles:
  506. // "inside" - "outside" - "inside", 6 vertices will be put to
  507. // the vertex buffer, but space was allocated only for 5.
  508. // To prevent similar cases draw the previous primitive as clipped
  509. // and re-use vertex buffer space
  510. pv->dwFlags |= D3DPV_NONCLIPPED;
  511. ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
  512. dwVerCount, primitiveCount);
  513. pv->dwFlags &= ~D3DPV_NONCLIPPED;
  514. dwInsideVertexCount -= dwVerCount;
  515. lpOutVer = (D3DTLVERTEX*)startVertex;
  516. if (ret != D3D_OK)
  517. goto l_Exit;
  518. }
  519. primitiveCount = 0;
  520. bFirstInsideTriangle = TRUE;
  521. }
  522. }
  523. if (bFirstInsideTriangle)
  524. {
  525. // For the first completely inside triangle we have to
  526. // write the first vertex to the output
  527. MAKE_TL_VERTEX_FVF(pv, (BYTE*)lpOutVer, &cv1);
  528. lpOutVer = (D3DTLVERTEX*)((BYTE*)lpOutVer + pv->dwOutputSize);
  529. bFirstInsideTriangle = FALSE;
  530. dwInsideVertexCount++;
  531. }
  532. d_CopyToOutputVertex(2, lpOutVer)
  533. dwInsideVertexCount++;
  534. }
  535. if (vf & __VERTEX_IN_CLIPTRIANGLE)
  536. {
  537. d_CopyToClipVertex(2, cv2)
  538. }
  539. if (vf & __TRIANGLE_INSIDE)
  540. { // Triangle is inside the frustum
  541. primitiveCount++;
  542. }
  543. else
  544. {
  545. if (primitiveCount > 0)
  546. {
  547. // Draw batched primitive
  548. DWORD dwVerCount = primitiveCount+2;
  549. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
  550. dwVerCount, primitiveCount);
  551. if (ret != D3D_OK)
  552. goto l_Exit;
  553. // Prepare for the next part of the primitive
  554. startVertex += dwVerCount * pv->dwOutputSize;
  555. primitiveCount = 0;
  556. bFirstInsideTriangle = TRUE;
  557. }
  558. if (vf & __TRIANGLE_CLIP)
  559. { // The triangle requires clipping
  560. // Clip prev triangle - cv1, cv, cv2
  561. HRESULT ret = Clip(pv, cv, cv2, &cv1);
  562. if (ret != D3D_OK)
  563. goto l_Exit;
  564. }
  565. }
  566. d_UpdateInputPointers(1);
  567. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  568. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  569. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  570. cv = cv2;
  571. cv2 = cv3;
  572. cv3 = cv3->next;
  573. vf >>= 5;
  574. dwVertexCount++;
  575. if (--i > 1)
  576. {
  577. if (dwClipUnion == 0 && primitiveCount == 1)
  578. {
  579. // If all vertices are inside the frustum we use the optimized loop
  580. goto l_InsideLoop;
  581. }
  582. goto l_ClippedLoop;
  583. }
  584. // For the last vertex we have to do processing only
  585. if (i)
  586. goto l_ClippedLoopProcessOnly;
  587. goto l_Exit;
  588. l_InsideLoop:
  589. d_TransformVertex(1, lpInpStart, m, x,y,z,w, pWeights, pMatrixIndices)
  590. d_ComputeClipCode(1)
  591. cv3->hx = x;
  592. cv3->hy = y;
  593. cv3->hz = z;
  594. cv3->hw = w;
  595. cv3->clip = 0;
  596. if (clip)
  597. goto l_ExitInsideLoop;
  598. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  599. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  600. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  601. l_InsideLoopProcessOnly:
  602. {
  603. w = D3DVAL(1)/cv2->hw;
  604. d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
  605. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  606. d_CopyToOutputVertex(2, lpOutVer)
  607. d_UpdateInputPointers(2)
  608. primitiveCount++;
  609. cv2 = cv3;
  610. cv3 = cv3->next;
  611. dwVertexCount++;
  612. dwInsideVertexCount++;
  613. if (--i > 1)
  614. goto l_InsideLoop;
  615. if (i)
  616. goto l_InsideLoopProcessOnly;
  617. }
  618. goto l_Exit;
  619. l_ExitInsideLoop:
  620. {
  621. // For the last transforem vertex (cv3) we computed only clip code
  622. // without guardband
  623. d_ComputeClipCodeGB(2)
  624. cv3->clip = clip;
  625. dwClipUnion |= clip;
  626. // We have to set status for the cv2 vertex
  627. vf |= __VERTEX_IN_INSIDETRIANGLE | __TRIANGLE_INSIDE;
  628. goto l_ClippedLoop2;
  629. }
  630. l_Exit:
  631. if (primitiveCount > 0)
  632. {
  633. // Draw batched primitive
  634. DWORD dwVertexCount = primitiveCount+2;
  635. ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
  636. dwVertexCount, primitiveCount);
  637. }
  638. pv->dwClipUnion = dwClipUnion;
  639. pv->dwClipIntersection = dwClipIntersection;
  640. return D3D_OK;
  641. }
  642. //---------------------------------------------------------------------
  643. // Clipping and lighting a non-indexed triangle strip in one pass
  644. //
  645. // Vertices cv1 cv2 cv3 cv4 cv5
  646. // Next to Next to
  647. // process transform
  648. // | | | |
  649. // * * * * * * * *
  650. //
  651. HRESULT D3DFE_PVFUNCSI::ProcessTriangleStrip(D3DFE_PROCESSVERTICES *pv)
  652. {
  653. #ifdef DEBUG_PIPELINE
  654. if (g_DebugFlags & __DEBUG_ONEPASS)
  655. d_ProcessPrimitive(1)
  656. #endif
  657. if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
  658. d_ProcessPrimitive(1)
  659. int primitiveCount; // Number of triangles in the current unclipped part
  660. DWORD dwTriIndex; // Index of the current triangle in the primitive
  661. // Start vertex for the current unclipped part of the triangle strip
  662. BYTE *startVertex = (BYTE*)pv->lpvOut;
  663. // Vertex flags has 5 bits per vertex
  664. // Bits 0 - 4 - vertex cv3
  665. // Bits 5 - 9 - vertex cv4
  666. // Bits 10 - 14 - vertex cv5
  667. DWORD vf = 0;
  668. D3DLIGHTINGELEMENT EyeSpaceData;
  669. pv->dwFirstClippedVertex = 0xFFFFFFFF;
  670. pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
  671. pv->pGeometryFuncs->ProcessVertices(pv);
  672. if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
  673. {
  674. pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
  675. if (pv->dwClipIntersection)
  676. return D3D_OK;
  677. return (DoDrawPrimitive(pv));
  678. }
  679. else
  680. {
  681. primitiveCount = 0;
  682. dwTriIndex = 0;
  683. if (pv->dwFirstClippedVertex > 3)
  684. {
  685. DWORD dwStartVertexIndex = pv->dwFirstClippedVertex - 2;
  686. primitiveCount = dwStartVertexIndex - 2;
  687. dwTriIndex = dwStartVertexIndex;
  688. SetInputAndOutputPointers(pv, dwStartVertexIndex);
  689. }
  690. }
  691. HRESULT ret = D3D_OK;
  692. // Current pointer to the output vertex buffer
  693. D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
  694. ClipVertex *cv1; // First vertex of delayed clipped triangle
  695. ClipVertex *cv2; // Second vertex of delayed clipped triangle
  696. ClipVertex *cv4;
  697. ClipVertex *cv3; // Vertex to process
  698. ClipVertex *cv5; // Vertex to transform
  699. D3DVERTEX *lpInpStart; // Next input vertex to transform
  700. D3DVALUE *pWeights; // Vertex weights. Should be in ssync with lpInpStart
  701. BYTE *pMatrixIndices; // Vertex weights. Should be in ssync with lpInpStart
  702. DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
  703. LPD3DMATRIXI m = &pv->mCTM[0];
  704. DWORD dwNumPrimitives = pv->dwNumPrimitives;
  705. DWORD i;
  706. BOOL bOddStrip = FALSE; // Strip starts from odd vertex index
  707. // (1, 3, 5 ...). First triangle is drawn as
  708. // indexed.
  709. d_Setup()
  710. lpInpStart = (D3DVERTEX*)in;
  711. pWeights = (D3DVALUE*)inWeights;
  712. pMatrixIndices = (BYTE*)inMatrixIndices;
  713. cv1 = NULL;
  714. cv2 = NULL;
  715. cv3 = pv->clipVer;
  716. cv5 = pv->clipVer;
  717. cv4 = cv3->next;
  718. // Transform first two vertices and copy them to the clip buffer
  719. for (DWORD j=2; j; j--)
  720. {
  721. DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv5);
  722. dwClipUnion |= clip;
  723. dwClipIntersection &= clip;
  724. cv5 = cv5->next;
  725. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  726. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  727. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  728. }
  729. float x,y,z,w;
  730. int clip;
  731. if (pv->dwFirstClippedVertex > 3)
  732. {
  733. // Force clip code to be zero to fix potential PSGP precision problem
  734. cv3->clip = 0;
  735. cv4->clip = 0;
  736. dwClipIntersection = 0;
  737. // We have to set status for the cv3 and cv4 vertices
  738. vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
  739. __TRIANGLE_INSIDE | __2_TRIANGLE_INSIDE;
  740. goto l_InsideLoop;
  741. }
  742. dwClipUnion |= cv3->clip | cv4->clip;
  743. dwClipIntersection &= cv3->clip & cv4->clip;
  744. l_ClippedLoop:
  745. d_TransformVertexMakeClipCode(1, lpInpStart, cv5, pWeights, pMatrixIndices)
  746. dwClipUnion |= clip;
  747. dwClipIntersection &= clip;
  748. l_ClippedLoop2:
  749. // Set status for cv3, cv4, cv5 vertices based on their clip codes
  750. if (!(cv3->clip & cv4->clip & cv5->clip))
  751. {
  752. if (!((cv3->clip | cv4->clip | cv5->clip) & dwClipMaskOffScreen))
  753. vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
  754. __3_VERTEX_IN_INSIDETRIANGLE | __3_TRIANGLE_INSIDE;
  755. else
  756. vf |= __VERTEX_IN_CLIPTRIANGLE | __2_VERTEX_IN_CLIPTRIANGLE |
  757. __3_VERTEX_IN_CLIPTRIANGLE | __3_TRIANGLE_CLIP;
  758. }
  759. else
  760. vf |= __3_TRIANGLE_OUTSIDE;
  761. l_ProcessOnly:
  762. // When we process a vertex, its status is completely defined
  763. if ((cv3->clip & pv->dwClipMaskOffScreen) == 0)
  764. { // vertex is inside the guardband or frustum
  765. // Compute screen coordinates
  766. w = D3DVAL(1)/cv3->hw;
  767. d_ComputeScreenCoordinatesNoOutput(2, cv3->hx, cv3->hy, cv3->hz, w, x,y,z)
  768. }
  769. if (vf & (__VERTEX_IN_INSIDETRIANGLE | __VERTEX_IN_CLIPTRIANGLE))
  770. {
  771. // Compute colors
  772. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  773. }
  774. if (vf & __VERTEX_IN_INSIDETRIANGLE)
  775. {
  776. d_CopyToOutputVertex(2, lpOutVer)
  777. }
  778. if (vf & __VERTEX_IN_CLIPTRIANGLE)
  779. {
  780. d_CopyToClipVertex(2, cv3)
  781. }
  782. if (vf & __TRIANGLE_INSIDE)
  783. {
  784. primitiveCount++;
  785. if (primitiveCount == 1)
  786. {
  787. if (dwTriIndex & 1)
  788. // First triangle has an odd index
  789. bOddStrip = TRUE;
  790. else
  791. bOddStrip = FALSE;
  792. }
  793. }
  794. else
  795. {
  796. if (primitiveCount > 0)
  797. {
  798. // Draw batched primitive
  799. if (bOddStrip)
  800. {
  801. // Draw first triangle as indexed triangle
  802. WORD indices[3] = {0, 2, 1};
  803. pv->lpvOut = startVertex;
  804. pv->dwIndexSize = 2;
  805. pv->pDDI->SetIndexedPrimParams(0, 0, 3, pv->pDDI->GetCurrentPrimBase());
  806. ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLELIST, indices, 3, 1);
  807. if (ret != D3D_OK)
  808. goto l_Error;
  809. primitiveCount--;
  810. // Move to the next vertex
  811. startVertex += pv->dwOutputSize;
  812. pv->pDDI->SkipVertices(1);
  813. }
  814. DWORD dwVerCount = primitiveCount+2;
  815. if (primitiveCount > 0)
  816. {
  817. ret = DRAW_PRIM(pv, D3DPT_TRIANGLESTRIP, startVertex,
  818. dwVerCount, primitiveCount);
  819. if (ret != D3D_OK)
  820. goto l_Error;
  821. }
  822. else
  823. {
  824. // When primitiveCount is 0 we still need to skip 2 vertices
  825. // of the odd triangle
  826. pv->pDDI->SkipVertices(2);
  827. }
  828. // Prepare for the next part of the primitive
  829. startVertex += dwVerCount * pv->dwOutputSize;
  830. primitiveCount = 0;
  831. // If next triangle is inside, we have to re-use the last vertex
  832. // of just rendered part of the triangle strip
  833. if (vf & __2_TRIANGLE_INSIDE)
  834. {
  835. pv->pDDI->MovePrimitiveBase(-1);
  836. startVertex -= pv->dwOutputSize;
  837. }
  838. }
  839. if (vf & __TRIANGLE_CLIP)
  840. { // The triangle requires clipping
  841. // Clip prev triangle - cv1, cv2, cv3
  842. HRESULT ret;
  843. if (dwTriIndex & 1)
  844. ret = Clip(pv, cv1, cv3, cv2);
  845. else
  846. ret = Clip(pv, cv1, cv2, cv3);
  847. if (ret != D3D_OK)
  848. goto l_Exit;
  849. }
  850. }
  851. d_UpdateInputPointers(1);
  852. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  853. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  854. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  855. cv1 = cv2;
  856. cv2 = cv3;
  857. cv3 = cv4;
  858. cv4 = cv5;
  859. cv5 = cv5->next;
  860. dwTriIndex++;
  861. vf >>= 5;
  862. if (dwTriIndex < dwNumPrimitives)
  863. {
  864. if (dwClipUnion == 0 && primitiveCount == 1)
  865. {
  866. // If all vertices are inside the frustum we use the optimized loop
  867. goto l_InsideLoop;
  868. }
  869. goto l_ClippedLoop;
  870. }
  871. // We still have to process the last two vertices. They are already transformed
  872. if (dwTriIndex < dwNumPrimitives + 2)
  873. goto l_ProcessOnly;
  874. goto l_Exit;
  875. l_InsideLoop:
  876. d_TransformVertex(1, lpInpStart, m, x,y,z,w, pWeights, pMatrixIndices)
  877. d_ComputeClipCode(1)
  878. cv5->hx = x;
  879. cv5->hy = y;
  880. cv5->hz = z;
  881. cv5->hw = w;
  882. cv5->clip = 0;
  883. if (clip)
  884. goto l_ExitInsideLoop;
  885. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  886. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  887. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  888. l_InsideLoopProcessOnly:
  889. {
  890. // Because "primitiveCount" is now in sync with the transformed vertex
  891. // (not processed one as it should be), it is greater by 2 then the actual
  892. // primitive count
  893. primitiveCount++;
  894. w = D3DVAL(1)/cv3->hw;
  895. d_ComputeScreenCoordinatesNoOutput(2, cv3->hx, cv3->hy, cv3->hz, w, x,y,z)
  896. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  897. d_CopyToOutputVertex(2, lpOutVer)
  898. dwTriIndex++;
  899. cv3 = cv3->next;
  900. cv5 = cv5->next;
  901. d_UpdateInputPointers(2);
  902. if (dwTriIndex < dwNumPrimitives)
  903. {
  904. goto l_InsideLoop;
  905. }
  906. // We still have to process the last two vertices. They are already transformed
  907. if (dwTriIndex < dwNumPrimitives + 2)
  908. goto l_InsideLoopProcessOnly;
  909. }
  910. goto l_Exit;
  911. l_ExitInsideLoop:
  912. {
  913. // For the last transforem vertex (cv5) we computed only clip code
  914. // without guardband
  915. d_ComputeClipCodeGB(2)
  916. cv5->clip = clip;
  917. dwClipUnion |= clip;
  918. // We have to set status for the cv3 and cv4 vertices
  919. vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
  920. __TRIANGLE_INSIDE | __2_TRIANGLE_INSIDE;
  921. cv4 = cv3->next;
  922. goto l_ClippedLoop2;
  923. }
  924. l_Exit:
  925. if (primitiveCount > 0)
  926. {
  927. // Draw batched primitive
  928. if (bOddStrip)
  929. {
  930. // Draw first triangle as indexed triangle
  931. WORD indices[3] = {0, 2, 1};
  932. pv->dwIndexSize = 2;
  933. pv->lpvOut = startVertex;
  934. pv->pDDI->SetIndexedPrimParams(0, 0, 3, pv->pDDI->GetCurrentPrimBase());
  935. ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLELIST, indices, 3, 1);
  936. if (ret != D3D_OK)
  937. goto l_Exit;
  938. primitiveCount--;
  939. // Move to the next vertex
  940. pv->pDDI->SkipVertices(1);
  941. startVertex += pv->dwOutputSize;
  942. }
  943. DWORD dwVertexCount = primitiveCount+2;
  944. if (primitiveCount > 0)
  945. {
  946. ret = DRAW_PRIM(pv, D3DPT_TRIANGLESTRIP, startVertex,
  947. dwVertexCount, primitiveCount);
  948. if (ret != D3D_OK)
  949. goto l_Error;
  950. }
  951. else
  952. {
  953. pv->pDDI->SkipVertices(2);
  954. }
  955. }
  956. pv->dwClipUnion = dwClipUnion;
  957. pv->dwClipIntersection = dwClipIntersection;
  958. l_Error:
  959. return ret;
  960. }
  961. //---------------------------------------------------------------------
  962. // Clipping and lighting a non-indexed line list in one pass
  963. //
  964. HRESULT D3DFE_PVFUNCSI::ProcessLineList(D3DFE_PROCESSVERTICES *pv)
  965. {
  966. #ifdef DEBUG_PIPELINE
  967. if (g_DebugFlags & __DEBUG_ONEPASS)
  968. d_ProcessPrimitive(1)
  969. #endif
  970. if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
  971. d_ProcessPrimitive(1)
  972. pv->dwFirstClippedVertex = 0xFFFFFFFF;
  973. pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
  974. pv->pGeometryFuncs->ProcessVertices(pv);
  975. int primitiveCount = 0; // Number of triangles in the current unclipped part
  976. BYTE *startVertex = (BYTE*)pv->lpvOut;
  977. if (pv->dwFirstClippedVertex != 0xFFFFFFFF)
  978. {
  979. if (pv->dwFirstClippedVertex > 2)
  980. {
  981. // Compute number of unclipped primitives
  982. primitiveCount = pv->dwFirstClippedVertex >> 1;
  983. // Index of the first vertex to process
  984. DWORD dwStartVertexIndex = primitiveCount << 1;
  985. DWORD dwVertexCount = dwStartVertexIndex;
  986. // Compute new number of primitives to process
  987. pv->dwNumPrimitives = pv->dwNumPrimitives - primitiveCount;
  988. SetInputAndOutputPointers(pv, dwStartVertexIndex);
  989. }
  990. }
  991. else
  992. {
  993. pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
  994. if (pv->dwClipIntersection)
  995. return D3D_OK;
  996. return (DoDrawPrimitive(pv));
  997. }
  998. HRESULT ret = D3D_OK;
  999. D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
  1000. ClipVertex cv[2];
  1001. DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen;
  1002. LPD3DMATRIXI m = &pv->mCTM[0];
  1003. D3DLIGHTINGELEMENT EyeSpaceData;
  1004. d_Setup()
  1005. cv[0].next = &cv[1];
  1006. for (DWORD n = pv->dwNumPrimitives; n; n--)
  1007. {
  1008. ClipVertex *out = cv;
  1009. D3DVERTEX *lpInpVer = (D3DVERTEX*)in;
  1010. D3DVALUE *pWeights = inWeights;
  1011. BYTE* pMatrixIndices = inMatrixIndices;
  1012. // First we transform three vertices and compute the clip codes
  1013. dwClipUnion = 0;
  1014. dwClipIntersection = ~0;
  1015. for (DWORD i=2; i; i--)
  1016. {
  1017. DWORD clip = TransformVertexMakeClipCode(pv, lpInpVer, pWeights, pMatrixIndices, out);
  1018. out++;
  1019. dwClipUnion |= clip;
  1020. dwClipIntersection &= clip;
  1021. lpInpVer = (D3DVERTEX*)((BYTE*)lpInpVer + dwInpVerSize);
  1022. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  1023. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  1024. }
  1025. pv->dwClipUnion |= dwClipUnion;
  1026. pv->dwClipIntersection &= dwClipIntersection;
  1027. // Now we can check where the triangle is
  1028. if (!dwClipIntersection)
  1029. {
  1030. if (!(dwClipUnion & dwClipMaskOffScreen))
  1031. { // The line does not require clipping
  1032. ClipVertex *lpXfmVer = cv;
  1033. primitiveCount++;
  1034. for (DWORD i=2; i; i--)
  1035. {
  1036. ComputeScreenCoordinates(pv, lpXfmVer, (D3DVECTORH*)lpOutVer);
  1037. d_DoLightingAndFog(5, in, inNormal, inDiffuse, inSpecular, lpOutVer, inWeights, inMatrixIndices)
  1038. D3DVALUE *pOutTexture = (D3DVALUE*)((BYTE*)lpOutVer + pv->texOffsetOut);
  1039. d_CopyTextureCoordUpdateInputPointers(5, pOutTexture)
  1040. lpXfmVer = lpXfmVer->next;
  1041. lpOutVer = (D3DTLVERTEX*)((BYTE*)lpOutVer + dwOutVerSize);
  1042. }
  1043. }
  1044. else
  1045. { // The line requires clipping
  1046. if (primitiveCount)
  1047. { // first draw the ones that didn't need clipping
  1048. DWORD vertexCount = primitiveCount << 1;
  1049. ret = DRAW_PRIM(pv, D3DPT_LINELIST, startVertex,
  1050. vertexCount, primitiveCount);
  1051. startVertex = (BYTE*)lpOutVer;
  1052. if (ret)
  1053. goto l_Exit;
  1054. }
  1055. primitiveCount = 0;
  1056. ClipVertex *lpXfmVer = cv;
  1057. for (DWORD i=2; i; i--)
  1058. {
  1059. if ((lpXfmVer->clip & dwClipMaskOffScreen) == 0)
  1060. {
  1061. ComputeScreenCoordinates(pv, lpXfmVer, (D3DVECTORH*)&lpXfmVer->sx);
  1062. }
  1063. d_ComputeOutputColors(5, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  1064. if (pv->dwVIDOut & D3DFVF_DIFFUSE)
  1065. lpXfmVer->color = pv->lighting.outDiffuse;
  1066. if (pv->dwVIDOut & D3DFVF_SPECULAR)
  1067. lpXfmVer->specular = pv->lighting.outSpecular;
  1068. d_CopyTextureCoordUpdateInputPointers(5, lpXfmVer->tex)
  1069. lpXfmVer++;
  1070. }
  1071. ret = ClipLine(pv, &cv[0], &cv[1]);
  1072. if (ret != D3D_OK)
  1073. goto l_Exit;
  1074. }
  1075. }
  1076. else
  1077. { // Line is outside
  1078. // Update input pointers
  1079. d_UpdateInputPointers(3)
  1080. d_UpdateInputPointers(3)
  1081. }
  1082. }
  1083. // draw final batch, if any
  1084. if (primitiveCount)
  1085. {
  1086. DWORD dwVertexCount = primitiveCount << 1;
  1087. ret = DRAW_PRIM(pv, D3DPT_LINELIST, startVertex, dwVertexCount, primitiveCount);
  1088. }
  1089. l_Exit:
  1090. return ret;
  1091. }
  1092. //---------------------------------------------------------------------
  1093. // Clipping and lighting a non-indexed triangle line in one pass
  1094. //
  1095. // Vertices cv1 cv2 cv3
  1096. // Next to Next to
  1097. // process transform
  1098. // | | |
  1099. // * * * * * * *
  1100. //
  1101. HRESULT D3DFE_PVFUNCSI::ProcessLineStrip(D3DFE_PROCESSVERTICES *pv)
  1102. {
  1103. #ifdef DEBUG_PIPELINE
  1104. if (g_DebugFlags & __DEBUG_ONEPASS)
  1105. d_ProcessPrimitive(1)
  1106. #endif
  1107. if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
  1108. d_ProcessPrimitive(1)
  1109. int primitiveCount; // Number of triangles in the current unclipped part
  1110. DWORD dwTriIndex; // Index of the current triangle in the primitive
  1111. // Start vertex for the current unclipped part of the triangle strip
  1112. BYTE *startVertex = (BYTE*)pv->lpvOut;
  1113. // Vertex flags has 5 bits per vertex
  1114. // Bits 0 - 4 - vertex cv2
  1115. // Bits 5 - 9 - vertex cv3
  1116. DWORD vf = 0;
  1117. D3DLIGHTINGELEMENT EyeSpaceData;
  1118. pv->dwFirstClippedVertex = 0xFFFFFFFF;
  1119. pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
  1120. pv->pGeometryFuncs->ProcessVertices(pv);
  1121. if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
  1122. {
  1123. pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
  1124. if (pv->dwClipIntersection)
  1125. return D3D_OK;
  1126. return (DoDrawPrimitive(pv));
  1127. }
  1128. else
  1129. {
  1130. primitiveCount = 0;
  1131. dwTriIndex = 0;
  1132. if (pv->dwFirstClippedVertex > 2)
  1133. {
  1134. DWORD dwStartVertexIndex = pv->dwFirstClippedVertex - 1;
  1135. primitiveCount = dwStartVertexIndex - 1;
  1136. dwTriIndex = dwStartVertexIndex;
  1137. // We have to set status for the cv2 vertex
  1138. vf |= __VERTEX_IN_INSIDETRIANGLE | __TRIANGLE_INSIDE;
  1139. SetInputAndOutputPointers(pv, dwStartVertexIndex);
  1140. }
  1141. }
  1142. HRESULT ret = D3D_OK;
  1143. // Current pointer to the output vertex buffer
  1144. D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
  1145. ClipVertex *cv1; // First vertex of delayed clipped line
  1146. ClipVertex *cv2; // Vertex to process
  1147. ClipVertex *cv3; // Vertex to transform
  1148. D3DVERTEX *lpInpStart; // Next input vertex to transform
  1149. D3DVALUE *pWeights; // Vertex weights. Should be in ssync with lpInpStart
  1150. BYTE *pMatrixIndices; // Vertex weights. Should be in ssync with lpInpStart
  1151. DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
  1152. LPD3DMATRIXI m = &pv->mCTM[0];
  1153. DWORD dwNumPrimitives = pv->dwNumPrimitives;
  1154. DWORD i;
  1155. d_Setup()
  1156. lpInpStart = (D3DVERTEX*)in;
  1157. pWeights = (D3DVALUE*)inWeights;
  1158. pMatrixIndices = (BYTE*)inMatrixIndices;
  1159. cv1 = NULL;
  1160. cv2 = pv->clipVer;
  1161. cv3 = pv->clipVer;
  1162. {
  1163. // Transform first vertex and copy it to the clip buffer
  1164. DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv3);
  1165. dwClipUnion |= clip;
  1166. dwClipIntersection &= clip;
  1167. cv3 = cv3->next;
  1168. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  1169. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  1170. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  1171. }
  1172. dwClipUnion |= cv2->clip;
  1173. dwClipIntersection &= cv2->clip;
  1174. float x,y,z,w;
  1175. int clip;
  1176. if (pv->dwFirstClippedVertex > 2)
  1177. {
  1178. // Force clip code to be zero to fix potential PSGP precision problem
  1179. cv2->clip = 0;
  1180. dwClipIntersection = 0;
  1181. goto l_InsideLoop;
  1182. }
  1183. l_ClippedLoop:
  1184. clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv3);
  1185. dwClipUnion |= clip;
  1186. dwClipIntersection &= clip;
  1187. l_ClippedLoop2:
  1188. // Set status for cv2, cv3 vertices based on their clip codes
  1189. if (!(cv2->clip & cv3->clip))
  1190. {
  1191. if (!((cv2->clip | cv3->clip) & dwClipMaskOffScreen))
  1192. vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
  1193. __2_TRIANGLE_INSIDE;
  1194. else
  1195. vf |= __VERTEX_IN_CLIPTRIANGLE | __2_VERTEX_IN_CLIPTRIANGLE |
  1196. __2_TRIANGLE_CLIP;
  1197. }
  1198. else
  1199. vf |= __2_TRIANGLE_OUTSIDE;
  1200. l_ProcessOnly:
  1201. // When we process a vertex, its status is completely defined
  1202. if ((cv2->clip & pv->dwClipMaskOffScreen) == 0)
  1203. { // vertex is inside the guardband or frustum
  1204. // Compute screen coordinates
  1205. w = D3DVAL(1)/cv2->hw;
  1206. d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
  1207. }
  1208. if (vf & (__VERTEX_IN_INSIDETRIANGLE | __VERTEX_IN_CLIPTRIANGLE))
  1209. {
  1210. // Compute colors
  1211. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  1212. }
  1213. if (vf & __VERTEX_IN_INSIDETRIANGLE)
  1214. {
  1215. d_CopyToOutputVertex(2, lpOutVer)
  1216. }
  1217. if (vf & __VERTEX_IN_CLIPTRIANGLE)
  1218. {
  1219. d_CopyToClipVertex(2, cv2)
  1220. }
  1221. if (vf & __TRIANGLE_INSIDE)
  1222. {
  1223. primitiveCount++;
  1224. }
  1225. else
  1226. {
  1227. if (primitiveCount > 0)
  1228. {
  1229. // Draw batched primitive
  1230. DWORD dwVerCount = primitiveCount+1;
  1231. ret = DRAW_PRIM(pv, D3DPT_LINESTRIP, startVertex, dwVerCount, primitiveCount);
  1232. if (ret != D3D_OK)
  1233. goto l_Exit;
  1234. // Prepare for the next part of the primitive
  1235. startVertex += dwVerCount * pv->dwOutputSize;
  1236. primitiveCount = 0;
  1237. }
  1238. if (vf & __TRIANGLE_CLIP)
  1239. { // The line requires clipping
  1240. // Clip prev triangle - cv1, cv2
  1241. HRESULT ret;
  1242. ret = ClipLine(pv, cv1, cv2);
  1243. if (ret != D3D_OK)
  1244. goto l_Exit;
  1245. }
  1246. }
  1247. d_UpdateInputPointers(1);
  1248. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  1249. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  1250. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  1251. cv1 = cv2;
  1252. cv2 = cv3;
  1253. cv3 = cv3->next;
  1254. dwTriIndex++;
  1255. vf >>= 5;
  1256. if (dwTriIndex < dwNumPrimitives)
  1257. {
  1258. if (dwClipUnion == 0 && primitiveCount == 1)
  1259. {
  1260. // If all vertices are inside the frustum we use the optimized loop
  1261. goto l_InsideLoop;
  1262. }
  1263. goto l_ClippedLoop;
  1264. }
  1265. // We still have to process one last vertex. It is already transformed
  1266. if (dwTriIndex < dwNumPrimitives + 1)
  1267. goto l_ProcessOnly;
  1268. goto l_Exit;
  1269. l_InsideLoop:
  1270. d_TransformVertex(1, lpInpStart, m, x,y,z,w, pWeights, pMatrixIndices)
  1271. d_ComputeClipCode(1)
  1272. cv3->hx = x;
  1273. cv3->hy = y;
  1274. cv3->hz = z;
  1275. cv3->hw = w;
  1276. cv3->clip = 0;
  1277. if (clip)
  1278. goto l_ExitInsideLoop;
  1279. lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
  1280. pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
  1281. pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
  1282. l_InsideLoopProcessOnly:
  1283. {
  1284. // Because "primitiveCount" is now in sync with the transformed vertex
  1285. // (not processed one as it should be), it is greater by 1 then the actual
  1286. // primitive count
  1287. primitiveCount++;
  1288. w = D3DVAL(1)/cv2->hw;
  1289. d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
  1290. d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
  1291. d_CopyToOutputVertex(2, lpOutVer)
  1292. dwTriIndex++;
  1293. cv2 = cv2->next;
  1294. cv3 = cv3->next;
  1295. d_UpdateInputPointers(2);
  1296. if (dwTriIndex < dwNumPrimitives)
  1297. {
  1298. goto l_InsideLoop;
  1299. }
  1300. // We still have to process one last two vertex. It is already transformed
  1301. if (dwTriIndex < dwNumPrimitives + 1)
  1302. goto l_InsideLoopProcessOnly;
  1303. }
  1304. goto l_Exit;
  1305. l_ExitInsideLoop:
  1306. {
  1307. // For the last transforem vertex (cv3) we computed only clip code
  1308. // without guardband
  1309. d_ComputeClipCodeGB(2)
  1310. cv3->clip = clip;
  1311. dwClipUnion |= clip;
  1312. // We have to set status for the cv3 and cv4 vertices
  1313. vf |= __VERTEX_IN_INSIDETRIANGLE | __TRIANGLE_INSIDE ;
  1314. goto l_ClippedLoop2;
  1315. }
  1316. l_Exit:
  1317. if (primitiveCount > 0)
  1318. {
  1319. // Draw batched primitive
  1320. DWORD dwVertexCount = primitiveCount+1;
  1321. ret = DRAW_PRIM(pv, D3DPT_LINESTRIP, startVertex, dwVertexCount, primitiveCount);
  1322. }
  1323. pv->dwClipUnion = dwClipUnion;
  1324. pv->dwClipIntersection = dwClipIntersection;
  1325. return ret;
  1326. }