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.

1662 lines
58 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dphal.c
  6. * Content: DrawPrimitive implementation for DrawPrimitive HALs
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. #include "drawprim.hpp"
  12. #include "clipfunc.h"
  13. #include "d3dfei.h"
  14. extern const DWORD LOWVERTICESNUMBER = 20;
  15. #if DBG
  16. extern DWORD FaceCount;
  17. DWORD FaceCount = 0;
  18. DWORD StartFace = 0;
  19. DWORD EndFace = 10000;
  20. #endif
  21. extern void SetDebugRenderState(DWORD value);
  22. #define ALIGN32(x) x = ((DWORD)(x + 31)) & (~31);
  23. //---------------------------------------------------------------------
  24. // Array to map D3DVERTEXTYPE to FVF vertex type
  25. //
  26. DWORD d3dVertexToFVF[4] =
  27. {
  28. 0,
  29. D3DFVF_VERTEX,
  30. D3DFVF_LVERTEX,
  31. D3DFVF_TLVERTEX
  32. };
  33. //---------------------------------------------------------------------
  34. // Handles strides and FVF
  35. //
  36. #undef DPF_MODNAME
  37. #define DPF_MODNAME "D3DFE_updateExtents"
  38. void D3DFE_updateExtents(LPDIRECT3DDEVICEI lpDevI)
  39. {
  40. int i;
  41. D3DVECTOR *v = (D3DVECTOR*)lpDevI->position.lpvData;
  42. DWORD stride = lpDevI->position.dwStride;
  43. for (i = lpDevI->dwNumVertices; i; i--)
  44. {
  45. if (v->x < lpDevI->rExtents.x1)
  46. lpDevI->rExtents.x1 = v->x;
  47. if (v->x > lpDevI->rExtents.x2)
  48. lpDevI->rExtents.x2 = v->x;
  49. if (v->y < lpDevI->rExtents.y1)
  50. lpDevI->rExtents.y1 = v->y;
  51. if (v->y > lpDevI->rExtents.y2)
  52. lpDevI->rExtents.y2 = v->y;
  53. v = (D3DVECTOR*)((char*)v + stride);
  54. }
  55. }
  56. //---------------------------------------------------------------------
  57. #undef DPF_MODNAME
  58. #define DPF_MODNAME "MapFVFtoTLVertex1"
  59. inline void MapFVFtoTLVertex1(LPDIRECT3DDEVICEI lpDevI, D3DTLVERTEX *pOut,
  60. DWORD *pIn)
  61. {
  62. // Copy position
  63. pOut->sx = *(D3DVALUE*)pIn++;
  64. pOut->sy = *(D3DVALUE*)pIn++;
  65. pOut->sz = *(D3DVALUE*)pIn++;
  66. pOut->rhw = *(D3DVALUE*)pIn++;
  67. // Other fields: diffuse, specular, texture
  68. if (lpDevI->dwVIDOut & D3DFVF_DIFFUSE)
  69. pOut->color = *pIn++;
  70. else
  71. {
  72. pOut->color = __DEFAULT_DIFFUSE;
  73. }
  74. if (lpDevI->dwVIDOut & D3DFVF_SPECULAR)
  75. pOut->specular = *pIn++;
  76. else
  77. {
  78. pOut->specular= __DEFAULT_SPECULAR;
  79. }
  80. if (lpDevI->nTexCoord)
  81. {
  82. pIn = &pIn[lpDevI->dwTextureIndexToCopy << 1];
  83. pOut->tu = *(D3DVALUE*)&pIn[0];
  84. pOut->tv = *(D3DVALUE*)&pIn[1];
  85. }
  86. else
  87. {
  88. pOut->tu = 0;
  89. pOut->tv = 0;
  90. }
  91. }
  92. //---------------------------------------------------------------------
  93. // All vertices from lpDevI->lpVout are copied to the output buffer, expanding
  94. // to D3DTLVERTEX.
  95. // The output buffer is lpAddress if it is not NULL, otherwise it is TLVbuf
  96. //
  97. #undef DPF_MODNAME
  98. #define DPF_MODNAME "MapFVFtoTLVertex"
  99. HRESULT MapFVFtoTLVertex(LPDIRECT3DDEVICEI lpDevI, LPVOID lpAddress)
  100. {
  101. int i;
  102. DWORD size = lpDevI->dwNumVertices * sizeof(D3DTLVERTEX);
  103. D3DTLVERTEX *pOut;
  104. if (lpAddress)
  105. pOut = (D3DTLVERTEX*)lpAddress;
  106. else
  107. {
  108. // See if TL buffer has sufficient space
  109. if (size > lpDevI->TLVbuf.GetSize())
  110. {
  111. if (lpDevI->TLVbuf.Grow(lpDevI, size) != D3D_OK)
  112. {
  113. D3D_ERR( "Could not grow TL vertex buffer" );
  114. return DDERR_OUTOFMEMORY;
  115. }
  116. }
  117. pOut = (D3DTLVERTEX*)lpDevI->TLVbuf.GetAddress();
  118. }
  119. // Map vertices
  120. DWORD *pIn = (DWORD*)lpDevI->lpvOut;
  121. for (i=lpDevI->dwNumVertices; i; i--)
  122. {
  123. MapFVFtoTLVertex1(lpDevI, pOut, pIn);
  124. pOut++;
  125. pIn = (DWORD*)((char*)pIn + lpDevI->dwOutputSize);
  126. }
  127. return D3D_OK;
  128. }
  129. //---------------------------------------------------------------------
  130. #undef DPF_MODNAME
  131. #define DPF_MODNAME "CheckDrawPrimitive"
  132. HRESULT CheckDrawPrimitive(LPDIRECT3DDEVICEI lpDevI)
  133. {
  134. D3DFE_PROCESSVERTICES* data = lpDevI;
  135. HRESULT ret = CheckDeviceSettings(lpDevI);
  136. if (ret != D3D_OK)
  137. return ret;
  138. if (!data->dwNumVertices)
  139. {
  140. D3D_ERR( "Invalid dwNumVertices in DrawPrimitive" );
  141. return DDERR_INVALIDPARAMS;
  142. }
  143. if(data->position.lpvData==NULL) {
  144. D3D_ERR( "Invalid lpvVertices param in DrawPrimitive" );
  145. return DDERR_INVALIDPARAMS;
  146. }
  147. switch (data->primType)
  148. {
  149. case D3DPT_POINTLIST:
  150. break;
  151. case D3DPT_LINELIST:
  152. if (data->dwNumVertices & 1)
  153. {
  154. D3D_ERR( "DrawPrimitive: bad vertex count" );
  155. return DDERR_INVALIDPARAMS;
  156. }
  157. break;
  158. case D3DPT_LINESTRIP:
  159. if (data->dwNumVertices == 1)
  160. {
  161. D3D_ERR( "DrawPrimitive: bad vertex count" );
  162. return DDERR_INVALIDPARAMS;
  163. }
  164. break;
  165. case D3DPT_TRIANGLEFAN:
  166. case D3DPT_TRIANGLESTRIP:
  167. if (data->dwNumVertices < 3)
  168. {
  169. D3D_ERR( "DrawPrimitive: bad vertex count" );
  170. return DDERR_INVALIDPARAMS;
  171. }
  172. break;
  173. case D3DPT_TRIANGLELIST:
  174. if ( (data->dwNumVertices % 3) != 0 )
  175. {
  176. D3D_ERR( "DrawPrimitive: bad vertex count" );
  177. return DDERR_INVALIDPARAMS;
  178. }
  179. break;
  180. default:
  181. D3D_ERR( "Unknown or unsupported primitive type requested of DrawPrimitive" );
  182. return D3DERR_INVALIDPRIMITIVETYPE;
  183. }
  184. return D3D_OK;
  185. }
  186. //---------------------------------------------------------------------
  187. #undef DPF_MODNAME
  188. #define DPF_MODNAME "CheckDrawIndexedPrimitive"
  189. HRESULT
  190. CheckDrawIndexedPrimitive(LPDIRECT3DDEVICEI lpDevI)
  191. {
  192. D3DFE_PROCESSVERTICES *data = lpDevI;
  193. DWORD i;
  194. HRESULT ret = CheckDeviceSettings(lpDevI);
  195. if (ret != D3D_OK)
  196. return ret;
  197. if (data->dwNumVertices <= 0 || data->dwNumIndices <= 0)
  198. {
  199. D3D_ERR( "Invalid dwNumVertices or dwNumIndices in DrawIndexedPrimitive" );
  200. return DDERR_INVALIDPARAMS;
  201. }
  202. if (data->dwNumVertices > 65535ul )
  203. {
  204. D3D_ERR( "DrawIndexedPrimitive vertex array > 64K" );
  205. return DDERR_INVALIDPARAMS;
  206. }
  207. if((data->lpwIndices==NULL) || IsBadReadPtr(data->lpwIndices,data->dwNumIndices*sizeof(WORD))) {
  208. D3D_ERR( "Invalid lpwIndices param in DrawIndexedPrimitive" );
  209. return DDERR_INVALIDPARAMS;
  210. }
  211. if(data->position.lpvData==NULL) {
  212. D3D_ERR( "Invalid lpvVertices param in DrawIndexedPrimitive" );
  213. return DDERR_INVALIDPARAMS;
  214. }
  215. switch (data->primType)
  216. {
  217. case D3DPT_LINELIST:
  218. if (data->dwNumIndices & 1)
  219. {
  220. D3D_ERR( "DrawIndexedPrimitive: bad index count" );
  221. return DDERR_INVALIDPARAMS;
  222. }
  223. break;
  224. case D3DPT_LINESTRIP:
  225. if (data->dwNumIndices == 1)
  226. {
  227. D3D_ERR( "DrawIndexedPrimitive: bad index count" );
  228. return DDERR_INVALIDPARAMS;
  229. }
  230. break;
  231. case D3DPT_TRIANGLEFAN:
  232. case D3DPT_TRIANGLESTRIP:
  233. if (data->dwNumIndices < 3)
  234. {
  235. D3D_ERR( "DrawIndexedPrimitive: bad index count" );
  236. return DDERR_INVALIDPARAMS;
  237. }
  238. break;
  239. case D3DPT_TRIANGLELIST:
  240. if ( (data->dwNumIndices % 3) != 0 )
  241. {
  242. D3D_ERR( "DrawIndexedPrimitive: bad index count" );
  243. return DDERR_INVALIDPARAMS;
  244. }
  245. break;
  246. default:
  247. D3D_ERR( "Unknown or unsupported primitive type requested of DrawIndexedPrimitive" );
  248. return D3DERR_INVALIDPRIMITIVETYPE;
  249. }
  250. for (i=0; i < data->dwNumIndices; i++)
  251. {
  252. if (data->lpwIndices[i] >= data->dwNumVertices)
  253. {
  254. D3D_ERR( "Invalid index value in DrawIndexedPrimitive" );
  255. return DDERR_INVALIDPARAMS;
  256. }
  257. }
  258. return D3D_OK;
  259. }
  260. //---------------------------------------------------------------------
  261. // Draws non-indexed primitives which do not require clipping
  262. //
  263. #undef DPF_MODNAME
  264. #define DPF_MODNAME "DrawPrim"
  265. #define __DRAWPRIMFUNC
  266. #include "dpgen.h"
  267. //---------------------------------------------------------------------
  268. // Draws indexed primitives which do not require clipping
  269. //
  270. #undef DPF_MODNAME
  271. #define DPF_MODNAME "DrawIndexedPrim"
  272. #define __DRAWPRIMFUNC
  273. #define __DRAWPRIMINDEX
  274. #include "dpgen.h"
  275. //---------------------------------------------------------------------
  276. #undef DPF_MODNAME
  277. #define DPF_MODNAME "FlushStatesDP"
  278. HRESULT
  279. CDirect3DDeviceIDP::FlushStates()
  280. {
  281. HRESULT dwRet=D3D_OK;
  282. FlushTextureFromDevice( this ); // delink all texture surfaces
  283. if (this->dwDPOffset>sizeof(D3DHAL_DRAWPRIMCOUNTS))
  284. {
  285. if ((dwRet=CheckSurfaces()) != D3D_OK)
  286. {
  287. this->dwDPOffset = sizeof(D3DHAL_DRAWPRIMCOUNTS);
  288. this->lpDPPrimCounts = (LPD3DHAL_DRAWPRIMCOUNTS)this->lpwDPBuffer;
  289. memset( (char *)this->lpwDPBuffer,0,sizeof(D3DHAL_DRAWPRIMCOUNTS)); //Clear header also
  290. if (dwRet == DDERR_SURFACELOST)
  291. {
  292. this->dwFEFlags |= D3DFE_LOSTSURFACES;
  293. return D3D_OK;
  294. }
  295. return dwRet;
  296. }
  297. D3DHAL_DRAWPRIMITIVESDATA dpData;
  298. DWORD dwDPOffset;
  299. if (this->lpDPPrimCounts->wNumVertices) //this->lpDPPrimCounts->wNumVertices==0 means the end
  300. { //force it if not
  301. memset(((LPBYTE)this->lpwDPBuffer+this->dwDPOffset),0,sizeof(D3DHAL_DRAWPRIMCOUNTS));
  302. }
  303. dpData.dwhContext = this->dwhContext;
  304. dpData.dwFlags = 0;
  305. dpData.lpvData = this->lpwDPBuffer;
  306. if (FVF_DRIVERSUPPORTED(this))
  307. dpData.dwFVFControl = this->dwCurrentBatchVID;
  308. else
  309. {
  310. if (this->dwDebugFlags & D3DDEBUG_DISABLEFVF)
  311. dpData.dwFVFControl = D3DFVF_TLVERTEX;
  312. else
  313. dpData.dwFVFControl = 0; //always zero for non-FVF drivers
  314. }
  315. dpData.ddrval = 0;
  316. dwDPOffset=this->dwDPOffset; //save it in case Flush returns prematurely
  317. #if 0
  318. if (D3DRENDERSTATE_TEXTUREHANDLE==*((DWORD*)this->lpwDPBuffer+2))
  319. DPF(0,"Flushing dwDPOffset=%08lx ddihandle=%08lx",dwDPOffset,*((DWORD*)this->lpwDPBuffer+3));
  320. #endif //0
  321. //we clear this to break re-entering as SW rasterizer needs to lock DDRAWSURFACE
  322. this->dwDPOffset = sizeof(D3DHAL_DRAWPRIMCOUNTS);
  323. // Spin waiting on the driver if wait requested
  324. #if _D3D_FORCEDOUBLE
  325. CD3DForceFPUDouble ForceFPUDouble(this);
  326. #endif //_D3D_FORCEDOUBLE
  327. do {
  328. #ifndef WIN95
  329. if((dwRet = CheckContextSurface(this)) != D3D_OK)
  330. {
  331. this->dwDPOffset = dwDPOffset;
  332. return (dwRet);
  333. }
  334. #endif //WIN95
  335. CALL_HAL2ONLY(dwRet, this, DrawPrimitives, &dpData);
  336. if (dwRet != DDHAL_DRIVER_HANDLED)
  337. {
  338. D3D_ERR ( "Driver call for DrawOnePrimitive failed" );
  339. // Need sensible return value in this case,
  340. // currently we return whatever the driver stuck in here.
  341. }
  342. } while (dpData.ddrval == DDERR_WASSTILLDRAWING);
  343. this->lpDPPrimCounts = (LPD3DHAL_DRAWPRIMCOUNTS)this->lpwDPBuffer;
  344. memset( (char *)this->lpwDPBuffer,0,sizeof(D3DHAL_DRAWPRIMCOUNTS)); //Clear header also
  345. dwRet= dpData.ddrval;
  346. this->dwCurrentBatchVID = this->dwVIDOut;
  347. }
  348. return dwRet;
  349. }
  350. //---------------------------------------------------------------------
  351. #undef DPF_MODNAME
  352. #define DPF_MODNAME "DoDrawPrimitive"
  353. HRESULT DoDrawPrimitive(LPD3DFE_PROCESSVERTICES pv)
  354. {
  355. HRESULT ret;
  356. if (!CheckIfNeedClipping(pv))
  357. return pv->DrawPrim();
  358. // Preserve primitive type for large begin-end primitives
  359. // Primitive type could be changed by the clipper
  360. D3DPRIMITIVETYPE oldPrimType = pv->primType;
  361. switch (pv->primType)
  362. {
  363. case D3DPT_POINTLIST:
  364. ret = ProcessClippedPoints(pv);
  365. break;
  366. case D3DPT_LINELIST:
  367. ret = ProcessClippedLine(pv);
  368. break;
  369. case D3DPT_LINESTRIP:
  370. ret = ProcessClippedLine(pv);
  371. break;
  372. case D3DPT_TRIANGLELIST:
  373. ret = ProcessClippedTriangleList(pv);
  374. break;
  375. case D3DPT_TRIANGLESTRIP:
  376. ret = ProcessClippedTriangleStrip(pv);
  377. break;
  378. case D3DPT_TRIANGLEFAN:
  379. ret = ProcessClippedTriangleFan(pv);
  380. break;
  381. default:
  382. ret = DDERR_GENERIC;
  383. break;
  384. }
  385. ClampExtents(pv);
  386. pv->primType = oldPrimType;
  387. return ret;
  388. }
  389. //---------------------------------------------------------------------
  390. #undef DPF_MODNAME
  391. #define DPF_MODNAME "DoDrawIndexedPrimitive"
  392. HRESULT DoDrawIndexedPrimitive(LPD3DFE_PROCESSVERTICES pv)
  393. {
  394. HRESULT ret;
  395. if (!CheckIfNeedClipping(pv))
  396. return pv->DrawIndexPrim();
  397. // Preserve primitive type for large begin-end primitives
  398. // Primitive type could be changed by the clipper
  399. D3DPRIMITIVETYPE oldPrimType = pv->primType;
  400. switch (pv->primType)
  401. {
  402. case D3DPT_LINELIST:
  403. ret = ProcessClippedIndexedLine(pv);
  404. break;
  405. case D3DPT_LINESTRIP:
  406. ret = ProcessClippedIndexedLine(pv);
  407. break;
  408. case D3DPT_TRIANGLELIST:
  409. ret = ProcessClippedIndexedTriangleList(pv);
  410. break;
  411. case D3DPT_TRIANGLEFAN:
  412. ret = ProcessClippedIndexedTriangleFan(pv);
  413. break;
  414. case D3DPT_TRIANGLESTRIP:
  415. ret = ProcessClippedIndexedTriangleStrip(pv);
  416. break;
  417. default:
  418. break;
  419. }
  420. ClampExtents(pv);
  421. pv->primType = oldPrimType;
  422. return ret;
  423. }
  424. //---------------------------------------------------------------------
  425. // ProcessPrimitive processes indexed, non-indexed primitives or
  426. // vertices only as defined by "op"
  427. //
  428. // op = __PROCPRIMOP_NONINDEXEDPRIM by default
  429. //
  430. HRESULT DIRECT3DDEVICEI::ProcessPrimitive(__PROCPRIMOP op)
  431. {
  432. HRESULT ret=D3D_OK;
  433. DWORD vertexPoolSize;
  434. // Update vertex stats
  435. this->D3DStats.dwVerticesProcessed += this->dwNumVertices;
  436. DWORD dwCurrPrimVertices = this->dwNumVertices;
  437. // Need to call UpdateTextures()
  438. this->dwFEFlags |= D3DFE_NEED_TEXTURE_UPDATE;
  439. // Viewport ID could be different from Device->v_id, because during Execute call
  440. // Device->v_id is changed to whatever viewport is used as a parameter.
  441. // So we have to make sure that we use the right viewport.
  442. //
  443. LPDIRECT3DVIEWPORTI lpView = this->lpCurrentViewport;
  444. if (this->v_id != lpView->v_id)
  445. {
  446. HRESULT ret = downloadView(lpView);
  447. if (ret != D3D_OK)
  448. return ret;
  449. }
  450. // We need to grow TL vertex buffer if
  451. // 1. We have to transform vertices
  452. // 2. We do not have to transform vertices and
  453. // 2.1 Ramp mode is used, because we have to change vertex colors
  454. // 2.2 DP2HAL is used and we have small number of vertices, so we need to
  455. // copy vertices into TL buffer
  456. //
  457. vertexPoolSize = this->dwNumVertices * this->dwOutputSize;
  458. if ((!FVF_TRANSFORMED(this->dwVIDIn)) ||
  459. (this->dwDeviceFlags & D3DDEV_RAMP))
  460. {
  461. if (vertexPoolSize > this->TLVbuf.GetSize())
  462. {
  463. if (this->TLVbuf.Grow(this, vertexPoolSize) != D3D_OK)
  464. {
  465. D3D_ERR( "Could not grow TL vertex buffer" );
  466. ret = DDERR_OUTOFMEMORY;
  467. return ret;
  468. }
  469. }
  470. if (IS_DP2HAL_DEVICE(this))
  471. {
  472. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  473. ret = dev->StartPrimVB(this->TLVbuf.GetVBI(), 0);
  474. if (ret != D3D_OK)
  475. return ret;
  476. }
  477. this->lpvOut = this->TLVbuf.GetAddress();
  478. }
  479. // Grow clip flags buffer if we need clipping
  480. //
  481. if (!(this->dwFlags & D3DDP_DONOTCLIP))
  482. {
  483. DWORD size = this->dwNumVertices * sizeof(D3DFE_CLIPCODE);
  484. if (size > this->HVbuf.GetSize())
  485. {
  486. if (this->HVbuf.Grow(size) != D3D_OK)
  487. {
  488. D3D_ERR( "Could not grow clip buffer" );
  489. ret = DDERR_OUTOFMEMORY;
  490. return ret;
  491. }
  492. }
  493. this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
  494. }
  495. if (FVF_TRANSFORMED(this->dwVIDIn))
  496. {
  497. if (this->dwDeviceFlags & D3DDEV_RAMP)
  498. {
  499. ConvertColorsToRamp(this,
  500. (D3DTLVERTEX*)this->position.lpvData,
  501. (D3DTLVERTEX*)(this->lpvOut),
  502. this->dwNumVertices);
  503. }
  504. else
  505. {
  506. // Pass vertices directly from the user memory
  507. this->dwVIDOut = this->dwVIDIn;
  508. this->dwOutputSize = this->position.dwStride;
  509. this->lpvOut = this->position.lpvData;
  510. vertexPoolSize = this->dwNumVertices * this->dwOutputSize;
  511. if (IS_DP2HAL_DEVICE(this))
  512. {
  513. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  514. dev->StartPrimUserMem(this->position.lpvData);
  515. if (ret != D3D_OK)
  516. return ret;
  517. }
  518. }
  519. if (this->dwFlags & D3DDP_DONOTCLIP)
  520. {
  521. if (!(this->dwFlags & D3DDP_DONOTUPDATEEXTENTS))
  522. D3DFE_updateExtents(this);
  523. if (op == __PROCPRIMOP_INDEXEDPRIM)
  524. {
  525. ret = this->DrawIndexPrim();
  526. }
  527. else if (op == __PROCPRIMOP_NONINDEXEDPRIM)
  528. {
  529. ret = this->DrawPrim();
  530. }
  531. goto l_exit;
  532. }
  533. else
  534. {
  535. // Clear clip union and intersection flags
  536. this->dwClipIntersection = 0;
  537. this->dwClipUnion = 0;
  538. DWORD clip_intersect;
  539. clip_intersect = this->pGeometryFuncs->GenClipFlags(this);
  540. D3DFE_UpdateClipStatus(this);
  541. if (!clip_intersect)
  542. {
  543. this->dwFlags |= D3DPV_TLVCLIP;
  544. if (op == __PROCPRIMOP_INDEXEDPRIM)
  545. {
  546. ret = DoDrawIndexedPrimitive(this);
  547. }
  548. else if (op == __PROCPRIMOP_NONINDEXEDPRIM)
  549. {
  550. ret = DoDrawPrimitive(this);
  551. }
  552. goto l_exit;
  553. }
  554. }
  555. }
  556. else
  557. {
  558. // Clear clip union and intersection flags
  559. this->dwClipIntersection = 0;
  560. this->dwClipUnion = 0;
  561. // Update Lighting and related flags
  562. if ((ret = DoUpdateState(this)) != D3D_OK)
  563. return ret;
  564. // Call PSGP or our implementation
  565. if (op == __PROCPRIMOP_INDEXEDPRIM)
  566. ret = this->pGeometryFuncs->ProcessIndexedPrimitive(this);
  567. else if (op == __PROCPRIMOP_NONINDEXEDPRIM)
  568. ret = this->pGeometryFuncs->ProcessPrimitive(this);
  569. else
  570. ret = this->pGeometryFuncs->ProcessVertices(this);
  571. D3DFE_UpdateClipStatus(this);
  572. }
  573. l_exit:
  574. if (IS_DP2HAL_DEVICE(this))
  575. {
  576. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  577. if (op != __PROCPRIMOP_PROCVERONLY)
  578. ret = dev->EndPrim(vertexPoolSize);
  579. }
  580. return ret;
  581. }
  582. //---------------------------------------------------------------------
  583. // This function is called when a number of indices in an indexed primitive
  584. // is much less than a number of vertices. In this case we build non-indexed
  585. // primitives.
  586. HRESULT DereferenceIndexedPrim(LPDIRECT3DDEVICEI lpDevI)
  587. {
  588. HRESULT ret = CheckVertexBatch(lpDevI);
  589. if (ret != D3D_OK)
  590. return ret;
  591. // Save original vertice and number of primitives
  592. D3DVERTEX *lpvVertices = (D3DVERTEX*)lpDevI->position.lpvData;
  593. DWORD dwNumPrimitivesOrg = lpDevI->dwNumPrimitives;
  594. WORD *lpwIndices = lpDevI->lpwIndices;
  595. // We will dereference here
  596. D3DVERTEX *lpVertex = (D3DVERTEX*)lpDevI->lpvVertexBatch;
  597. lpDevI->position.lpvData = lpVertex;
  598. lpDevI->lpwIndices = NULL;
  599. switch (lpDevI->primType)
  600. {
  601. case D3DPT_LINELIST:
  602. {
  603. for (DWORD j=0; j < dwNumPrimitivesOrg; j += BEGIN_DATA_BLOCK_SIZE/2)
  604. {
  605. lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg - j,
  606. (BEGIN_DATA_BLOCK_SIZE/2));
  607. lpDevI->dwNumVertices = lpDevI->dwNumPrimitives << 1;
  608. D3DVERTEX *lpTmp = lpVertex;
  609. for (DWORD i=lpDevI->dwNumVertices; i; i--)
  610. {
  611. *lpTmp++ = lpvVertices[*lpwIndices++];
  612. }
  613. ret = lpDevI->ProcessPrimitive();
  614. if (ret != D3D_OK)
  615. return ret;
  616. }
  617. break;
  618. }
  619. case D3DPT_LINESTRIP:
  620. {
  621. for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE-1)
  622. {
  623. lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg-j,
  624. (BEGIN_DATA_BLOCK_SIZE-1));
  625. lpDevI->dwNumVertices = lpDevI->dwNumPrimitives + 1;
  626. D3DVERTEX *lpTmp = lpVertex;
  627. for (DWORD i=lpDevI->dwNumVertices; i; i--)
  628. {
  629. *lpTmp++ = lpvVertices[*lpwIndices++];
  630. }
  631. lpwIndices--; // back off one so the next batch is connected
  632. ret = lpDevI->ProcessPrimitive();
  633. if (ret != D3D_OK)
  634. return ret;
  635. }
  636. break;
  637. }
  638. case D3DPT_TRIANGLEFAN:
  639. {
  640. lpVertex[0] = lpvVertices[*lpwIndices++];
  641. for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE-2)
  642. {
  643. lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg - j,
  644. (BEGIN_DATA_BLOCK_SIZE-2));
  645. lpDevI->dwNumVertices = lpDevI->dwNumPrimitives + 2;
  646. D3DVERTEX *lpTmp = &lpVertex[1];
  647. for (DWORD i=lpDevI->dwNumVertices-1; i; i--)
  648. {
  649. *lpTmp++ = lpvVertices[*lpwIndices++];
  650. }
  651. lpwIndices--; // back off one so the next batch is connected
  652. ret = lpDevI->ProcessPrimitive();
  653. if (ret != D3D_OK)
  654. return ret;
  655. }
  656. break;
  657. }
  658. case D3DPT_TRIANGLESTRIP:
  659. {
  660. for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE-2)
  661. {
  662. lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg-j,
  663. (BEGIN_DATA_BLOCK_SIZE-2));
  664. lpDevI->dwNumVertices = lpDevI->dwNumPrimitives + 2;
  665. D3DVERTEX *lpTmp = lpVertex;
  666. for (DWORD i=lpDevI->dwNumVertices; i; i--)
  667. {
  668. *lpTmp++ = lpvVertices[*lpwIndices++];
  669. }
  670. lpwIndices-= 2; // back off so the next batch is connected
  671. ret = lpDevI->ProcessPrimitive();
  672. if (ret != D3D_OK)
  673. return ret;
  674. }
  675. break;
  676. }
  677. case D3DPT_TRIANGLELIST:
  678. {
  679. for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE/3)
  680. {
  681. lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg-j,
  682. (BEGIN_DATA_BLOCK_SIZE/3));
  683. lpDevI->dwNumVertices = lpDevI->dwNumPrimitives * 3;
  684. D3DVERTEX *lpTmp = lpVertex;
  685. for (DWORD i=lpDevI->dwNumVertices; i; i--)
  686. {
  687. *lpTmp++ = lpvVertices[*lpwIndices++];
  688. }
  689. ret = lpDevI->ProcessPrimitive();
  690. if (ret != D3D_OK)
  691. return ret;
  692. }
  693. break;
  694. }
  695. }
  696. return D3D_OK;
  697. }
  698. //---------------------------------------------------------------------
  699. // API calls
  700. //---------------------------------------------------------------------
  701. //---------------------------------------------------------------------
  702. #undef DPF_MODNAME
  703. #define DPF_MODNAME "DrawPrimitiveStrided"
  704. HRESULT D3DAPI
  705. DIRECT3DDEVICEI::DrawPrimitiveStrided(
  706. D3DPRIMITIVETYPE PrimitiveType,
  707. DWORD dwVertexType,
  708. LPD3DDRAWPRIMITIVESTRIDEDDATA lpDrawData,
  709. DWORD dwNumVertices,
  710. DWORD dwFlags)
  711. {
  712. HRESULT ret = D3D_OK;
  713. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  714. #if DBG
  715. if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
  716. return DDERR_INVALIDPARAMS;
  717. Profile(PROF_DRAWPRIMITIVESTRIDED,PrimitiveType,dwVertexType);
  718. #endif
  719. //note: this check should be done in retail as well as dbg build
  720. if((dwVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  721. return D3DERR_INVALIDVERTEXTYPE;
  722. this->primType = PrimitiveType;
  723. this->dwVIDIn = dwVertexType;
  724. this->position = lpDrawData->position;
  725. this->normal = lpDrawData->normal;
  726. this->diffuse = lpDrawData->diffuse;
  727. this->specular = lpDrawData->specular;
  728. ComputeOutputFVF(this);
  729. for (DWORD i=0; i < this->nTexCoord; i++)
  730. this->textures[i] = lpDrawData->textureCoords[i];
  731. this->dwNumVertices = dwNumVertices;
  732. this->lpwIndices = NULL;
  733. this->dwNumIndices = 0;
  734. this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress();
  735. this->dwFlags = dwFlags | D3DPV_STRIDE;
  736. if (this->dwVIDIn & D3DFVF_NORMAL)
  737. this->dwFlags |= D3DPV_LIGHTING;
  738. GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
  739. #if DBG
  740. if (this->dwNumVertices > MAX_DX6_VERTICES)
  741. {
  742. D3D_ERR("D3D for DX6 cannot handle greater than 64K vertices");
  743. return D3DERR_TOOMANYVERTICES;
  744. }
  745. ret = CheckDrawPrimitive(this);
  746. if (ret != D3D_OK)
  747. {
  748. return ret;
  749. }
  750. #endif
  751. return this->ProcessPrimitive();
  752. } // end of DrawPrimitiveStrided()
  753. //---------------------------------------------------------------------
  754. #undef DPF_MODNAME
  755. #define DPF_MODNAME "DrawIndexedPrimitiveStrided"
  756. HRESULT D3DAPI
  757. DIRECT3DDEVICEI::DrawIndexedPrimitiveStrided(
  758. D3DPRIMITIVETYPE PrimitiveType,
  759. DWORD dwVertexType,
  760. LPD3DDRAWPRIMITIVESTRIDEDDATA lpDrawData,
  761. DWORD dwNumVertices,
  762. LPWORD lpwIndices,
  763. DWORD dwNumIndices,
  764. DWORD dwFlags)
  765. {
  766. HRESULT ret = D3D_OK;
  767. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  768. #if DBG
  769. if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
  770. return DDERR_INVALIDPARAMS;
  771. Profile(PROF_DRAWINDEXEDPRIMITIVESTRIDED,PrimitiveType,dwVertexType);
  772. #endif
  773. //note: this check should be done in retail as well as dbg build
  774. if((dwVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  775. return D3DERR_INVALIDVERTEXTYPE;
  776. this->primType = PrimitiveType;
  777. this->dwVIDIn = dwVertexType;
  778. this->position = lpDrawData->position;
  779. this->normal = lpDrawData->normal;
  780. this->diffuse = lpDrawData->diffuse;
  781. this->specular = lpDrawData->specular;
  782. ComputeOutputFVF(this);
  783. for (DWORD i=0; i < this->nTexCoord; i++)
  784. this->textures[i] = lpDrawData->textureCoords[i];
  785. this->dwNumVertices = dwNumVertices;
  786. this->lpwIndices = lpwIndices;
  787. this->dwNumIndices = dwNumIndices;
  788. this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress();
  789. this->dwFlags = dwFlags | D3DPV_STRIDE;
  790. if (this->dwVIDIn & D3DFVF_NORMAL)
  791. this->dwFlags |= D3DPV_LIGHTING;
  792. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
  793. #if DBG
  794. if (this->dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  795. {
  796. D3D_ERR("D3D for DX6 cannot handle greater than 64K sized primitives");
  797. return D3DERR_TOOMANYPRIMITIVES;
  798. }
  799. ret = CheckDrawIndexedPrimitive(this);
  800. if (ret != D3D_OK)
  801. {
  802. return ret;
  803. }
  804. if (this->dwNumIndices * INDEX_BATCH_SCALE < this->dwNumVertices &&
  805. !FVF_TRANSFORMED(this->dwVIDIn))
  806. {
  807. D3D_WARN(1, "The number of indices is much less than the number of vertices.");
  808. D3D_WARN(1, "This will likely be inefficient. Consider using vertex buffers.");
  809. }
  810. #endif
  811. return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  812. } // end of DrawIndexedPrimitiveStrided()
  813. //---------------------------------------------------------------------
  814. #undef DPF_MODNAME
  815. #define DPF_MODNAME "DrawPrimitive3"
  816. HRESULT D3DAPI
  817. DIRECT3DDEVICEI::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,
  818. DWORD dwVertexType,
  819. LPVOID lpvVertices,
  820. DWORD dwNumVertices,
  821. DWORD dwFlags)
  822. {
  823. HRESULT ret = D3D_OK;
  824. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  825. #if DBG
  826. if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
  827. return DDERR_INVALIDPARAMS;
  828. Profile(PROF_DRAWPRIMITIVEDEVICE3,PrimitiveType,dwVertexType);
  829. #endif
  830. /* This stuff does not change from call to call */
  831. this->lpwIndices = NULL;
  832. this->dwNumIndices = 0;
  833. this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress();
  834. /* This stuff is mandatory for the call */
  835. this->primType = PrimitiveType;
  836. this->dwVIDIn = dwVertexType;
  837. this->position.lpvData = lpvVertices;
  838. this->dwNumVertices = dwNumVertices;
  839. this->dwFlags = dwFlags;
  840. /* This stuff depends upon the vertex type */
  841. this->position.dwStride = GetVertexSizeFVF(this->dwVIDIn);
  842. if (this->dwVIDIn & D3DFVF_NORMAL)
  843. this->dwFlags |= D3DPV_LIGHTING;
  844. ComputeOutputFVF(this);
  845. GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
  846. #if DBG
  847. if (this->dwNumVertices > MAX_DX6_VERTICES)
  848. {
  849. D3D_ERR("D3D for DX6 cannot handle greater than 64K vertices");
  850. return D3DERR_TOOMANYVERTICES;
  851. }
  852. ret = CheckDrawPrimitive(this);
  853. if (ret != D3D_OK)
  854. {
  855. return ret;
  856. }
  857. #endif
  858. return this->ProcessPrimitive();
  859. }
  860. //---------------------------------------------------------------------
  861. #undef DPF_MODNAME
  862. #define DPF_MODNAME "Direct3DDevice::DrawIndexedPrimitive"
  863. HRESULT D3DAPI
  864. DIRECT3DDEVICEI::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType,
  865. DWORD dwVertexType,
  866. LPVOID lpvVertices, DWORD dwNumVertices,
  867. LPWORD lpwIndices, DWORD dwNumIndices,
  868. DWORD dwFlags)
  869. {
  870. HRESULT ret = D3D_OK;
  871. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  872. #if DBG
  873. if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
  874. return DDERR_INVALIDPARAMS;
  875. Profile(PROF_DRAWINDEXEDPRIMITIVEDEVICE3,PrimitiveType,dwVertexType);
  876. #endif
  877. // Static part
  878. this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress();
  879. // Mandatory part
  880. this->primType = PrimitiveType;
  881. this->dwVIDIn = dwVertexType;
  882. this->dwNumVertices = dwNumVertices;
  883. this->lpwIndices = lpwIndices;
  884. this->dwNumIndices = dwNumIndices;
  885. this->dwFlags = dwFlags;
  886. this->position.lpvData = lpvVertices;
  887. // Stuff that depends upon dwVIDIn
  888. this->position.dwStride = GetVertexSizeFVF(this->dwVIDIn);
  889. if (this->dwVIDIn & D3DFVF_NORMAL)
  890. this->dwFlags |= D3DPV_LIGHTING;
  891. ComputeOutputFVF(this);
  892. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
  893. #if DBG
  894. if (this->dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  895. {
  896. D3D_ERR("D3D for DX6 cannot handle greater than 64K sized primitives");
  897. return D3DERR_TOOMANYPRIMITIVES;
  898. }
  899. ret = CheckDrawIndexedPrimitive(this);
  900. if (ret != D3D_OK)
  901. {
  902. return ret;
  903. }
  904. if (this->dwNumIndices * INDEX_BATCH_SCALE < this->dwNumVertices &&
  905. !FVF_TRANSFORMED(this->dwVIDIn))
  906. {
  907. D3D_WARN(1, "The number of indices is much less than the number of vertices.");
  908. D3D_WARN(1, "This will likely be inefficient. Consider using vertex buffers.");
  909. }
  910. #endif
  911. return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  912. }
  913. //---------------------------------------------------------------------
  914. #undef DPF_MODNAME
  915. #define DPF_MODNAME "DrawPrimitive"
  916. HRESULT D3DAPI
  917. DIRECT3DDEVICEI::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,
  918. D3DVERTEXTYPE VertexType,
  919. LPVOID lpvVertices, DWORD dwNumVertices, DWORD dwFlags)
  920. {
  921. HRESULT ret = D3D_OK;
  922. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  923. #if DBG
  924. if (!IsDPFlagsValid(dwFlags))
  925. return DDERR_INVALIDPARAMS;
  926. if((VertexType<=0) || (VertexType>D3DVT_TLVERTEX)) {
  927. D3D_ERR("Invalid VertexType");
  928. return D3DERR_INVALIDVERTEXTYPE;
  929. }
  930. Profile(PROF_DRAWPRIMITIVEDEVICE2,PrimitiveType,VertexType);
  931. #endif
  932. /* Static assignments */
  933. this->position.dwStride = sizeof(D3DVERTEX);
  934. this->lpwIndices = NULL;
  935. this->dwNumIndices = 0;
  936. this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress();
  937. this->nTexCoord = 1;
  938. /* Necessary work */
  939. this->primType = PrimitiveType;
  940. this->dwNumVertices = dwNumVertices;
  941. this->dwFlags = dwFlags;
  942. this->position.lpvData = lpvVertices;
  943. this->dwVIDIn = d3dVertexToFVF[VertexType];
  944. DWORD dwVertexSize = sizeof(D3DVERTEX);
  945. ComputeOutputFVF(this);
  946. if (this->dwVIDIn & D3DFVF_NORMAL)
  947. this->dwFlags |= D3DPV_LIGHTING;
  948. // AnanKan (6/22/98)
  949. // !! This is a hack for the crippled DP2 driver model which cannot accept
  950. // !! more that 64K vertices. In DX6 interfaces we fail rendering if we
  951. // !! encounter such large primitives for all DDI.
  952. // !! In the legacy (DX5) interfaces,
  953. // !! If the primitive size is greater than MAX_DX6_PRIMCOUNT and
  954. // !! the DDI cannot handle it, then we to break up the primitive into
  955. // !! manageable chunks.
  956. if ((this->dwNumVertices > MAX_DX6_VERTICES) &&
  957. (IS_DP2HAL_DEVICE(this)))
  958. {
  959. DWORD dwOrigNumVerts = this->dwNumVertices;
  960. WORD wChunkSize = MAX_DX6_VERTICES - 3; // Even and a multiple of 3
  961. BYTE TmpVertex[32], FirstVertex[32];
  962. DWORD dwStepPerChunk;
  963. switch(this->primType)
  964. {
  965. case D3DPT_POINTLIST:
  966. case D3DPT_LINELIST:
  967. case D3DPT_TRIANGLELIST:
  968. dwStepPerChunk = dwVertexSize*wChunkSize;
  969. break;
  970. case D3DPT_LINESTRIP:
  971. dwStepPerChunk = dwVertexSize*(wChunkSize - 1);
  972. break;
  973. case D3DPT_TRIANGLEFAN:
  974. // Save the first index
  975. memcpy(FirstVertex, this->position.lpvData, dwVertexSize);
  976. // Fall through
  977. case D3DPT_TRIANGLESTRIP:
  978. dwStepPerChunk = dwVertexSize*(wChunkSize - 2);
  979. break;
  980. }
  981. int numChunks = (int)(dwOrigNumVerts/(DWORD)wChunkSize);
  982. WORD wRemainingVerts = (WORD)(dwOrigNumVerts - wChunkSize*numChunks);
  983. this->dwNumVertices = wChunkSize;
  984. // Calculate dwNumPrimitives and update stats
  985. GetNumPrim(this, this->dwNumVertices);
  986. // 0th iteration
  987. #if DBG
  988. ret = CheckDrawPrimitive(this);
  989. if (ret != D3D_OK)
  990. {
  991. return ret;
  992. }
  993. #endif
  994. ret = this->ProcessPrimitive();
  995. if (ret != D3D_OK)
  996. {
  997. return ret;
  998. }
  999. for (int i=1; i<numChunks; i++)
  1000. {
  1001. this->position.lpvData = (LPVOID)((LPBYTE)this->position.lpvData +
  1002. dwStepPerChunk);
  1003. if (this->primType == D3DPT_TRIANGLEFAN)
  1004. {
  1005. // Save the vertex
  1006. memcpy(TmpVertex, this->position.lpvData, dwVertexSize);
  1007. // Copy in the first vertex
  1008. memcpy(this->position.lpvData, FirstVertex, dwVertexSize);
  1009. }
  1010. #if DBG
  1011. ret = CheckDrawPrimitive(this);
  1012. if (ret != D3D_OK)
  1013. {
  1014. return ret;
  1015. }
  1016. #endif
  1017. ret = this->ProcessPrimitive();
  1018. // Write back the proper vertex in case something has been
  1019. // switched
  1020. if(this->primType == D3DPT_TRIANGLEFAN)
  1021. memcpy(this->position.lpvData, TmpVertex, dwVertexSize);
  1022. if (ret != D3D_OK)
  1023. {
  1024. return ret;
  1025. }
  1026. }
  1027. // The last time around
  1028. if (wRemainingVerts)
  1029. {
  1030. this->dwNumVertices = wRemainingVerts;
  1031. // Calculate dwNumPrimitives and update stats
  1032. GetNumPrim(this, this->dwNumVertices);
  1033. this->position.lpvData = (LPVOID)((LPBYTE)this->position.lpvData +
  1034. dwStepPerChunk);
  1035. if (this->primType == D3DPT_TRIANGLEFAN)
  1036. {
  1037. memcpy(TmpVertex, this->position.lpvData, dwVertexSize);
  1038. memcpy(this->position.lpvData, FirstVertex, dwVertexSize);
  1039. }
  1040. #if DBG
  1041. ret = CheckDrawPrimitive(this);
  1042. if (ret != D3D_OK)
  1043. {
  1044. return ret;
  1045. }
  1046. #endif
  1047. ret = this->ProcessPrimitive();
  1048. // Write back the proper vertex in case something has been
  1049. // switched
  1050. if(this->primType == D3DPT_TRIANGLEFAN)
  1051. memcpy(this->position.lpvData, TmpVertex, dwVertexSize);
  1052. if (ret != D3D_OK)
  1053. {
  1054. return ret;
  1055. }
  1056. }
  1057. }
  1058. else
  1059. {
  1060. // Calculate dwNumPrimitives and update stats
  1061. GetNumPrim(this, dwNumVertices);
  1062. #if DBG
  1063. ret = CheckDrawPrimitive(this);
  1064. if (ret != D3D_OK)
  1065. {
  1066. return ret;
  1067. }
  1068. #endif
  1069. return this->ProcessPrimitive();
  1070. }
  1071. return D3D_OK;
  1072. }
  1073. //---------------------------------------------------------------------
  1074. #undef DPF_MODNAME
  1075. #define DPF_MODNAME "DrawIndexedPrimitive"
  1076. HRESULT D3DAPI
  1077. DIRECT3DDEVICEI::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType,
  1078. D3DVERTEXTYPE VertexType,
  1079. LPVOID lpvVertices, DWORD dwNumVertices,
  1080. LPWORD lpwIndices, DWORD dwNumIndices,
  1081. DWORD dwFlags)
  1082. {
  1083. HRESULT ret = D3D_OK;
  1084. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  1085. #if DBG
  1086. if (!IsDPFlagsValid(dwFlags))
  1087. return DDERR_INVALIDPARAMS;
  1088. Profile(PROF_DRAWINDEXEDPRIMITIVEDEVICE2,PrimitiveType,VertexType);
  1089. #endif
  1090. this->primType = PrimitiveType;
  1091. this->dwVIDIn = d3dVertexToFVF[VertexType];
  1092. this->position.dwStride = sizeof(D3DVERTEX);
  1093. this->dwNumVertices = dwNumVertices;
  1094. this->lpwIndices = lpwIndices;
  1095. this->dwNumIndices = dwNumIndices;
  1096. this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress();
  1097. this->dwFlags = dwFlags;
  1098. this->position.lpvData = lpvVertices;
  1099. this->nTexCoord = 1;
  1100. ComputeOutputFVF(this);
  1101. if (this->dwVIDIn & D3DFVF_NORMAL)
  1102. this->dwFlags |= D3DPV_LIGHTING;
  1103. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
  1104. // AnanKan (6/22/98)
  1105. // !! This is a hack for the crippled DP2 driver model which cannot accept
  1106. // !! more that 64K primitives (primcount is a WORD). In DX6 interfaces
  1107. // !! we fail rendering if we encounter such large primitives.
  1108. // !! We do this for all DDI.
  1109. // !! In the legacy (DX5) interfaces,
  1110. // !! If the primitive size is greater than MAX_DX6_PRIMCOUNT and
  1111. // !! the DDI cannot handle it, then we to break up the primitive into
  1112. // !! manageable chunks.
  1113. if ((this->dwNumPrimitives > MAX_DX6_PRIMCOUNT) &&
  1114. (IS_DP2HAL_DEVICE(this)))
  1115. {
  1116. WORD wFirstIndex, wTmpIndex;
  1117. WORD wChunkSize = MAX_DX6_PRIMCOUNT;
  1118. int numPrimChunks;
  1119. DWORD dwResidualPrim;
  1120. DWORD dwResidualIndices;
  1121. DWORD dwStepPerChunk;
  1122. DWORD dwOrigNumPrim = this->dwNumPrimitives;
  1123. this->dwNumPrimitives = wChunkSize;
  1124. numPrimChunks = (int)(dwOrigNumPrim/(DWORD)wChunkSize);
  1125. dwResidualPrim = dwOrigNumPrim - wChunkSize*numPrimChunks;
  1126. switch(this->primType)
  1127. {
  1128. case D3DPT_POINTLIST:
  1129. this->dwNumIndices = this->dwNumPrimitives;
  1130. dwStepPerChunk = this->dwNumIndices;
  1131. dwResidualIndices = dwResidualPrim;
  1132. break;
  1133. case D3DPT_LINELIST:
  1134. this->dwNumIndices = this->dwNumPrimitives<<1;
  1135. dwStepPerChunk = this->dwNumIndices;
  1136. dwResidualIndices = dwResidualPrim << 1;
  1137. break;
  1138. case D3DPT_LINESTRIP:
  1139. this->dwNumIndices = this->dwNumPrimitives + 1;
  1140. dwStepPerChunk = this->dwNumIndices - 1;
  1141. dwResidualIndices = dwResidualPrim + 1;
  1142. break;
  1143. case D3DPT_TRIANGLEFAN:
  1144. this->dwNumIndices = this->dwNumPrimitives + 2;
  1145. dwStepPerChunk = this->dwNumIndices - 2;
  1146. dwResidualIndices = dwResidualPrim + 2;
  1147. // Save the first index
  1148. wTmpIndex = wFirstIndex = this->lpwIndices[0];
  1149. break;
  1150. case D3DPT_TRIANGLESTRIP:
  1151. wChunkSize = (MAX_DX6_PRIMCOUNT-1);
  1152. this->dwNumPrimitives = wChunkSize;
  1153. this->dwNumIndices = this->dwNumPrimitives + 2;
  1154. dwStepPerChunk = this->dwNumIndices - 2;
  1155. numPrimChunks = (int)(dwOrigNumPrim/(DWORD)wChunkSize);
  1156. dwResidualPrim = dwOrigNumPrim - wChunkSize*numPrimChunks;
  1157. dwResidualIndices = dwResidualPrim + 2;
  1158. break;
  1159. case D3DPT_TRIANGLELIST:
  1160. this->dwNumIndices = this->dwNumPrimitives * 3;
  1161. dwStepPerChunk = this->dwNumIndices;
  1162. dwResidualIndices = dwResidualPrim * 3;
  1163. break;
  1164. }
  1165. // 0th iteration
  1166. #if DBG
  1167. ret = CheckDrawIndexedPrimitive(this);
  1168. if (ret != D3D_OK)
  1169. {
  1170. return ret;
  1171. }
  1172. #endif
  1173. ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  1174. if (ret != D3D_OK)
  1175. {
  1176. return ret;
  1177. }
  1178. // Remaining chunks
  1179. for (int i=1; i<numPrimChunks; i++)
  1180. {
  1181. this->lpwIndices += dwStepPerChunk;
  1182. if (this->primType == D3DPT_TRIANGLEFAN)
  1183. {
  1184. // Save the index
  1185. wTmpIndex = this->lpwIndices[0];
  1186. // Copy in the first vertex
  1187. this->lpwIndices[0] = wFirstIndex;
  1188. }
  1189. #if DBG
  1190. ret = CheckDrawIndexedPrimitive(this);
  1191. if (ret != D3D_OK)
  1192. {
  1193. return ret;
  1194. }
  1195. #endif
  1196. ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  1197. // Write back the proper index in case something has been
  1198. // switched
  1199. if(this->primType == D3DPT_TRIANGLEFAN)
  1200. this->lpwIndices[0] = wTmpIndex;
  1201. if (ret != D3D_OK)
  1202. {
  1203. return ret;
  1204. }
  1205. }
  1206. // The last time around
  1207. if (dwResidualPrim)
  1208. {
  1209. this->dwNumPrimitives = dwResidualPrim;
  1210. this->dwNumIndices = dwResidualIndices;
  1211. this->lpwIndices += dwStepPerChunk;
  1212. if (this->primType == D3DPT_TRIANGLEFAN)
  1213. {
  1214. wTmpIndex = this->lpwIndices[0];
  1215. this->lpwIndices[0] = wFirstIndex;
  1216. }
  1217. #if DBG
  1218. ret = CheckDrawIndexedPrimitive(this);
  1219. if (ret != D3D_OK)
  1220. {
  1221. return ret;
  1222. }
  1223. #endif
  1224. ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  1225. // Write back the proper index in case something has been
  1226. // switched
  1227. if(this->primType == D3DPT_TRIANGLEFAN)
  1228. this->lpwIndices[0] = wTmpIndex;
  1229. if (ret != D3D_OK)
  1230. {
  1231. return ret;
  1232. }
  1233. }
  1234. }
  1235. else
  1236. {
  1237. #if DBG
  1238. ret = CheckDrawIndexedPrimitive(this);
  1239. if (ret != D3D_OK)
  1240. {
  1241. return ret;
  1242. }
  1243. #endif
  1244. // For an untransformed primitive, if a number of indices is much less
  1245. // than number of vertices we rebuild the primitive to reduce number
  1246. // of vertices to process.
  1247. if (this->dwNumIndices * INDEX_BATCH_SCALE < this->dwNumVertices &&
  1248. !FVF_TRANSFORMED(this->dwVIDIn))
  1249. return DereferenceIndexedPrim(this);
  1250. else
  1251. return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  1252. }
  1253. return D3D_OK;
  1254. }
  1255. //---------------------------------------------------------------------
  1256. #undef DPF_MODNAME
  1257. #define DPF_MODNAME "CDirect3DDeviceIDP::SetRenderStateI"
  1258. HRESULT D3DAPI
  1259. CDirect3DDeviceIDP::SetRenderStateI(D3DRENDERSTATETYPE dwStateType,
  1260. DWORD value)
  1261. {
  1262. LPD3DHAL_DRAWPRIMCOUNTS lpPC;
  1263. LPDWORD lpStateChange;
  1264. HRESULT ret;
  1265. if (dwStateType > D3DRENDERSTATE_STIPPLEPATTERN31)
  1266. {
  1267. D3D_WARN(4,"Trying to send invalid state %d to legacy driver",dwStateType);
  1268. return D3D_OK;
  1269. }
  1270. if (dwStateType > D3DRENDERSTATE_FLUSHBATCH && dwStateType < D3DRENDERSTATE_STIPPLEPATTERN00)
  1271. {
  1272. D3D_WARN(4,"Trying to send invalid state %d to legacy driver",dwStateType);
  1273. return D3D_OK;
  1274. }
  1275. if (D3DRENDERSTATE_FLUSHBATCH == dwStateType)
  1276. {
  1277. CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
  1278. ret = FlushStates();
  1279. if (ret != D3D_OK)
  1280. {
  1281. D3D_ERR("Error trying to render batched commands in SetRenderStateI");
  1282. }
  1283. return ret;
  1284. }
  1285. lpPC = this->lpDPPrimCounts;
  1286. if (lpPC->wNumVertices) //Do we already have Vertices filled in for this count ?
  1287. { //Yes, then Increment count
  1288. lpPC=this->lpDPPrimCounts=(LPD3DHAL_DRAWPRIMCOUNTS)((LPBYTE)this->lpwDPBuffer+this->dwDPOffset);
  1289. memset( (char *)lpPC,0,sizeof(D3DHAL_DRAWPRIMCOUNTS));
  1290. this->dwDPOffset += sizeof(D3DHAL_DRAWPRIMCOUNTS);
  1291. }
  1292. if (this->dwDPOffset + 2*sizeof(DWORD) > this->dwDPMaxOffset )
  1293. {
  1294. CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
  1295. ret = FlushStates();
  1296. if (ret != D3D_OK)
  1297. {
  1298. D3D_ERR("Error trying to render batched commands in SetRenderStateI");
  1299. return ret;
  1300. }
  1301. }
  1302. lpStateChange=(LPDWORD)((char *)this->lpwDPBuffer + this->dwDPOffset);
  1303. *lpStateChange=dwStateType;
  1304. lpStateChange ++;
  1305. *lpStateChange=value;
  1306. this->lpDPPrimCounts->wNumStateChanges ++;
  1307. this->dwDPOffset += 2*sizeof(DWORD);
  1308. #if 0
  1309. if (dwStateType == D3DRENDERSTATE_TEXTUREHANDLE && this->dwDPOffset== 0x10){
  1310. DPF(0,"SRdwDPOffset=%08lx, dwStateType=%08lx value=%08lx ddihandle=%08lx lpStateChange=%08lx lpDPPrimCounts=%08lx",
  1311. this->dwDPOffset,dwStateType,value,*lpStateChange,lpStateChange,this->lpDPPrimCounts);
  1312. _asm int 3
  1313. }
  1314. #endif //0
  1315. return D3D_OK;
  1316. }
  1317. //---------------------------------------------------------------------
  1318. DWORD visResults[6][2] =
  1319. {
  1320. D3DVIS_INTERSECT_LEFT ,
  1321. D3DVIS_OUTSIDE_LEFT ,
  1322. D3DVIS_INTERSECT_RIGHT ,
  1323. D3DVIS_OUTSIDE_RIGHT ,
  1324. D3DVIS_INTERSECT_TOP ,
  1325. D3DVIS_OUTSIDE_TOP ,
  1326. D3DVIS_INTERSECT_BOTTOM ,
  1327. D3DVIS_OUTSIDE_BOTTOM ,
  1328. D3DVIS_INTERSECT_NEAR ,
  1329. D3DVIS_OUTSIDE_NEAR ,
  1330. D3DVIS_INTERSECT_FAR ,
  1331. D3DVIS_OUTSIDE_FAR
  1332. };
  1333. //---------------------------------------------------------------------
  1334. DWORD CheckSphere(LPDIRECT3DDEVICEI lpDevI, LPD3DVECTOR center, D3DVALUE radius)
  1335. {
  1336. DWORD result = 0;
  1337. for (int i=0; i < 6; i++)
  1338. {
  1339. // Compute a distance from the center to the plane
  1340. D3DVALUE d = lpDevI->transform.frustum[i].x*center->x +
  1341. lpDevI->transform.frustum[i].y*center->y +
  1342. lpDevI->transform.frustum[i].z*center->z +
  1343. lpDevI->transform.frustum[i].w;
  1344. if (d + radius < 0)
  1345. result |= visResults[i][1]; // Outside
  1346. else
  1347. if (d - radius < 0.5f) // 0.5 is chosen to offset precision errors
  1348. result |= visResults[i][0]; // Intersect
  1349. }
  1350. if (result & (D3DVIS_OUTSIDE_LEFT |
  1351. D3DVIS_OUTSIDE_RIGHT |
  1352. D3DVIS_OUTSIDE_TOP |
  1353. D3DVIS_OUTSIDE_BOTTOM |
  1354. D3DVIS_OUTSIDE_NEAR |
  1355. D3DVIS_OUTSIDE_FAR))
  1356. {
  1357. result |= D3DVIS_OUTSIDE_FRUSTUM;
  1358. }
  1359. else
  1360. if (result)
  1361. result |= D3DVIS_INTERSECT_FRUSTUM;
  1362. return result;
  1363. }
  1364. //---------------------------------------------------------------------
  1365. #undef DPF_MODNAME
  1366. #define DPF_MODNAME "DIRECT3DDEVICEI::ComputeSphereVisibility"
  1367. HRESULT D3DAPI
  1368. DIRECT3DDEVICEI::ComputeSphereVisibility(LPD3DVECTOR lpCenters,
  1369. LPD3DVALUE lpRadii,
  1370. DWORD dwNumSpheres,
  1371. DWORD dwFlags,
  1372. LPDWORD lpdwReturnValues)
  1373. {
  1374. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  1375. #if DBG
  1376. TRY
  1377. {
  1378. if (dwFlags != 0 || dwNumSpheres == 0 ||
  1379. IsBadWritePtr(lpdwReturnValues, dwNumSpheres * sizeof(DWORD)) ||
  1380. IsBadWritePtr(lpRadii, dwNumSpheres * sizeof(D3DVALUE)) ||
  1381. IsBadWritePtr(lpCenters, dwNumSpheres * sizeof(LPD3DVECTOR)))
  1382. {
  1383. return DDERR_INVALIDPARAMS;
  1384. }
  1385. }
  1386. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1387. {
  1388. D3D_ERR( "Exception encountered validating parameters" );
  1389. return DDERR_INVALIDPARAMS;
  1390. }
  1391. #endif
  1392. this->dwFlags = 0;
  1393. if (dwFEFlags & D3DFE_TRANSFORM_DIRTY)
  1394. {
  1395. updateTransform(this);
  1396. }
  1397. if (this->dwFEFlags & D3DFE_FRUSTUMPLANES_DIRTY)
  1398. {
  1399. this->dwFlags |= D3DPV_FRUSTUMPLANES_DIRTY;
  1400. this->dwFEFlags &= ~D3DFE_FRUSTUMPLANES_DIRTY;
  1401. }
  1402. return this->pGeometryFuncs->ComputeSphereVisibility(this,
  1403. lpCenters,
  1404. lpRadii,
  1405. dwNumSpheres,
  1406. dwFlags,
  1407. lpdwReturnValues);
  1408. }
  1409. //---------------------------------------------------------------------
  1410. #undef DPF_MODNAME
  1411. #define DPF_MODNAME "ID3DFE_PVFUNCS::ComputeSphereVisibility"
  1412. HRESULT
  1413. D3DFE_PVFUNCS::ComputeSphereVisibility(LPD3DFE_PROCESSVERTICES pv,
  1414. LPD3DVECTOR lpCenters,
  1415. LPD3DVALUE lpRadii,
  1416. DWORD dwNumSpheres,
  1417. DWORD dwFlags,
  1418. LPDWORD lpdwReturnValues)
  1419. {
  1420. LPDIRECT3DDEVICEI lpDevI = static_cast<LPDIRECT3DDEVICEI>(pv);
  1421. HRESULT ret = D3DERR_INVALIDMATRIX;
  1422. #define transform lpDevI->transform
  1423. if (pv->dwFlags & D3DPV_FRUSTUMPLANES_DIRTY)
  1424. {
  1425. transform.dwFlags &= ~D3DTRANS_VALIDFRUSTUM;
  1426. if (Inverse4x4((D3DMATRIX*)&lpDevI->mCTM,
  1427. (D3DMATRIX*)&transform.mCTMI))
  1428. {
  1429. D3D_ERR("Cannot invert current (World X View) matrix.");
  1430. return ret;
  1431. }
  1432. // Transform the following clipping volume points to the model space by
  1433. // multiplying by inverse CTM
  1434. //
  1435. // v1 = { 0, 0, 0, 1};
  1436. // v2 = { 1, 0, 0, 1};
  1437. // v3 = { 1, 1, 0, 1};
  1438. // v4 = { 0, 1, 0, 1};
  1439. // v5 = { 0, 0, 1, 1};
  1440. // v6 = { 1, 0, 1, 1};
  1441. // v7 = { 0, 1, 1, 1};
  1442. //
  1443. // We do it manually to speed up
  1444. //
  1445. D3DVECTORH v1 = {transform.mCTMI._41,
  1446. transform.mCTMI._42,
  1447. transform.mCTMI._43,
  1448. transform.mCTMI._44};
  1449. D3DVECTORH v2 = {transform.mCTMI._11 + transform.mCTMI._41,
  1450. transform.mCTMI._12 + transform.mCTMI._42,
  1451. transform.mCTMI._13 + transform.mCTMI._43,
  1452. transform.mCTMI._14 + transform.mCTMI._44};
  1453. D3DVECTORH v3 = {transform.mCTMI._11 + transform.mCTMI._21 + transform.mCTMI._41,
  1454. transform.mCTMI._12 + transform.mCTMI._22 + transform.mCTMI._42,
  1455. transform.mCTMI._13 + transform.mCTMI._23 + transform.mCTMI._43,
  1456. transform.mCTMI._14 + transform.mCTMI._24 + transform.mCTMI._44};
  1457. D3DVECTORH v4 = {transform.mCTMI._21 + transform.mCTMI._41,
  1458. transform.mCTMI._22 + transform.mCTMI._42,
  1459. transform.mCTMI._23 + transform.mCTMI._43,
  1460. transform.mCTMI._24 + transform.mCTMI._44};
  1461. D3DVECTORH v5 = {transform.mCTMI._31 + transform.mCTMI._41,
  1462. transform.mCTMI._32 + transform.mCTMI._42,
  1463. transform.mCTMI._33 + transform.mCTMI._43,
  1464. transform.mCTMI._34 + transform.mCTMI._44};
  1465. D3DVECTORH v6 = {transform.mCTMI._11 + transform.mCTMI._31 + transform.mCTMI._41,
  1466. transform.mCTMI._12 + transform.mCTMI._32 + transform.mCTMI._42,
  1467. transform.mCTMI._13 + transform.mCTMI._33 + transform.mCTMI._43,
  1468. transform.mCTMI._14 + transform.mCTMI._34 + transform.mCTMI._44};
  1469. D3DVECTORH v7 = {transform.mCTMI._21 + transform.mCTMI._31 + transform.mCTMI._41,
  1470. transform.mCTMI._22 + transform.mCTMI._32 + transform.mCTMI._42,
  1471. transform.mCTMI._23 + transform.mCTMI._33 + transform.mCTMI._43,
  1472. transform.mCTMI._24 + transform.mCTMI._34 + transform.mCTMI._44};
  1473. // Convert vectors from homogeneous to 3D
  1474. if (Vector4to3D(&v1))
  1475. goto exit;
  1476. if (Vector4to3D(&v2))
  1477. goto exit;
  1478. if (Vector4to3D(&v3))
  1479. goto exit;
  1480. if (Vector4to3D(&v4))
  1481. goto exit;
  1482. if (Vector4to3D(&v5))
  1483. goto exit;
  1484. if (Vector4to3D(&v6))
  1485. goto exit;
  1486. if (Vector4to3D(&v7))
  1487. goto exit;
  1488. // Build frustum planes
  1489. // Left
  1490. if (MakePlane((D3DVECTOR*)&v1, (D3DVECTOR*)&v4, (D3DVECTOR*)&v5, &transform.frustum[0]))
  1491. goto exit;
  1492. // Right
  1493. if (MakePlane((D3DVECTOR*)&v2, (D3DVECTOR*)&v6, (D3DVECTOR*)&v3, &transform.frustum[1]))
  1494. goto exit;
  1495. // Top
  1496. if (MakePlane((D3DVECTOR*)&v4, (D3DVECTOR*)&v3, (D3DVECTOR*)&v7, &transform.frustum[2]))
  1497. goto exit;
  1498. // Bottom
  1499. if (MakePlane((D3DVECTOR*)&v1, (D3DVECTOR*)&v5, (D3DVECTOR*)&v2, &transform.frustum[3]))
  1500. goto exit;
  1501. // Near
  1502. if (MakePlane((D3DVECTOR*)&v1, (D3DVECTOR*)&v2, (D3DVECTOR*)&v3, &transform.frustum[4]))
  1503. goto exit;
  1504. // Far
  1505. if (MakePlane((D3DVECTOR*)&v6, (D3DVECTOR*)&v5, (D3DVECTOR*)&v7, &transform.frustum[5]))
  1506. goto exit;
  1507. transform.dwFlags |= D3DTRANS_VALIDFRUSTUM;
  1508. }
  1509. if (transform.dwFlags & D3DTRANS_VALIDFRUSTUM)
  1510. {
  1511. // Now we can check the spheres against the clipping planes
  1512. for (DWORD i=0; i < dwNumSpheres; i++)
  1513. {
  1514. lpdwReturnValues[i] = CheckSphere(lpDevI, &lpCenters[i], lpRadii[i]);
  1515. }
  1516. return D3D_OK;
  1517. }
  1518. exit:
  1519. D3D_ERR("Non-orthogonal (world X view) matrix");
  1520. return ret;
  1521. #undef transform
  1522. }
  1523. //---------------------------------------------------------------------
  1524. DWORD
  1525. D3DFE_PVFUNCS::GenClipFlags(D3DFE_PROCESSVERTICES *pv)
  1526. {
  1527. return D3DFE_GenClipFlags(pv);
  1528. }
  1529. //---------------------------------------------------------------------
  1530. DWORD
  1531. D3DFE_PVFUNCS::TransformVertices(D3DFE_PROCESSVERTICES *pv,
  1532. DWORD vertexCount,
  1533. LPD3DTRANSFORMDATAI data)
  1534. {
  1535. if (pv->dwFlags & D3DDP_DONOTCLIP)
  1536. return D3DFE_TransformUnclippedVp(pv, vertexCount, data);
  1537. else
  1538. return D3DFE_TransformClippedVp(pv, vertexCount, data);
  1539. }
  1540. //---------------------------------------------------------------------
  1541. DWORD ID3DFE_PVFUNCS::GenClipFlags(D3DFE_PROCESSVERTICES *pv)
  1542. {
  1543. return GeometryFuncsGuaranteed.GenClipFlags(pv);
  1544. }
  1545. //---------------------------------------------------------------------
  1546. // Used to implement viewport->TransformVertices
  1547. // Returns clip intersection code
  1548. DWORD ID3DFE_PVFUNCS::TransformVertices(D3DFE_PROCESSVERTICES *pv,
  1549. DWORD vertexCount,
  1550. D3DTRANSFORMDATAI* data)
  1551. {
  1552. return GeometryFuncsGuaranteed.TransformVertices(pv, vertexCount, data);
  1553. }