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.

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