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.

1492 lines
41 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name
  4. trimesh.cxx
  5. Abstract:
  6. Implement triangle mesh API
  7. Author:
  8. Mark Enstrom (marke) 23-Jun-1996
  9. Enviornment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "precomp.hxx"
  14. #include "dciman.h"
  15. #pragma hdrstop
  16. extern PFNGRFILL gpfnGradientFill;
  17. #if !(_WIN32_WINNT >= 0x500)
  18. /**************************************************************************\
  19. * bCalcGradientRectOffsets
  20. *
  21. * quick summary of gradient rect drawing bounds
  22. *
  23. * Arguments:
  24. *
  25. * pGradRect - gradient rect data
  26. *
  27. * Return Value:
  28. *
  29. * status
  30. *
  31. * History:
  32. *
  33. * 2/14/1997 Mark Enstrom [marke]
  34. *
  35. \**************************************************************************/
  36. BOOL
  37. bCalcGradientRectOffsets(
  38. PGRADIENTRECTDATA pGradRect
  39. )
  40. {
  41. LONG yScanTop = MAX(pGradRect->rclClip.top,pGradRect->rclGradient.top);
  42. LONG yScanBottom = MIN(pGradRect->rclClip.bottom,pGradRect->rclGradient.bottom);
  43. LONG yScanLeft = MAX(pGradRect->rclClip.left,pGradRect->rclGradient.left);
  44. LONG yScanRight = MIN(pGradRect->rclClip.right,pGradRect->rclGradient.right);
  45. //
  46. // calc actual widht, check for early out
  47. //
  48. pGradRect->ptDraw.x = yScanLeft;
  49. pGradRect->ptDraw.y = yScanTop;
  50. pGradRect->szDraw.cx = yScanRight - yScanLeft;
  51. pGradRect->szDraw.cy = yScanBottom - yScanTop;
  52. LONG ltemp = pGradRect->rclClip.left - pGradRect->rclGradient.left;
  53. if (ltemp <= 0)
  54. {
  55. ltemp = 0;
  56. }
  57. pGradRect->xScanAdjust = ltemp;
  58. ltemp = pGradRect->rclClip.top - pGradRect->rclGradient.top;
  59. if (ltemp <= 0)
  60. {
  61. ltemp = 0;
  62. }
  63. pGradRect->yScanAdjust = ltemp;
  64. return((pGradRect->szDraw.cx > 0) && (pGradRect->szDraw.cy > 0));
  65. }
  66. /******************************Public*Routine******************************\
  67. * pfnGradientRectFillFunction
  68. *
  69. * look at format to decide if DIBSection should be drawn directly
  70. *
  71. * 32 bpp RGB
  72. * 32 bpp BGR
  73. * 24 bpp
  74. * 16 bpp 565
  75. * 16 bpp 555
  76. *
  77. * Trangles are only filled in high color (no palette) surfaces
  78. *
  79. * Arguments:
  80. *
  81. * pDibInfo - information about destination surface
  82. *
  83. * Return Value:
  84. *
  85. * PFN_GRADRECT - triangle filling routine
  86. *
  87. * History:
  88. *
  89. * 12/6/1996 Mark Enstrom [marke]
  90. *
  91. \**************************************************************************/
  92. PFN_GRADRECT
  93. pfnGradientRectFillFunction(
  94. PDIBINFO pDibInfo
  95. )
  96. {
  97. PFN_GRADRECT pfnRet = NULL;
  98. PULONG pulMasks = (PULONG)&pDibInfo->pbmi->bmiColors[0];
  99. //
  100. // 32 bpp RGB
  101. //
  102. if (
  103. (pDibInfo->pbmi->bmiHeader.biBitCount == 32) &&
  104. (pDibInfo->pbmi->bmiHeader.biCompression == BI_RGB)
  105. )
  106. {
  107. pfnRet = vFillGRectDIB32BGRA;
  108. }
  109. else if (
  110. (pDibInfo->pbmi->bmiHeader.biBitCount == 32) &&
  111. (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) &&
  112. (pulMasks[0] == 0xff0000) &&
  113. (pulMasks[1] == 0x00ff00) &&
  114. (pulMasks[2] == 0x0000ff)
  115. )
  116. {
  117. pfnRet = vFillGRectDIB32BGRA;
  118. }
  119. else if (
  120. (pDibInfo->pbmi->bmiHeader.biBitCount == 32) &&
  121. (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) &&
  122. (pulMasks[0] == 0x0000ff) &&
  123. (pulMasks[1] == 0x00ff00) &&
  124. (pulMasks[2] == 0xff0000)
  125. )
  126. {
  127. pfnRet = vFillGRectDIB32RGB;
  128. }
  129. else if (
  130. (pDibInfo->pbmi->bmiHeader.biBitCount == 24) &&
  131. (pDibInfo->pbmi->bmiHeader.biCompression == BI_RGB)
  132. )
  133. {
  134. pfnRet = vFillGRectDIB24RGB;
  135. }
  136. //
  137. // 16 BPP
  138. //
  139. else if (
  140. (pDibInfo->pbmi->bmiHeader.biBitCount == 16) &&
  141. (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS)
  142. )
  143. {
  144. //
  145. // 565,555
  146. //
  147. if (
  148. (pulMasks[0] == 0xf800) &&
  149. (pulMasks[1] == 0x07e0) &&
  150. (pulMasks[2] == 0x001f)
  151. )
  152. {
  153. pfnRet = vFillGRectDIB16_565;
  154. }
  155. else if (
  156. (pulMasks[0] == 0x7c00) &&
  157. (pulMasks[1] == 0x03e0) &&
  158. (pulMasks[2] == 0x001f)
  159. )
  160. {
  161. pfnRet = vFillGRectDIB16_555;
  162. }
  163. }
  164. else
  165. {
  166. pfnRet = vFillGRectDIB32Direct;
  167. }
  168. return(pfnRet);
  169. }
  170. /**************************************************************************\
  171. * DIBGradientRect
  172. *
  173. *
  174. * Arguments:
  175. *
  176. *
  177. *
  178. * Return Value:
  179. *
  180. *
  181. *
  182. * History:
  183. *
  184. * 2/11/1997 Mark Enstrom [marke]
  185. *
  186. \**************************************************************************/
  187. BOOL
  188. DIBGradientRect(
  189. HDC hdc,
  190. PTRIVERTEX pVertex,
  191. ULONG nVertex,
  192. PGRADIENT_RECT pMesh,
  193. ULONG nMesh,
  194. ULONG ulMode,
  195. PRECTL prclPhysExt,
  196. PDIBINFO pDibInfo,
  197. PPOINTL pptlDitherOrg
  198. )
  199. {
  200. BOOL bStatus = TRUE;
  201. PFN_GRADRECT pfnGradRect = NULL;
  202. ULONG ulIndex;
  203. pfnGradRect = pfnGradientRectFillFunction(pDibInfo);
  204. if (pfnGradRect == NULL)
  205. {
  206. WARNING("DIBGradientRect:Can't draw to surface\n");
  207. return(TRUE);
  208. }
  209. //
  210. // work in physical map mode, restore before return
  211. //
  212. ULONG OldMode = SetMapMode(hdc,MM_TEXT);
  213. //
  214. // fake up scale !!!
  215. //
  216. for (ulIndex=0;ulIndex<nVertex;ulIndex++)
  217. {
  218. pVertex[ulIndex].x = pVertex[ulIndex].x * 16;
  219. pVertex[ulIndex].y = pVertex[ulIndex].y * 16;
  220. }
  221. //
  222. // limit rectangle output to clipped output
  223. //
  224. LONG dxRect = prclPhysExt->right - prclPhysExt->left;
  225. LONG dyRect = prclPhysExt->bottom - prclPhysExt->top;
  226. //
  227. // check for clipped out
  228. //
  229. if ((dyRect > 0) && (dxRect > 0))
  230. {
  231. GRADIENTRECTDATA grData;
  232. //
  233. // clip output
  234. //
  235. grData.rclClip = *prclPhysExt;
  236. grData.ptDitherOrg = *pptlDitherOrg;
  237. for (ulIndex=0;ulIndex<nMesh;ulIndex++)
  238. {
  239. ULONG ulRect0 = pMesh[ulIndex].UpperLeft;
  240. ULONG ulRect1 = pMesh[ulIndex].LowerRight;
  241. //
  242. // make sure index are in array
  243. //
  244. if (
  245. (ulRect0 > nVertex) ||
  246. (ulRect1 > nVertex)
  247. )
  248. {
  249. bStatus = FALSE;
  250. break;
  251. }
  252. TRIVERTEX tvert0 = pVertex[ulRect0];
  253. TRIVERTEX tvert1 = pVertex[ulRect1];
  254. PTRIVERTEX pv0 = &tvert0;
  255. PTRIVERTEX pv1 = &tvert1;
  256. PTRIVERTEX pvt;
  257. //
  258. // make sure rectangle endpoints are properly ordered
  259. //
  260. if (ulMode == GRADIENT_FILL_RECT_H)
  261. {
  262. if (pv0->x > pv1->x)
  263. {
  264. SWAP_VERTEX(pv0,pv1,pvt);
  265. }
  266. if (pv0->y > pv1->y)
  267. {
  268. //
  269. // must swap y
  270. //
  271. LONG ltemp = pv1->y;
  272. pv1->y = pv0->y;
  273. pv0->y = ltemp;
  274. }
  275. }
  276. else
  277. {
  278. if (pv0->y > pv1->y)
  279. {
  280. SWAP_VERTEX(pv0,pv1,pvt);
  281. }
  282. if (pv0->x > pv1->x)
  283. {
  284. //
  285. // must swap x
  286. //
  287. LONG ltemp = pv1->x;
  288. pv1->x = pv0->x;
  289. pv0->x = ltemp;
  290. }
  291. }
  292. //
  293. // gradient definition rectangle
  294. //
  295. grData.rclGradient.left = pv0->x >> 4;
  296. grData.rclGradient.top = pv0->y >> 4;
  297. grData.rclGradient.right = pv1->x >> 4;
  298. grData.rclGradient.bottom = pv1->y >> 4;
  299. LONG dxGrad = grData.rclGradient.right - grData.rclGradient.left;
  300. LONG dyGrad = grData.rclGradient.bottom - grData.rclGradient.top;
  301. //
  302. // make sure this is not an empty rectangle
  303. //
  304. if ((dxGrad > 0) && (dyGrad > 0))
  305. {
  306. grData.ulMode = ulMode;
  307. //
  308. // calculate color gradients for x and y
  309. //
  310. grData.llRed = ((LONGLONG)pv0->Red) << 40;
  311. grData.llGreen = ((LONGLONG)pv0->Green) << 40;
  312. grData.llBlue = ((LONGLONG)pv0->Blue) << 40;
  313. grData.llAlpha = ((LONGLONG)pv0->Alpha) << 40;
  314. if (ulMode == GRADIENT_FILL_RECT_H)
  315. {
  316. grData.lldRdY = 0;
  317. grData.lldGdY = 0;
  318. grData.lldBdY = 0;
  319. grData.lldAdY = 0;
  320. LONGLONG lldRed = (LONGLONG)(pv1->Red) << 40;
  321. LONGLONG lldGreen = (LONGLONG)(pv1->Green) << 40;
  322. LONGLONG lldBlue = (LONGLONG)(pv1->Blue) << 40;
  323. LONGLONG lldAlpha = (LONGLONG)(pv1->Alpha) << 40;
  324. lldRed -= (LONGLONG)(pv0->Red) << 40;
  325. lldGreen -= (LONGLONG)(pv0->Green) << 40;
  326. lldBlue -= (LONGLONG)(pv0->Blue) << 40;
  327. lldAlpha -= (LONGLONG)(pv0->Alpha) << 40;
  328. grData.lldRdX = MDiv64(lldRed ,(LONGLONG)1,(LONGLONG)dxGrad);
  329. grData.lldGdX = MDiv64(lldGreen,(LONGLONG)1,(LONGLONG)dxGrad);
  330. grData.lldBdX = MDiv64(lldBlue ,(LONGLONG)1,(LONGLONG)dxGrad);
  331. grData.lldAdX = MDiv64(lldAlpha,(LONGLONG)1,(LONGLONG)dxGrad);
  332. }
  333. else
  334. {
  335. grData.lldRdX = 0;
  336. grData.lldGdX = 0;
  337. grData.lldBdX = 0;
  338. grData.lldAdX = 0;
  339. LONGLONG lldRed = (LONGLONG)(pv1->Red) << 40;
  340. LONGLONG lldGreen = (LONGLONG)(pv1->Green) << 40;
  341. LONGLONG lldBlue = (LONGLONG)(pv1->Blue) << 40;
  342. LONGLONG lldAlpha = (LONGLONG)(pv1->Alpha) << 40;
  343. lldRed -= (LONGLONG)(pv0->Red) << 40;
  344. lldGreen -= (LONGLONG)(pv0->Green) << 40;
  345. lldBlue -= (LONGLONG)(pv0->Blue) << 40;
  346. lldAlpha -= (LONGLONG)(pv0->Alpha) << 40;
  347. grData.lldRdY = MDiv64(lldRed ,(LONGLONG)1,(LONGLONG)dyGrad);
  348. grData.lldGdY = MDiv64(lldGreen,(LONGLONG)1,(LONGLONG)dyGrad);
  349. grData.lldBdY = MDiv64(lldBlue ,(LONGLONG)1,(LONGLONG)dyGrad);
  350. grData.lldAdY = MDiv64(lldAlpha,(LONGLONG)1,(LONGLONG)dyGrad);
  351. }
  352. //
  353. // calculate common offsets
  354. //
  355. if (bCalcGradientRectOffsets(&grData))
  356. {
  357. //
  358. // call specific drawing routine if output
  359. // not totally clipped
  360. //
  361. (*pfnGradRect)(pDibInfo,&grData);
  362. }
  363. }
  364. }
  365. }
  366. SetMapMode(hdc,OldMode);
  367. return(bStatus);
  368. }
  369. /******************************Public*Routine******************************\
  370. * DIBTriangleMesh
  371. *
  372. * Draw triangle mesh to surface
  373. *
  374. * Arguments:
  375. *
  376. * hdc - dc
  377. * pVertex - vertex array
  378. * nVertex - elements in vertex array
  379. * pMesh - mesh array
  380. * nMesh - elements in mesh array
  381. * ulMode - drawing mode
  382. * prclPhysExt - physical extents
  383. * prclMeshExt - unconstrained physical mesh ext
  384. * pDibInfo - surface information
  385. * pptlDitherOrg - dither origin
  386. * bReadable - surface readable
  387. *
  388. * Return Value:
  389. *
  390. * status
  391. *
  392. * History:
  393. *
  394. * 12/4/1996 Mark Enstrom [marke]
  395. *
  396. \**************************************************************************/
  397. BOOL
  398. DIBTriangleMesh(
  399. HDC hdc,
  400. PTRIVERTEX pVertex,
  401. ULONG nVertex,
  402. PGRADIENT_TRIANGLE pMesh,
  403. ULONG nMesh,
  404. ULONG ulMode,
  405. PRECTL prclPhysExt,
  406. PRECTL prclMeshExt,
  407. PDIBINFO pDibInfo,
  408. PPOINTL pptlDitherOrg,
  409. BOOL bReadable
  410. )
  411. {
  412. BOOL bStatus = TRUE;
  413. RECTL rclDst;
  414. RECTL rclDstWk;
  415. ULONG ulIndex;
  416. PTRIANGLEDATA ptData = NULL;
  417. PFN_TRIFILL pfnTriFill = NULL;
  418. pfnTriFill = pfnTriangleFillFunction(pDibInfo,bReadable);
  419. if (pfnTriFill == NULL)
  420. {
  421. WARNING("DIBTriangleMesh:Can't draw to surface\n");
  422. return(TRUE);
  423. }
  424. //
  425. // work in physical map mode, restore before return
  426. //
  427. ULONG OldMode = SetMapMode(hdc,MM_TEXT);
  428. //
  429. // limit recorded triangle to clipped output
  430. //
  431. LONG dxTri = prclPhysExt->right - prclPhysExt->left;
  432. LONG dyTri = prclPhysExt->bottom - prclPhysExt->top;
  433. //
  434. // check for clipped out
  435. //
  436. if ((dyTri > 0) && (dxTri > 0))
  437. {
  438. //
  439. // allocate structure to hold scan line data for all triangles
  440. // drawn during this call
  441. //
  442. ptData = (PTRIANGLEDATA)LOCALALLOC(sizeof(TRIANGLEDATA) + (dyTri-1) * sizeof(TRIEDGE));
  443. if (ptData != NULL)
  444. {
  445. //
  446. // Init Global Data
  447. //
  448. ptData->rcl = *prclPhysExt;
  449. ptData->DrawMode = ulMode;
  450. ptData->ptDitherOrg = *pptlDitherOrg;
  451. //
  452. // if triangle does not need to be split, draw each one.
  453. // Triangles need to be split if any edge exceeds a length
  454. // that will cause math problems.
  455. //
  456. if (
  457. ((prclMeshExt->right - prclMeshExt->left) < MAX_EDGE_LENGTH) &&
  458. ((prclMeshExt->bottom - prclMeshExt->top) < MAX_EDGE_LENGTH)
  459. )
  460. {
  461. //
  462. // no split needed
  463. //
  464. ULONG ulIndex;
  465. for (ulIndex = 0;ulIndex<nMesh;ulIndex++)
  466. {
  467. PTRIVERTEX pv0 = &pVertex[pMesh[ulIndex].Vertex1];
  468. PTRIVERTEX pv1 = &pVertex[pMesh[ulIndex].Vertex2];
  469. PTRIVERTEX pv2 = &pVertex[pMesh[ulIndex].Vertex3];
  470. if (bIsTriangleInBounds(pv0,pv1,pv2,ptData))
  471. {
  472. bStatus = bCalculateAndDrawTriangle(pDibInfo,pv0,pv1,pv2,ptData,pfnTriFill);
  473. }
  474. }
  475. }
  476. else
  477. {
  478. //
  479. // some triangles exceed maximum length, need to scan through triangles
  480. // and split triangles that exceed maximum edge length. This routine
  481. // works in a pseudo recursive manner, by splitting one triangle, then
  482. // splitting one of those 2 and so on. maximum depth is:
  483. //
  484. // 2 * ((log(2)(max dx,dy)) - 10)
  485. //
  486. // 10 = log(2) MAX_EDGE_LENGTH (2^14)
  487. // LOG(2)(2^28) = 28
  488. //
  489. // 2 * (28 - 14) = 28
  490. //
  491. ULONG ulMaxVertex = nVertex + 28;
  492. ULONG ulMaxMesh = nMesh + 28;
  493. PBYTE pAlloc = NULL;
  494. ULONG ulSizeAlloc = (sizeof(TRIVERTEX) * ulMaxVertex) +
  495. (sizeof(GRADIENT_TRIANGLE) * ulMaxMesh) +
  496. (sizeof(ULONG) * ulMaxMesh);
  497. pAlloc = (PBYTE)LOCALALLOC(ulSizeAlloc);
  498. if (pAlloc != NULL)
  499. {
  500. //
  501. // assign buffers
  502. //
  503. PTRIVERTEX pTempVertex = (PTRIVERTEX)pAlloc;
  504. PGRADIENT_TRIANGLE pTempMesh = (PGRADIENT_TRIANGLE)(pAlloc + (sizeof(TRIVERTEX) * ulMaxVertex));
  505. PULONG pRecurse = (PULONG)((PBYTE)pTempMesh + (sizeof(GRADIENT_TRIANGLE) * ulMaxMesh));
  506. //
  507. // copy initial triangle information
  508. //
  509. memcpy(pTempVertex,pVertex,sizeof(TRIVERTEX) * nVertex);
  510. memcpy(pTempMesh,pMesh,sizeof(TRIVERTEX) * nMesh);
  511. memset(pRecurse,0,nMesh * sizeof(ULONG));
  512. //
  513. // next free location in vertex and mesh arrays
  514. //
  515. ULONG FreeVertex = nVertex;
  516. ULONG FreeMesh = nMesh;
  517. do
  518. {
  519. BOOL bSplit = FALSE;
  520. //
  521. // always operate on the last triangle in array
  522. //
  523. ULONG CurrentMesh = FreeMesh - 1;
  524. ASSERTGDI(CurrentMesh >= 0,"bTriangleMesh: Error in CurrentMesh\n");
  525. //
  526. // validate mesh pointers
  527. //
  528. if (
  529. (pTempMesh[CurrentMesh].Vertex1 >= ulMaxVertex) ||
  530. (pTempMesh[CurrentMesh].Vertex2 >= ulMaxVertex) ||
  531. (pTempMesh[CurrentMesh].Vertex3 >= ulMaxVertex)
  532. )
  533. {
  534. RIP("Error in triangle split routine:Vertex out of range\n");
  535. break;
  536. }
  537. PTRIVERTEX pv0 = &pTempVertex[pTempMesh[CurrentMesh].Vertex1];
  538. PTRIVERTEX pv1 = &pTempVertex[pTempMesh[CurrentMesh].Vertex2];
  539. PTRIVERTEX pv2 = &pTempVertex[pTempMesh[CurrentMesh].Vertex3];
  540. //
  541. // check if triangle boundary is inside clip rect
  542. //
  543. if (bIsTriangleInBounds(pv0,pv1,pv2,ptData))
  544. {
  545. bSplit = bSplitTriangle(pTempVertex,&FreeVertex,pTempMesh,&FreeMesh,pRecurse);
  546. if (!bSplit)
  547. {
  548. //
  549. // draw triangle
  550. //
  551. bStatus = bCalculateAndDrawTriangle(pDibInfo,pv0,pv1,pv2,ptData,pfnTriFill);
  552. }
  553. else
  554. {
  555. //
  556. // validate array indcies
  557. //
  558. if ((FreeVertex > ulMaxVertex) ||
  559. (FreeMesh > ulMaxMesh))
  560. {
  561. RIP("Error in triangle split routine: indicies out of range\n");
  562. break;
  563. }
  564. }
  565. }
  566. //
  567. // if triangle was not split, then remove from list.
  568. //
  569. if (!bSplit)
  570. {
  571. //
  572. // remove triangle just drawn. If this is the second triangle of a
  573. // split, then remove the added vertex and the original triangle as
  574. // well
  575. //
  576. do
  577. {
  578. FreeMesh--;
  579. if (pRecurse[FreeMesh])
  580. {
  581. FreeVertex--;
  582. }
  583. } while ((FreeMesh != 0) && (pRecurse[FreeMesh] == 1));
  584. }
  585. } while (FreeMesh != 0);
  586. LOCALFREE(pAlloc);
  587. }
  588. else
  589. {
  590. WARNING1("Memory allocation failed for temp triangle buffers\n");
  591. bStatus = FALSE;
  592. }
  593. }
  594. }
  595. else
  596. {
  597. DbgPrint("DIBTriangleMesh:Failed alloc \n");
  598. bStatus = FALSE;
  599. }
  600. //
  601. // cleanup
  602. //
  603. if (ptData)
  604. {
  605. LOCALFREE(ptData);
  606. }
  607. }
  608. return(bStatus);
  609. }
  610. /******************************Public*Routine******************************\
  611. * vCalcMeshExtent
  612. *
  613. * Calculate bounding rect of drawing
  614. *
  615. * Arguments:
  616. *
  617. * pVertex - vertex array
  618. * nVertex - number of vertex in array
  619. * pMesh - array of rect or tri
  620. * nMesh - number in mesh array
  621. * ulMode - triangle or rectangle
  622. * prclExt - return extent rect
  623. *
  624. * Return Value:
  625. *
  626. * None - if prcl in NULL then error occured
  627. *
  628. * History:
  629. *
  630. * 12/3/1996 Mark Enstrom [marke]
  631. *
  632. \**************************************************************************/
  633. VOID
  634. vCalcMeshExtent(
  635. PTRIVERTEX pVertex,
  636. ULONG nVertex,
  637. PVOID pMesh,
  638. ULONG nMesh,
  639. ULONG ulMode,
  640. RECTL *prclExt
  641. )
  642. {
  643. ULONG ulIndex;
  644. LONG xmin = MAX_INT;
  645. LONG xmax = MIN_INT;
  646. LONG ymin = MAX_INT;
  647. LONG ymax = MIN_INT;
  648. if (
  649. (ulMode == GRADIENT_FILL_RECT_H) ||
  650. (ulMode == GRADIENT_FILL_RECT_V)
  651. )
  652. {
  653. ASSERTGDI(nMesh == 1,"vCalcMeshExtent: nMesh must be 1 for rect mode");
  654. RECTL rcl;
  655. ULONG vul = ((PGRADIENT_RECT)pMesh)->UpperLeft;
  656. ULONG vlr = ((PGRADIENT_RECT)pMesh)->LowerRight;
  657. if ((vul <= nVertex) && (vlr <= nVertex))
  658. {
  659. if (pVertex[vul].x < xmin)
  660. {
  661. xmin = pVertex[vul].x;
  662. }
  663. if (pVertex[vul].x > xmax)
  664. {
  665. xmax = pVertex[vul].x;
  666. }
  667. if (pVertex[vul].y < ymin)
  668. {
  669. ymin = pVertex[vul].y;
  670. }
  671. if (pVertex[vul].y > ymax)
  672. {
  673. ymax = pVertex[vul].y;
  674. }
  675. if (pVertex[vlr].x < xmin)
  676. {
  677. xmin = pVertex[vlr].x;
  678. }
  679. if (pVertex[vlr].x > xmax)
  680. {
  681. xmax = pVertex[vlr].x;
  682. }
  683. if (pVertex[vlr].y < ymin)
  684. {
  685. ymin = pVertex[vlr].y;
  686. }
  687. if (pVertex[vlr].y > ymax)
  688. {
  689. ymax = pVertex[vlr].y;
  690. }
  691. }
  692. }
  693. else if (ulMode == GRADIENT_FILL_TRIANGLE)
  694. {
  695. PGRADIENT_TRIANGLE pGradTri = (PGRADIENT_TRIANGLE)pMesh;
  696. for (ulIndex=0;ulIndex<nMesh;ulIndex++)
  697. {
  698. LONG lVertex[3];
  699. LONG vIndex;
  700. lVertex[0] = pGradTri->Vertex1;
  701. lVertex[1] = pGradTri->Vertex2;
  702. lVertex[2] = pGradTri->Vertex3;
  703. for (vIndex=0;vIndex<3;vIndex++)
  704. {
  705. ULONG TriVertex = lVertex[vIndex];
  706. if (TriVertex < nVertex)
  707. {
  708. if (pVertex[TriVertex].x < xmin)
  709. {
  710. xmin = pVertex[TriVertex].x;
  711. }
  712. if (pVertex[TriVertex].x > xmax)
  713. {
  714. xmax = pVertex[TriVertex].x;
  715. }
  716. if (pVertex[TriVertex].y < ymin)
  717. {
  718. ymin = pVertex[TriVertex].y;
  719. }
  720. if (pVertex[TriVertex].y > ymax)
  721. {
  722. ymax = pVertex[TriVertex].y;
  723. }
  724. }
  725. else
  726. {
  727. //
  728. // error in mesh/vertex array, return null
  729. // bounding rect
  730. //
  731. prclExt->left = 0;
  732. prclExt->right = 0;
  733. prclExt->top = 0;
  734. prclExt->bottom = 0;
  735. return;
  736. }
  737. }
  738. pGradTri++;
  739. }
  740. }
  741. prclExt->left = xmin;
  742. prclExt->right = xmax;
  743. prclExt->top = ymin;
  744. prclExt->bottom = ymax;
  745. }
  746. /******************************Public*Routine******************************\
  747. * bConvertVertexToPhysical
  748. *
  749. * Convert from logical to physical coordinates
  750. *
  751. * Arguments:
  752. *
  753. * hdc - hdc
  754. * pVertex - logical vertex array
  755. * nVertex - number of elements in vertex array
  756. * pPhysVert - physical vertex array
  757. *
  758. * Return Value:
  759. *
  760. * status
  761. *
  762. * History:
  763. *
  764. * 12/4/1996 Mark Enstrom [marke]
  765. *
  766. \**************************************************************************/
  767. BOOL
  768. bConvertVertexToPhysical(
  769. HDC hdc,
  770. PTRIVERTEX pVertex,
  771. ULONG nVertex,
  772. PTRIVERTEX pPhysVert
  773. )
  774. {
  775. ULONG ulIndex;
  776. for (ulIndex = 0;ulIndex<nVertex;ulIndex++)
  777. {
  778. POINT pt;
  779. pt.x = pVertex[ulIndex].x;
  780. pt.y = pVertex[ulIndex].y;
  781. if (!LPtoDP(hdc,&pt,1))
  782. {
  783. return(FALSE);
  784. }
  785. pPhysVert[ulIndex].x = pt.x;
  786. pPhysVert[ulIndex].y = pt.y;
  787. pPhysVert[ulIndex].Red = pVertex[ulIndex].Red;
  788. pPhysVert[ulIndex].Green = pVertex[ulIndex].Green;
  789. pPhysVert[ulIndex].Blue = pVertex[ulIndex].Blue;
  790. pPhysVert[ulIndex].Alpha = pVertex[ulIndex].Alpha;
  791. }
  792. return(TRUE);
  793. }
  794. /******************************Public*Routine******************************\
  795. * pfnTriangleFillFunction
  796. *
  797. * look at format to decide if DIBSection should be drawn directly
  798. *
  799. * 32 bpp RGB
  800. * 32 bpp BGR
  801. * 24 bpp
  802. * 16 bpp 565
  803. * 16 bpp 555
  804. * (bitfields,8,4,1)
  805. *
  806. * Trangles are only filled in high color (no palette) surfaces
  807. *
  808. * Arguments:
  809. *
  810. * pDibInfo - information about destination surface
  811. * bReadable - Can dst surface be read?
  812. *
  813. * Return Value:
  814. *
  815. * PFN_TRIFILL - triangle filling routine
  816. *
  817. * History:
  818. *
  819. * 12/6/1996 Mark Enstrom [marke]
  820. *
  821. \**************************************************************************/
  822. PFN_TRIFILL
  823. pfnTriangleFillFunction(
  824. PDIBINFO pDibInfo,
  825. BOOL bReadable
  826. )
  827. {
  828. PFN_TRIFILL pfnRet = NULL;
  829. PULONG pulMasks = (PULONG)&pDibInfo->pbmi->bmiColors[0];
  830. //
  831. // 32 bpp RGB
  832. //
  833. if (!bReadable || (pDibInfo->flag & PRINTER_DC))
  834. {
  835. pfnRet = vFillTriDIBUnreadable;
  836. }
  837. else if (
  838. (pDibInfo->pbmi->bmiHeader.biBitCount == 32) &&
  839. (pDibInfo->pbmi->bmiHeader.biCompression == BI_RGB)
  840. )
  841. {
  842. pfnRet = vFillTriDIB32BGRA;
  843. }
  844. else if (
  845. (pDibInfo->pbmi->bmiHeader.biBitCount == 32) &&
  846. (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) &&
  847. (pulMasks[0] == 0xff0000) &&
  848. (pulMasks[1] == 0x00ff00) &&
  849. (pulMasks[2] == 0x0000ff)
  850. )
  851. {
  852. pfnRet = vFillTriDIB32BGRA;
  853. }
  854. else if (
  855. (pDibInfo->pbmi->bmiHeader.biBitCount == 32) &&
  856. (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS) &&
  857. (pulMasks[0] == 0x0000ff) &&
  858. (pulMasks[1] == 0x00ff00) &&
  859. (pulMasks[2] == 0xff0000)
  860. )
  861. {
  862. pfnRet = vFillTriDIB32RGB;
  863. }
  864. else if (
  865. (pDibInfo->pbmi->bmiHeader.biBitCount == 24) &&
  866. (pDibInfo->pbmi->bmiHeader.biCompression == BI_RGB)
  867. )
  868. {
  869. pfnRet = vFillTriDIB24RGB;
  870. }
  871. //
  872. // 16 BPP
  873. //
  874. else if (
  875. (pDibInfo->pbmi->bmiHeader.biBitCount == 16) &&
  876. (pDibInfo->pbmi->bmiHeader.biCompression == BI_BITFIELDS)
  877. )
  878. {
  879. //
  880. // 565,555
  881. //
  882. if (
  883. (pulMasks[0] == 0xf800) &&
  884. (pulMasks[1] == 0x07e0) &&
  885. (pulMasks[2] == 0x001f)
  886. )
  887. {
  888. pfnRet = vFillTriDIB16_565;
  889. }
  890. else if (
  891. (pulMasks[0] == 0x7c00) &&
  892. (pulMasks[1] == 0x03e0) &&
  893. (pulMasks[2] == 0x001f)
  894. )
  895. {
  896. pfnRet = vFillTriDIB16_555;
  897. }
  898. }
  899. else
  900. {
  901. pfnRet = vFillTriDIBUnreadable;
  902. }
  903. return(pfnRet);
  904. }
  905. /******************************Public*Routine******************************\
  906. * WinTriangleMesh
  907. * win95 emulation
  908. *
  909. * Arguments:
  910. *
  911. * hdc - dc
  912. * pVertex - vertex array
  913. * nVertex - elements in vertex array
  914. * pMesh - mesh array
  915. * nMesh - elements in mesh array
  916. * ulMode - drawing mode
  917. *
  918. * Return Value:
  919. *
  920. * status
  921. *
  922. * History:
  923. *
  924. * 12/3/1996 Mark Enstrom [marke]
  925. *
  926. \**************************************************************************/
  927. BOOL
  928. WinGradientFill(
  929. HDC hdc,
  930. PTRIVERTEX pLogVertex,
  931. ULONG nVertex,
  932. PVOID pMesh,
  933. ULONG nMesh,
  934. ULONG ulMode
  935. )
  936. {
  937. //
  938. // If the DC has a DIBSection selected, then draw direct to DIBSECTION.
  939. // else copy the rectangle needed from the dst to a 32bpp temp buffer,
  940. // draw into the buffer, then bitblt to dst.
  941. //
  942. // calc extents for drawing
  943. //
  944. // convert extents and points to physical
  945. //
  946. // if no global then
  947. // create memory DC with dibsection of correct size
  948. // copy dst into dibsection (if can't make clipping)
  949. // draw physical into dibsection
  950. // copy dibsection to destination
  951. //
  952. PBYTE pDIB;
  953. RECTL rclPhysMeshExt;
  954. RECTL rclPhysExt;
  955. RECTL rclLogExt;
  956. PRECTL prclClip;
  957. BOOL bStatus = FALSE;
  958. PFN_TRIFILL pfnTriFill;
  959. DIBINFO dibInfoDst;
  960. PALINFO palDst;
  961. ULONG ulDIBMode = SOURCE_GRADIENT_TRI;
  962. BOOL bReadable;
  963. POINTL ptlDitherOrg = {0,0};
  964. //
  965. // validate params and buffers
  966. //
  967. if ((ulMode & ~GRADIENT_FILL_OP_FLAG) != 0)
  968. {
  969. WARNING("NtGdiGradientFill: illegal parametets\n");
  970. return(FALSE);
  971. }
  972. if (
  973. (ulMode == GRADIENT_FILL_RECT_H) ||
  974. (ulMode == GRADIENT_FILL_RECT_V)
  975. )
  976. {
  977. ASSERTGDI(nMesh == 1,"Mesh must be one in GRADIENT_RECT");
  978. ulDIBMode = SOURCE_GRADIENT_RECT;
  979. }
  980. else if (ulMode != GRADIENT_FILL_TRIANGLE)
  981. {
  982. WARNING("Invalid mode in call to GradientFill\n");
  983. return(FALSE);
  984. }
  985. //
  986. // allocate space for copy of vertex data in device space
  987. //
  988. PTRIVERTEX pPhysVertex = (PTRIVERTEX)LOCALALLOC(nVertex * sizeof(TRIVERTEX));
  989. if (pPhysVertex != NULL)
  990. {
  991. //
  992. // convert to physical
  993. //
  994. bStatus = bConvertVertexToPhysical(hdc,pLogVertex,nVertex,pPhysVertex);
  995. if (bStatus)
  996. {
  997. //
  998. // get logical extents
  999. //
  1000. vCalcMeshExtent(pLogVertex,nVertex,pMesh,nMesh,ulMode,&rclLogExt);
  1001. //
  1002. // convert to physical extents
  1003. //
  1004. rclPhysExt = rclLogExt;
  1005. LPtoDP(hdc,(LPPOINT)&rclPhysExt,2);
  1006. //
  1007. // save unclipped mesh ext
  1008. //
  1009. rclPhysMeshExt = rclPhysExt;
  1010. //
  1011. // Set DIB information, convert to physical
  1012. //
  1013. bStatus = bInitDIBINFO(hdc,
  1014. rclLogExt.left,
  1015. rclLogExt.top,
  1016. rclLogExt.right - rclLogExt.left,
  1017. rclLogExt.bottom - rclLogExt.top,
  1018. &dibInfoDst);
  1019. if (bStatus)
  1020. {
  1021. //
  1022. // get a destination DIB. For RECT Mode, the destination is not read.
  1023. //
  1024. bSetupBitmapInfos(&dibInfoDst, NULL);
  1025. //
  1026. // DST can be printer DC
  1027. //
  1028. if (dibInfoDst.flag & PRINTER_DC)
  1029. {
  1030. bReadable = FALSE;
  1031. bStatus = TRUE;
  1032. }
  1033. else
  1034. {
  1035. bStatus = bGetDstDIBits(&dibInfoDst, &bReadable,ulDIBMode);
  1036. }
  1037. if (!((!bStatus) || (dibInfoDst.rclClipDC.left == dibInfoDst.rclClipDC.right)))
  1038. {
  1039. ULONG ulIndex;
  1040. if (bStatus)
  1041. {
  1042. if (dibInfoDst.hDIB)
  1043. {
  1044. //
  1045. // if temp surface has been allocated,
  1046. // subtract origin from points
  1047. //
  1048. for (ulIndex=0;ulIndex<nVertex;ulIndex++)
  1049. {
  1050. pPhysVertex[ulIndex].x -= dibInfoDst.ptlGradOffset.x;
  1051. pPhysVertex[ulIndex].y -= dibInfoDst.ptlGradOffset.y;
  1052. rclPhysMeshExt.left -= dibInfoDst.ptlGradOffset.x;
  1053. rclPhysMeshExt.right -= dibInfoDst.ptlGradOffset.x;
  1054. rclPhysMeshExt.top -= dibInfoDst.ptlGradOffset.y;
  1055. rclPhysMeshExt.bottom -= dibInfoDst.ptlGradOffset.y;
  1056. }
  1057. //
  1058. // clipping now in relation to temp DIB
  1059. //
  1060. rclPhysExt = dibInfoDst.rclDIB;
  1061. //
  1062. // adjust dither org
  1063. //
  1064. ptlDitherOrg.x = dibInfoDst.rclBounds.left;
  1065. ptlDitherOrg.y = dibInfoDst.rclBounds.top;
  1066. }
  1067. else
  1068. {
  1069. //
  1070. // clip extents to destination clip rect
  1071. //
  1072. if (rclPhysExt.left < dibInfoDst.rclClipDC.left)
  1073. {
  1074. rclPhysExt.left = dibInfoDst.rclClipDC.left;
  1075. }
  1076. if (rclPhysExt.right > dibInfoDst.rclClipDC.right)
  1077. {
  1078. rclPhysExt.right = dibInfoDst.rclClipDC.right;
  1079. }
  1080. if (rclPhysExt.top < dibInfoDst.rclClipDC.top)
  1081. {
  1082. rclPhysExt.top = dibInfoDst.rclClipDC.top;
  1083. }
  1084. if (rclPhysExt.bottom > dibInfoDst.rclClipDC.bottom)
  1085. {
  1086. rclPhysExt.bottom = dibInfoDst.rclClipDC.bottom;
  1087. }
  1088. }
  1089. if (
  1090. (ulMode == GRADIENT_FILL_RECT_H) ||
  1091. (ulMode == GRADIENT_FILL_RECT_V)
  1092. )
  1093. {
  1094. //
  1095. // draw gradient rectangles
  1096. //
  1097. bStatus = DIBGradientRect(hdc,
  1098. pPhysVertex,
  1099. nVertex,
  1100. (PGRADIENT_RECT)pMesh,
  1101. nMesh,
  1102. ulMode,
  1103. &rclPhysExt,
  1104. &dibInfoDst,
  1105. &ptlDitherOrg);
  1106. }
  1107. else if (ulMode == GRADIENT_FILL_TRIANGLE)
  1108. {
  1109. //
  1110. // draw triangles
  1111. //
  1112. bStatus = DIBTriangleMesh(hdc,
  1113. pPhysVertex,
  1114. nVertex,
  1115. (PGRADIENT_TRIANGLE)pMesh,
  1116. nMesh,
  1117. ulMode,
  1118. &rclPhysExt,
  1119. &rclPhysMeshExt,
  1120. &dibInfoDst,
  1121. &ptlDitherOrg,
  1122. bReadable);
  1123. }
  1124. //
  1125. // copy output to final dest if needed
  1126. //
  1127. if (bStatus && bReadable)
  1128. {
  1129. bStatus = bSendDIBINFO (hdc,&dibInfoDst);
  1130. }
  1131. }
  1132. }
  1133. }
  1134. vCleanupDIBINFO(&dibInfoDst);
  1135. }
  1136. LOCALFREE(pPhysVertex);
  1137. }
  1138. else
  1139. {
  1140. bStatus = FALSE;
  1141. }
  1142. return(bStatus);
  1143. }
  1144. #endif
  1145. /******************************Public*Routine******************************\
  1146. * GradientFill
  1147. *
  1148. * Draw gradient rectangle or triangle
  1149. *
  1150. * Arguments:
  1151. *
  1152. * hdc - dc
  1153. * pVertex - vertex array
  1154. * nVertex - elements in vertex array
  1155. * pMesh - mesh array
  1156. * nMesh - elements in mesh array
  1157. * ulMode - drawing mode
  1158. *
  1159. * Return Value:
  1160. *
  1161. * status
  1162. *
  1163. * History:
  1164. *
  1165. * 12/3/1996 Mark Enstrom [marke]
  1166. *
  1167. \**************************************************************************/
  1168. BOOL
  1169. GradientFill(
  1170. HDC hdc,
  1171. PTRIVERTEX pVertex,
  1172. ULONG nVertex,
  1173. PVOID pMesh,
  1174. ULONG nMesh,
  1175. ULONG ulMode
  1176. )
  1177. {
  1178. BOOL bRet;
  1179. #if !(_WIN32_WINNT >= 0x500)
  1180. //
  1181. // Convert GradientRect mesh into multiple single rect calls.
  1182. // This is more efficient in enulation since each rect covers
  1183. // dst surface (unless clipped)
  1184. //
  1185. if (
  1186. (
  1187. (ulMode == GRADIENT_FILL_RECT_H) ||
  1188. (ulMode == GRADIENT_FILL_RECT_V)
  1189. ) &&
  1190. ((nMesh > 1) || (nVertex > 2))
  1191. )
  1192. {
  1193. PGRADIENT_RECT pGradMesh = (PGRADIENT_RECT)pMesh;
  1194. GRADIENT_RECT GradRectFixed = {0,1};
  1195. TRIVERTEX TriVertex[2];
  1196. while (nMesh--)
  1197. {
  1198. //
  1199. // find two vertex structures referenced by GradientRect mesh
  1200. //
  1201. if (
  1202. (pGradMesh->UpperLeft < nVertex) &&
  1203. (pGradMesh->LowerRight < nVertex)
  1204. )
  1205. {
  1206. TriVertex[0] = pVertex[pGradMesh->UpperLeft];
  1207. TriVertex[1] = pVertex[pGradMesh->LowerRight];
  1208. bRet = gpfnGradientFill(hdc,
  1209. &TriVertex[0],
  1210. 2,
  1211. (PVOID)&GradRectFixed,
  1212. 1,
  1213. ulMode
  1214. );
  1215. }
  1216. else
  1217. {
  1218. bRet = FALSE;
  1219. }
  1220. if (!bRet)
  1221. {
  1222. break;
  1223. }
  1224. pGradMesh++;
  1225. }
  1226. }
  1227. else
  1228. {
  1229. bRet = gpfnGradientFill(hdc,
  1230. pVertex,
  1231. nVertex,
  1232. pMesh,
  1233. nMesh,
  1234. ulMode
  1235. );
  1236. }
  1237. #else
  1238. bRet = gpfnGradientFill(hdc,
  1239. pVertex,
  1240. nVertex,
  1241. pMesh,
  1242. nMesh,
  1243. ulMode
  1244. );
  1245. #endif
  1246. return(bRet);
  1247. }