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.

3022 lines
80 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: trimesh.cxx
  3. *
  4. * Gradient fill inplementation
  5. *
  6. * Created: 21-Jun-1996
  7. * Author: Mark Enstrom [marke]
  8. *
  9. * Copyright (c) 1996-1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. #include "solline.hxx"
  13. /**************************************************************************\
  14. * pfnDetermineTriangleFillRoutine
  15. *
  16. * determine scan line drawing routine for gradient fill
  17. *
  18. * Arguments:
  19. *
  20. * pSurfDst - dest surface
  21. * *ppal - dest palette
  22. * *pnfTriangleFill - return triangle fill routine
  23. * *pnfRectangleFill - return gradient fill routine
  24. *
  25. * Return Value:
  26. *
  27. * status
  28. *
  29. * History:
  30. *
  31. * 2/17/1997 Mark Enstrom [marke]
  32. *
  33. \**************************************************************************/
  34. BOOL
  35. bDetermineTriangleFillRoutine(
  36. PSURFACE pSurfDst,
  37. XEPALOBJ *ppal,
  38. PFN_GRADIENT *pnfTriangleFill,
  39. PFN_GRADRECT *pnfRectangleFill
  40. )
  41. {
  42. switch (pSurfDst->iFormat())
  43. {
  44. case BMF_1BPP:
  45. *pnfTriangleFill = vGradientFill1;
  46. *pnfRectangleFill = vFillGRectDIB1;
  47. break;
  48. case BMF_4BPP:
  49. *pnfTriangleFill = vGradientFill4;
  50. *pnfRectangleFill = vFillGRectDIB4;
  51. break;
  52. case BMF_8BPP:
  53. *pnfTriangleFill = vGradientFill8;
  54. *pnfRectangleFill = vFillGRectDIB8;
  55. break;
  56. case BMF_16BPP:
  57. {
  58. ULONG flR = ppal->flRed();
  59. ULONG flG = ppal->flGre();
  60. ULONG flB = ppal->flBlu();
  61. if (
  62. (flR == 0xf800) &&
  63. (flG == 0x07e0) &&
  64. (flB == 0x001f)
  65. )
  66. {
  67. *pnfTriangleFill = vGradientFill16_565;
  68. *pnfRectangleFill = vFillGRectDIB16_565;
  69. }
  70. else if (
  71. (flR == 0x7c00) &&
  72. (flG == 0x03e0) &&
  73. (flB == 0x001f)
  74. )
  75. {
  76. *pnfTriangleFill = vGradientFill16_555;
  77. *pnfRectangleFill = vFillGRectDIB16_555;
  78. }
  79. else
  80. {
  81. *pnfTriangleFill = vGradientFill16Bitfields;
  82. *pnfRectangleFill = vFillGRectDIB16Bitfields;
  83. }
  84. }
  85. break;
  86. case BMF_24BPP:
  87. if(ppal->bIsRGB())
  88. {
  89. *pnfTriangleFill = vGradientFill24RGB;
  90. *pnfRectangleFill = vFillGRectDIB24RGB;
  91. }
  92. else if(ppal->bIsBGR())
  93. {
  94. *pnfTriangleFill = vGradientFill24BGR;
  95. *pnfRectangleFill = vFillGRectDIB24BGR;
  96. }
  97. else
  98. {
  99. *pnfTriangleFill = vGradientFill24Bitfields;
  100. *pnfRectangleFill = vFillGRectDIB24Bitfields;
  101. }
  102. break;
  103. case BMF_32BPP:
  104. if (ppal->bIsRGB())
  105. {
  106. *pnfTriangleFill = vGradientFill32RGB;
  107. *pnfRectangleFill = vFillGRectDIB32RGB;
  108. }
  109. else if (ppal->bIsBGR())
  110. {
  111. *pnfTriangleFill = vGradientFill32BGRA;
  112. *pnfRectangleFill = vFillGRectDIB32BGRA;
  113. }
  114. else
  115. {
  116. *pnfTriangleFill = vGradientFill32Bitfields;
  117. *pnfRectangleFill = vFillGRectDIB32Bitfields;
  118. }
  119. break;
  120. }
  121. return(TRUE);
  122. }
  123. /******************************Public*Routine******************************\
  124. * vHorizontalLine
  125. *
  126. * Record information for horizontal line.
  127. * Colors are recorded as fixed point 8.56
  128. *
  129. * Arguments:
  130. *
  131. * pv1 - vertex 1
  132. * pv2 - vertex 2
  133. * ptData - triangle data
  134. * ptridda - dda data
  135. *
  136. * Return Value:
  137. *
  138. * none
  139. *
  140. * History:
  141. *
  142. * 11/20/1996 Mark Enstrom [marke]
  143. *
  144. \**************************************************************************/
  145. VOID
  146. vHorizontalLine(
  147. PTRIVERTEX pv1,
  148. PTRIVERTEX pv2,
  149. PTRIANGLEDATA ptData,
  150. PTRIDDA ptridda
  151. )
  152. {
  153. LONG yPosition = ptridda->N0;
  154. LONG yIndex = yPosition - ptData->y0;
  155. //
  156. // check if this line is whithin clipping in y
  157. //
  158. if (
  159. (yPosition >= ptData->rcl.top) &&
  160. (yPosition < ptData->rcl.bottom)
  161. )
  162. {
  163. //
  164. // find left edge
  165. //
  166. if (pv1->x <= pv2->x)
  167. {
  168. //
  169. // left edge
  170. //
  171. ptData->TriEdge[yIndex].xLeft = pv1->x;
  172. ptData->TriEdge[yIndex].llRed = ((LONGLONG)pv1->Red) << 48;
  173. ptData->TriEdge[yIndex].llGreen = ((LONGLONG)pv1->Green) << 48;
  174. ptData->TriEdge[yIndex].llBlue = ((LONGLONG)pv1->Blue) << 48;
  175. ptData->TriEdge[yIndex].llAlpha = ((LONGLONG)pv1->Alpha) << 48;
  176. //
  177. // right edge
  178. //
  179. ptData->TriEdge[yIndex].xRight = pv2->x;
  180. }
  181. else
  182. {
  183. //
  184. // left edge
  185. //
  186. ptData->TriEdge[yIndex].xLeft = pv2->x;
  187. ptData->TriEdge[yIndex].llRed = pv2->Red << 48;
  188. ptData->TriEdge[yIndex].llGreen = pv2->Green << 48;
  189. ptData->TriEdge[yIndex].llBlue = pv2->Blue << 48;
  190. ptData->TriEdge[yIndex].llAlpha = pv2->Alpha << 48;
  191. //
  192. // right edge
  193. //
  194. ptData->TriEdge[yIndex].xRight = pv1->x;
  195. }
  196. }
  197. }
  198. /******************************Public*Routine******************************\
  199. * vEdgeDDA
  200. *
  201. * Run line DDA down an edge of the triangle recording edge
  202. * position and color
  203. *
  204. * Arguments:
  205. *
  206. * ptData - triangle data
  207. * ptridda - line dda information
  208. *
  209. * Return Value:
  210. *
  211. * None
  212. *
  213. * History:
  214. *
  215. * 11/20/1996 Mark Enstrom [marke]
  216. *
  217. \**************************************************************************/
  218. VOID
  219. vEdgeDDA(
  220. PTRIANGLEDATA ptData,
  221. PTRIDDA ptridda
  222. )
  223. {
  224. LONG NumScanLines = ptridda->NumScanLines;
  225. LONG yIndex = ptridda->yIndex;
  226. LONGLONG llRed = ptridda->llRed;
  227. LONGLONG llGreen = ptridda->llGreen;
  228. LONGLONG llBlue = ptridda->llBlue;
  229. LONGLONG llAlpha = ptridda->llAlpha;
  230. LONG L = ptridda->L;
  231. LONG Rb = ptridda->Rb;
  232. //
  233. // Scan all lines, only record lines contained by
  234. // the clipping in ptData->rcl (y)
  235. //
  236. while (NumScanLines--)
  237. {
  238. //
  239. // check for and record left edge
  240. //
  241. if (yIndex >= 0)
  242. {
  243. if (L < ptData->TriEdge[yIndex].xLeft)
  244. {
  245. ptData->TriEdge[yIndex].xLeft = L;
  246. ptData->TriEdge[yIndex].llRed = llRed;
  247. ptData->TriEdge[yIndex].llGreen = llGreen;
  248. ptData->TriEdge[yIndex].llBlue = llBlue;
  249. ptData->TriEdge[yIndex].llAlpha = llAlpha;
  250. }
  251. if (L > ptData->TriEdge[yIndex].xRight)
  252. {
  253. ptData->TriEdge[yIndex].xRight = L;
  254. }
  255. }
  256. //
  257. // inc y by one scan line, inc x(L) by integer step
  258. // and inc error term by dR
  259. //
  260. yIndex++;
  261. L += ptridda->dL;
  262. Rb -= ptridda->dR;
  263. //
  264. // inc color components by y and integer x components
  265. //
  266. llRed += (ptridda->lldxyRed);
  267. llGreen += (ptridda->lldxyGreen);
  268. llBlue += (ptridda->lldxyBlue);
  269. llAlpha += (ptridda->lldxyAlpha);
  270. //
  271. // check for DDA error term overflow, add one
  272. // more step in x and color if true,
  273. // and correct error term
  274. //
  275. if (Rb < 0)
  276. {
  277. //
  278. // fraction step in x
  279. //
  280. L += ptridda->Linc;
  281. //
  282. // fraction step in color components
  283. //
  284. llRed += ptData->lldRdX;
  285. llGreen += ptData->lldGdX;
  286. llBlue += ptData->lldBdX;
  287. llAlpha += ptData->lldAdX;
  288. //
  289. // adjust error term
  290. //
  291. Rb += ptridda->dN;
  292. }
  293. }
  294. }
  295. /******************************Public*Routine******************************\
  296. * vCalulateLine
  297. *
  298. * calculate bounding line
  299. *
  300. * Arguments:
  301. *
  302. * pv1 - vertex 1
  303. * pv2 - vertex 2
  304. * ptData - triangle data
  305. *
  306. * Return Value:
  307. *
  308. * none
  309. *
  310. * History:
  311. *
  312. * 11/20/1996 Mark Enstrom [marke]
  313. *
  314. \**************************************************************************/
  315. VOID
  316. vCalculateLine(
  317. PTRIVERTEX pv1,
  318. PTRIVERTEX pv2,
  319. PTRIANGLEDATA ptData
  320. )
  321. {
  322. TRIDDA tridda;
  323. //
  324. // initial y component
  325. //
  326. tridda.lldxyRed = ptData->lldRdY;
  327. tridda.lldxyGreen = ptData->lldGdY;
  328. tridda.lldxyBlue = ptData->lldBdY;
  329. tridda.lldxyAlpha = ptData->lldAdY;
  330. //
  331. // N0 = integer y starting location
  332. // M0 = integer x starting location
  333. // dN = integer delta y
  334. // dM = integer delta x
  335. //
  336. // Arrange lines, must run DDA in positive delta y.
  337. //
  338. if (pv2->y >= pv1->y)
  339. {
  340. tridda.dN = pv2->y - pv1->y;
  341. tridda.dM = pv2->x - pv1->x;
  342. tridda.N0 = pv1->y;
  343. tridda.M0 = pv1->x;
  344. }
  345. else
  346. {
  347. tridda.dN = pv1->y - pv2->y;
  348. tridda.dM = pv1->x - pv2->x;
  349. tridda.N0 = pv2->y;
  350. tridda.M0 = pv2->x;
  351. }
  352. //
  353. // caclulate initial color value at stating vertex
  354. //
  355. tridda.llRed = ptData->lldRdY * (tridda.N0 - ptData->ptColorCalcOrg.y) +
  356. ptData->lldRdX * (tridda.M0 - ptData->ptColorCalcOrg.x) +
  357. ptData->llRA;
  358. tridda.llGreen = ptData->lldGdY * (tridda.N0 - ptData->ptColorCalcOrg.y) +
  359. ptData->lldGdX * (tridda.M0 - ptData->ptColorCalcOrg.x) +
  360. ptData->llGA;
  361. tridda.llBlue = ptData->lldBdY * (tridda.N0 - ptData->ptColorCalcOrg.y) +
  362. ptData->lldBdX * (tridda.M0 - ptData->ptColorCalcOrg.x) +
  363. ptData->llBA;
  364. tridda.llAlpha = ptData->lldAdY * (tridda.N0 - ptData->ptColorCalcOrg.y) +
  365. ptData->lldAdX * (tridda.M0 - ptData->ptColorCalcOrg.x) +
  366. ptData->llAA;
  367. //
  368. // Check for horizontal line, dN == 0 is a horizontal line.
  369. // In this case just record the end points.
  370. //
  371. if (tridda.dN == 0)
  372. {
  373. vHorizontalLine(pv1,pv2,ptData,&tridda);
  374. }
  375. else
  376. {
  377. LONGLONG l0,Frac;
  378. tridda.Linc = 1;
  379. //
  380. // yIndex is the offset into the edge array for
  381. // the current line. Calc number of scan lines
  382. // and maximum y position
  383. //
  384. tridda.yIndex = tridda.N0 - ptData->y0;
  385. tridda.NumScanLines = tridda.dN;
  386. LONG NMax = tridda.N0 + tridda.NumScanLines;
  387. //
  388. // make sure scan lines do not overrun buffer due to
  389. // clipping
  390. //
  391. if (
  392. (tridda.N0 > ptData->rcl.bottom) ||
  393. (NMax < ptData->rcl.top)
  394. )
  395. {
  396. //
  397. // nothing to draw
  398. //
  399. return;
  400. }
  401. else if (NMax > ptData->rcl.bottom)
  402. {
  403. tridda.NumScanLines = tridda.NumScanLines - (NMax - ptData->rcl.bottom);
  404. }
  405. tridda.j = tridda.N0;
  406. tridda.C = ((LONGLONG)tridda.M0 * (LONGLONG)tridda.dN) - ((LONGLONG)tridda.N0 * (LONGLONG)tridda.dM) -1;
  407. tridda.C = tridda.C + tridda.dN;
  408. LONGLONG LongL;
  409. if (tridda.dM > 0)
  410. {
  411. tridda.dL = tridda.dM / tridda.dN;
  412. tridda.dR = tridda.dM - tridda.dL * tridda.dN;
  413. }
  414. else if (tridda.dM < 0)
  415. {
  416. //
  417. // negative divide
  418. //
  419. LONG dLQ,dLR;
  420. tridda.dM = -tridda.dM;
  421. dLQ = (tridda.dM - 1) / tridda.dN;
  422. dLR = tridda.dM - 1 - (dLQ * tridda.dN);
  423. tridda.dL = -(dLQ + 1);
  424. tridda.dR = tridda.dN - dLR - 1;
  425. }
  426. else
  427. {
  428. //
  429. // dM = 0
  430. //
  431. tridda.dL = 0;
  432. tridda.dR = 0;
  433. }
  434. l0 = tridda.j * tridda.dL;
  435. LongL = tridda.j * tridda.dR + tridda.C;
  436. if (LongL > 0)
  437. {
  438. Frac = (LONG)(LongL/tridda.dN);
  439. }
  440. else if (LongL < 0)
  441. {
  442. LONGLONG Q = ((-LongL - 1)/tridda.dN);
  443. Frac = -(Q + 1);
  444. }
  445. else
  446. {
  447. Frac = 0;
  448. }
  449. tridda.R = (LONG)(LongL - (Frac * tridda.dN));
  450. tridda.L = (LONG)(l0 + Frac);
  451. tridda.Rb = tridda.dN - tridda.R - 1;
  452. //
  453. // Calculate color steps for dx
  454. //
  455. tridda.lldxyRed = tridda.lldxyRed + (ptData->lldRdX * tridda.dL);
  456. tridda.lldxyGreen = tridda.lldxyGreen + (ptData->lldGdX * tridda.dL);
  457. tridda.lldxyBlue = tridda.lldxyBlue + (ptData->lldBdX * tridda.dL);
  458. tridda.lldxyAlpha = tridda.lldxyAlpha + (ptData->lldAdX * tridda.dL);
  459. //
  460. // run edge dda
  461. //
  462. vEdgeDDA(ptData,&tridda);
  463. }
  464. }
  465. /**************************************************************************\
  466. * bCalulateColorGradient
  467. *
  468. * Calculate all color gradients
  469. *
  470. * Arguments:
  471. *
  472. * pv0,pv1,pv2 - triangle verticies
  473. * ptData - triangel data
  474. *
  475. * Return Value:
  476. *
  477. * status
  478. *
  479. * History:
  480. *
  481. * 5/22/1997 Kirk Olnyk [kirko]
  482. *
  483. \**************************************************************************/
  484. BOOL
  485. bCalulateColorGradient(
  486. PTRIVERTEX pv0,
  487. PTRIVERTEX pv1,
  488. PTRIVERTEX pv2,
  489. PTRIANGLEDATA ptData
  490. )
  491. {
  492. GRADSTRUCT g;
  493. LONGLONG d;
  494. LONG z;
  495. g.x1 = pv1->x;
  496. g.y1 = pv1->y;
  497. g.x2 = pv2->x;
  498. g.y2 = pv2->y;
  499. z = pv0->x;
  500. g.x1 -= z;
  501. g.x2 -= z;
  502. z = pv0->y;
  503. g.y1 -= z;
  504. g.y2 -= z;
  505. g.d = g.x1 * g.y2 - g.x2 * g.y1;
  506. LONG tx = MIN(g.x1,0);
  507. LONG ty = MIN(g.y1,0);
  508. g.m = MIN(tx,g.x2) + MIN(ty,g.y2);
  509. d = (LONGLONG) ABS(g.d);
  510. g.Q = (LONGLONG)TWO_TO_THE_48TH / d;
  511. g.R = (LONGLONG)TWO_TO_THE_48TH % d;
  512. ptData->ptColorCalcOrg.x = pv0->x;
  513. ptData->ptColorCalcOrg.y = pv0->y;
  514. bDoGradient( &ptData->lldRdX // &A
  515. , &ptData->lldRdY // &B
  516. , &ptData->llRA // &C
  517. , pv0->Red // R0
  518. , pv1->Red // R1
  519. , pv2->Red // R2
  520. , &g );
  521. bDoGradient( &ptData->lldGdX
  522. , &ptData->lldGdY
  523. , &ptData->llGA
  524. , pv0->Green
  525. , pv1->Green
  526. , pv2->Green
  527. , &g );
  528. bDoGradient( &ptData->lldBdX
  529. , &ptData->lldBdY
  530. , &ptData->llBA
  531. , pv0->Blue
  532. , pv1->Blue
  533. , pv2->Blue
  534. , &g );
  535. bDoGradient( &ptData->lldAdX
  536. , &ptData->lldAdY
  537. , &ptData->llAA
  538. , pv0->Alpha
  539. , pv1->Alpha
  540. , pv2->Alpha
  541. , &g );
  542. return(TRUE);
  543. }
  544. /**************************************************************************\
  545. * MDiv64
  546. * 64 bit mul-div
  547. *
  548. * Arguments:
  549. *
  550. * return = (a * b) / c
  551. *
  552. * Return Value:
  553. *
  554. *
  555. *
  556. * History:
  557. *
  558. * 5/22/1997 Kirk Olnyk [kirko]
  559. *
  560. \**************************************************************************/
  561. LONGLONG
  562. MDiv64(
  563. LONGLONG a,
  564. LONGLONG b,
  565. LONGLONG c)
  566. {
  567. LONGLONG Result;
  568. int isNegative=0;
  569. Result = 0;
  570. if (a != 0 && b != 0)
  571. {
  572. if (a < 0)
  573. {
  574. a = -a;
  575. isNegative = 1;
  576. }
  577. else if (b < 0)
  578. {
  579. b = -b;
  580. isNegative = 1;
  581. }
  582. a = a * b - (LONGLONG) isNegative;
  583. Result = a / c;
  584. if (isNegative)
  585. {
  586. Result = - Result - 1;
  587. }
  588. }
  589. return(Result);
  590. }
  591. /**************************************************************************\
  592. * bDoGradient
  593. *
  594. * calc color gradient for one color
  595. *
  596. * Arguments:
  597. *
  598. * pA
  599. * pB
  600. * pC
  601. * g0
  602. * g1
  603. * g2
  604. * pg
  605. *
  606. * Return Value:
  607. *
  608. * status
  609. *
  610. * History:
  611. *
  612. * 5/22/1997 Kirk Olnyk [kirko]
  613. *
  614. \**************************************************************************/
  615. BOOL
  616. bDoGradient(
  617. LONGLONG *pA,
  618. LONGLONG *pB,
  619. LONGLONG *pC,
  620. LONG g0,
  621. LONG g1,
  622. LONG g2,
  623. GRADSTRUCT *pg
  624. )
  625. {
  626. BOOL bDiv(LONGLONG*, LONGLONG, LONG);
  627. LONGLONG a,b,c,d;
  628. g1 = g1 - g0;
  629. g2 = g2 - g0;
  630. a = g1 * pg->y2 - g2 * pg->y1;
  631. b = g2 * pg->x1 - g1 * pg->x2;
  632. d = pg->d;
  633. if (d < 0)
  634. {
  635. a = -a;
  636. b = -b;
  637. d = -d;
  638. }
  639. *pA = pg->Q * a + MDiv64(a, pg->R, d);
  640. *pB = pg->Q * b + MDiv64(b, pg->R, d);
  641. c = (d >> 1) + 1;
  642. a = c * pg->R - pg->m - 1;
  643. a /= d;
  644. a += c * pg->Q;
  645. a += pg->m;
  646. *pC = a + (((LONGLONG) g0) << 48);
  647. return(TRUE);
  648. }
  649. /**************************************************************************\
  650. * lCalculateTriangleArea
  651. *
  652. * Arguments:
  653. *
  654. * pv0 - vertex
  655. * pv1 - vertex
  656. * pv2 - vertex
  657. * ptData - triangle data
  658. *
  659. * Return Value:
  660. *
  661. * < 0 = negative area
  662. * 0 = 0 area
  663. * > 0 = positive area
  664. *
  665. * History:
  666. *
  667. * 2/26/1997 Mark Enstrom [marke]
  668. *
  669. \**************************************************************************/
  670. LONG
  671. lCalculateTriangleArea(
  672. PTRIVERTEX pv0,
  673. PTRIVERTEX pv1,
  674. PTRIVERTEX pv2,
  675. PTRIANGLEDATA ptData
  676. )
  677. {
  678. LONG lRet;
  679. //
  680. // calc area, color gradients in x,y
  681. //
  682. // area = (v2-v0) X (v1 - v2)
  683. //
  684. LONGLONG v12x = pv1->x - pv2->x;
  685. LONGLONG v12y = pv1->y - pv2->y;
  686. LONGLONG v02x = pv0->x - pv2->x;
  687. LONGLONG v02y = pv0->y - pv2->y;
  688. LONGLONG Area = (v12y * v02x) - (v12x * v02y);
  689. if (Area == 0)
  690. {
  691. lRet = 0;
  692. }
  693. else if (Area > 0)
  694. {
  695. lRet = 1;
  696. if (ptData != NULL)
  697. {
  698. ptData->Area = Area;
  699. }
  700. }
  701. else
  702. {
  703. lRet = -1;
  704. }
  705. return(lRet);
  706. }
  707. /**************************************************************************\
  708. * LIMIT_COLOR
  709. *
  710. * Actual input colors are limited to 0x0000 - 0xff00
  711. * 256 * (0x00 - 0xff)
  712. *
  713. * Arguments:
  714. *
  715. * pv - vertex
  716. *
  717. * History:
  718. *
  719. * 2/26/1997 Mark Enstrom [marke]
  720. *
  721. \**************************************************************************/
  722. #define LIMIT_COLOR(pv) \
  723. \
  724. if (pv->Red > 0xff00) \
  725. { \
  726. pv->Red = 0xff00; \
  727. } \
  728. \
  729. if (pv->Green > 0xff00) \
  730. { \
  731. pv->Green = 0xff00; \
  732. } \
  733. \
  734. if (pv->Blue > 0xff00) \
  735. { \
  736. pv->Blue = 0xff00; \
  737. }
  738. /******************************Public*Routine******************************\
  739. * bCalculateTriangle
  740. *
  741. * if triangle is too largre, break it in into 2 triangles and call this
  742. * routine on each (max recursion ~= 16)
  743. *
  744. * Calculate color gradients, then scan the three lines that make up the
  745. * triangle. Fill out a structure that can later be used to fill in the
  746. * interior of the triangle.
  747. *
  748. * Arguments:
  749. *
  750. * pSurfDst - destination surface
  751. * pInV0 - vertex
  752. * pInV1 - vertex
  753. * pInV2 - vertex
  754. * ptData - triangle data
  755. * pfnG - surface gradient draw routine
  756. *
  757. * Return Value:
  758. *
  759. * status
  760. *
  761. * History:
  762. *
  763. * 17-Jul-1996 -by- Mark Enstrom [marke]
  764. *
  765. \**************************************************************************/
  766. BOOL
  767. bCalculateAndDrawTriangle(
  768. PSURFACE pSurfDst,
  769. PTRIVERTEX pInV0,
  770. PTRIVERTEX pInV1,
  771. PTRIVERTEX pInV2,
  772. PTRIANGLEDATA ptData,
  773. PFN_GRADIENT pfnG
  774. )
  775. {
  776. BOOL bStatus = TRUE;
  777. LONG index;
  778. LONG lStatus;
  779. PTRIVERTEX pv0 = pInV0;
  780. PTRIVERTEX pv1 = pInV1;
  781. PTRIVERTEX pv2 = pInV2;
  782. {
  783. PTRIVERTEX pvt;
  784. //
  785. // sort in y for line processing
  786. //
  787. if (pv0->y > pv1->y)
  788. {
  789. SWAP_VERTEX(pv0,pv1,pvt);
  790. }
  791. if (pv1->y > pv2->y)
  792. {
  793. SWAP_VERTEX(pv1,pv2,pvt);
  794. }
  795. if (pv0->y > pv1->y)
  796. {
  797. SWAP_VERTEX(pv0,pv1,pvt);
  798. }
  799. lStatus = lCalculateTriangleArea(pv0,pv1,pv2,ptData);
  800. //
  801. // if area is zero then this is a degenerate triangle
  802. //
  803. if (lStatus == 0)
  804. {
  805. return(FALSE);
  806. }
  807. else if (lStatus <0)
  808. {
  809. //
  810. // negative area, swap pv1 and pv2 and recalcualte
  811. //
  812. SWAP_VERTEX(pv1,pv2,pvt);
  813. lStatus = lCalculateTriangleArea(pv0,pv1,pv2,ptData);
  814. if (lStatus == 0)
  815. {
  816. return(FALSE);
  817. }
  818. else if (lStatus <0)
  819. {
  820. WARNING1("Triangle Area still negative after vertex swap\n");
  821. return(FALSE);
  822. }
  823. }
  824. //
  825. // calc min and max drawing y
  826. //
  827. ptData->y0 = MAX(pv0->y,ptData->rcl.top);
  828. LONG MaxY = MAX(pv1->y,pv2->y);
  829. ptData->y1 = MIN(MaxY,ptData->rcl.bottom);
  830. {
  831. //
  832. // init ptdata
  833. //
  834. LONG lIndex;
  835. for (lIndex=0;lIndex<(ptData->y1-ptData->y0);lIndex++)
  836. {
  837. ptData->TriEdge[lIndex].xLeft = LONG_MAX;
  838. ptData->TriEdge[lIndex].xRight = LONG_MIN;
  839. }
  840. }
  841. //
  842. // calculate color gradients for each color. There is a little redundant
  843. // work here with calculation of deltas. Should make this one call or
  844. // do it in place.
  845. //
  846. LIMIT_COLOR(pv0);
  847. LIMIT_COLOR(pv1);
  848. LIMIT_COLOR(pv2);
  849. bCalulateColorGradient(pv0,pv1,pv2,ptData);
  850. //
  851. // draw lines into data array
  852. //
  853. vCalculateLine(pv0,pv1,ptData);
  854. vCalculateLine(pv1,pv2,ptData);
  855. vCalculateLine(pv2,pv0,ptData);
  856. pfnG(pSurfDst,ptData);
  857. }
  858. return(bStatus);
  859. }
  860. /**************************************************************************\
  861. * bIsTriangleInBounds
  862. *
  863. * Is triangle inside bounding rect
  864. *
  865. * Arguments:
  866. *
  867. * pInV0 - vertex 0
  868. * pInV1 - vertex 1
  869. * pInV2 - vertex 2
  870. * ptData - triangle data
  871. *
  872. * Return Value:
  873. *
  874. * TRUE in any of the triangle is contained in bounding rect
  875. *
  876. * History:
  877. *
  878. * 5/8/1997 Mark Enstrom [marke]
  879. *
  880. \**************************************************************************/
  881. BOOL
  882. bIsTriangleInBounds(
  883. PTRIVERTEX pInV0,
  884. PTRIVERTEX pInV1,
  885. PTRIVERTEX pInV2,
  886. PTRIANGLEDATA ptData
  887. )
  888. {
  889. PRECTL prclClip = &ptData->rcl;
  890. RECTL rclTri;
  891. rclTri.left = MIN(pInV0->x,pInV1->x);
  892. rclTri.right = MAX(pInV0->x,pInV1->x);
  893. rclTri.top = MIN(pInV0->y,pInV1->y);
  894. rclTri.bottom = MAX(pInV0->y,pInV1->y);
  895. rclTri.left = MIN(rclTri.left,pInV2->x);
  896. rclTri.right = MAX(rclTri.right,pInV2->x);
  897. rclTri.top = MIN(rclTri.top,pInV2->y);
  898. rclTri.bottom = MAX(rclTri.bottom,pInV2->y);
  899. if ((rclTri.left >= prclClip->right) ||
  900. (rclTri.right <= prclClip->left) ||
  901. (rclTri.top >= prclClip->bottom) ||
  902. (rclTri.bottom <= prclClip->top))
  903. {
  904. return(FALSE);
  905. }
  906. return(TRUE);
  907. }
  908. /**************************************************************************\
  909. * bTriangleNeedSplit
  910. * determine whether triangle needs split
  911. *
  912. * Arguments:
  913. *
  914. * pv0,pv1,pv2 - triangle vertex
  915. *
  916. * Return Value:
  917. *
  918. * TRUE if triangle needs to be split
  919. *
  920. * History:
  921. *
  922. * 5/8/1997 Mark Enstrom [marke]
  923. *
  924. \**************************************************************************/
  925. BOOL
  926. bTriangleNeedsSplit(
  927. PTRIVERTEX pv0,
  928. PTRIVERTEX pv1,
  929. PTRIVERTEX pv2
  930. )
  931. {
  932. //
  933. // calc dx,dy for each leg
  934. //
  935. LONG dx01 = ABS(pv0->x - pv1->x);
  936. LONG dy01 = ABS(pv0->y - pv1->y);
  937. LONG dx02 = ABS(pv0->x - pv2->x);
  938. LONG dy02 = ABS(pv0->y - pv2->y);
  939. LONG dx12 = ABS(pv1->x - pv2->x);
  940. LONG dy12 = ABS(pv1->y - pv2->y);
  941. //
  942. // if any length is longer than max, break triangle into two pieces
  943. // and call this routine for each
  944. //
  945. if (
  946. (
  947. (dx01 > MAX_EDGE_LENGTH) || (dy01 > MAX_EDGE_LENGTH) ||
  948. (dx02 > MAX_EDGE_LENGTH) || (dy02 > MAX_EDGE_LENGTH) ||
  949. (dx12 > MAX_EDGE_LENGTH) || (dy12 > MAX_EDGE_LENGTH)
  950. )
  951. )
  952. {
  953. return(TRUE);
  954. }
  955. return(FALSE);
  956. }
  957. /**************************************************************************\
  958. * bSplitTriangle
  959. * Determine is triangle must be split.
  960. * Split triangle along longest edge
  961. *
  962. * Arguments:
  963. *
  964. * pv0,pv1,pv2 - triangle
  965. * pvNew - new vertex
  966. * pGrad - mesh
  967. *
  968. * Return Value:
  969. *
  970. * TRUE if split, FALSE otherwise
  971. *
  972. * History:
  973. *
  974. * 5/8/1997 Mark Enstrom [marke]
  975. *
  976. \**************************************************************************/
  977. BOOL
  978. bSplitTriangle(
  979. PTRIVERTEX pVert,
  980. PULONG pFreeVert,
  981. PGRADIENT_TRIANGLE pMesh,
  982. PULONG pFreeMesh,
  983. PULONG pRecurseLevel
  984. )
  985. {
  986. BOOL bStatus = FALSE;
  987. ULONG CurrentMesh = (*pFreeMesh) - 1;
  988. ULONG ulTM0 = pMesh[CurrentMesh].Vertex1;
  989. ULONG ulTM1 = pMesh[CurrentMesh].Vertex2;
  990. ULONG ulTM2 = pMesh[CurrentMesh].Vertex3;
  991. PTRIVERTEX pv0 = &pVert[ulTM0];
  992. PTRIVERTEX pv1 = &pVert[ulTM1];
  993. PTRIVERTEX pv2 = &pVert[ulTM2];
  994. PTRIVERTEX pvT0 = pv0;
  995. PTRIVERTEX pvT1 = pv1;
  996. PTRIVERTEX pvT2 = pv2;
  997. TRIVERTEX triNew;
  998. //
  999. // find longest edge
  1000. //
  1001. LONGLONG dx01 = ABS(pv0->x - pv1->x);
  1002. LONGLONG dy01 = ABS(pv0->y - pv1->y);
  1003. LONGLONG dx02 = ABS(pv0->x - pv2->x);
  1004. LONGLONG dy02 = ABS(pv0->y - pv2->y);
  1005. LONGLONG dx12 = ABS(pv1->x - pv2->x);
  1006. LONGLONG dy12 = ABS(pv1->y - pv2->y);
  1007. //
  1008. // determine if triangle needs to be split
  1009. //
  1010. if (
  1011. (
  1012. (dx01 > MAX_EDGE_LENGTH) || (dy01 > MAX_EDGE_LENGTH) ||
  1013. (dx02 > MAX_EDGE_LENGTH) || (dy02 > MAX_EDGE_LENGTH) ||
  1014. (dx12 > MAX_EDGE_LENGTH) || (dy12 > MAX_EDGE_LENGTH)
  1015. )
  1016. )
  1017. {
  1018. //
  1019. // make sure this is a triangle
  1020. //
  1021. if (lCalculateTriangleArea(pv0,pv1,pv2,NULL) != 0)
  1022. {
  1023. //
  1024. // Find longest edge, swap verticies so edge 0-1 is
  1025. // longest.
  1026. //
  1027. LONGLONG d01Max = dx01 * dx01 + dy01 * dy01;
  1028. LONGLONG d02Max = dx02 * dx02 + dy02 * dy02;
  1029. LONGLONG d12Max = dx12 * dx12 + dy12 * dy12;
  1030. if (d01Max > d02Max)
  1031. {
  1032. if (d01Max > d12Max)
  1033. {
  1034. //
  1035. // d01 largest, default
  1036. //
  1037. }
  1038. else
  1039. {
  1040. //
  1041. // d12 largest, swap 0 and 2
  1042. //
  1043. pvT0 = pv2;
  1044. pvT2 = pv0;
  1045. ulTM0 = pMesh[CurrentMesh].Vertex3;
  1046. ulTM2 = pMesh[CurrentMesh].Vertex1;
  1047. }
  1048. }
  1049. else
  1050. {
  1051. if (d02Max > d12Max)
  1052. {
  1053. //
  1054. // d02 largest, swap 1,2
  1055. //
  1056. pvT1 = pv2;
  1057. pvT2 = pv1;
  1058. ulTM1 = pMesh[CurrentMesh].Vertex3;
  1059. ulTM2 = pMesh[CurrentMesh].Vertex2;
  1060. }
  1061. else
  1062. {
  1063. //
  1064. // d12 largest, swap 0,2
  1065. //
  1066. pvT0 = pv2;
  1067. pvT2 = pv0;
  1068. ulTM0 = pMesh[CurrentMesh].Vertex3;
  1069. ulTM2 = pMesh[CurrentMesh].Vertex1;
  1070. }
  1071. }
  1072. //
  1073. // 2 new triangles 0,2,N and 1,2,N (float)
  1074. //
  1075. {
  1076. EFLOAT fpA,fpB;
  1077. EFLOAT fTwo;
  1078. LONG lTemp;
  1079. fTwo = (LONG)2;
  1080. fpA = pvT0->x;
  1081. fpB = pvT1->x;
  1082. fpB-=(fpA);
  1083. fpB/=(fTwo);
  1084. fpA+=(fpB);
  1085. fpA.bEfToL(triNew.x);
  1086. fpA = pvT0->y;
  1087. fpB = pvT1->y;
  1088. fpB-=(fpA);
  1089. fpB/=(fTwo);
  1090. fpA+=(fpB);
  1091. fpA.bEfToL(triNew.y);
  1092. fpA = (LONG)pvT0->Red;
  1093. fpB = (LONG)pvT1->Red;
  1094. fpB-=(fpA);
  1095. fpB/=(fTwo);
  1096. fpA+=(fpB);
  1097. fpA.bEfToL(lTemp);
  1098. triNew.Red = (USHORT)lTemp;
  1099. fpA = (LONG)pvT0->Green;
  1100. fpB = (LONG)pvT1->Green;
  1101. fpB-=(fpA);
  1102. fpB/=(fTwo);
  1103. fpA+=(fpB);
  1104. fpA.bEfToL(lTemp);
  1105. triNew.Green = (USHORT)lTemp;
  1106. fpA = (LONG)pvT0->Blue;
  1107. fpB = (LONG)pvT1->Blue;
  1108. fpB-=(fpA);
  1109. fpB/=(fTwo);
  1110. fpA+=(fpB);
  1111. fpA.bEfToL(lTemp);
  1112. triNew.Blue = (USHORT)lTemp;
  1113. fpA = (LONG)pvT0->Alpha;
  1114. fpB = (LONG)pvT1->Alpha;
  1115. fpB-=(fpA);
  1116. fpB/=(fTwo);
  1117. fpA+=(fpB);
  1118. fpA.bEfToL(lTemp);
  1119. triNew.Alpha = (USHORT)lTemp;
  1120. }
  1121. //
  1122. // add new entry to vertex array and two new entries to mesh array
  1123. //
  1124. // 0,2,New and 1,2,New
  1125. //
  1126. ULONG FreeVert = *pFreeVert;
  1127. ULONG FreeMesh = *pFreeMesh;
  1128. pVert[FreeVert] = triNew;
  1129. pMesh[FreeMesh].Vertex1 = ulTM0;
  1130. pMesh[FreeMesh].Vertex2 = ulTM2;
  1131. pMesh[FreeMesh].Vertex3 = FreeVert;
  1132. pMesh[FreeMesh+1].Vertex1 = ulTM1;
  1133. pMesh[FreeMesh+1].Vertex2 = ulTM2;
  1134. pMesh[FreeMesh+1].Vertex3 = FreeVert;
  1135. pRecurseLevel[FreeMesh] = 1;
  1136. pRecurseLevel[FreeMesh+1] = 0;
  1137. *pFreeMesh += 2;
  1138. *pFreeVert += 1;
  1139. bStatus = TRUE;
  1140. }
  1141. else
  1142. {
  1143. WARNING("bSplitTriangle:Error: triangle area = 0\n\n");
  1144. }
  1145. }
  1146. return(bStatus);
  1147. }
  1148. /**************************************************************************\
  1149. * bTriangleMesh
  1150. *
  1151. * Draw each triangle. If triangle is too big, then split.
  1152. *
  1153. * Arguments:
  1154. *
  1155. * pSurfDst - destination surface
  1156. * pxlo - xlate
  1157. * pVertex - pointer to vertex array
  1158. * nVertex - elements in vertex array
  1159. * pMesh - pointer to mesh array
  1160. * nMesh - elements in mesh array
  1161. * ulMode - draw mode
  1162. * prclClip - clip rect
  1163. * prclMeshExtents - triangle extents rect
  1164. * pptlDitherOrg - dither org
  1165. *
  1166. * Return Value:
  1167. *
  1168. * Status
  1169. *
  1170. * History:
  1171. *
  1172. * 5/22/1997 Mark Enstrom [marke]
  1173. *
  1174. \**************************************************************************/
  1175. BOOL
  1176. bTriangleMesh(
  1177. PSURFACE pSurfDst,
  1178. XLATEOBJ *pxlo,
  1179. PTRIVERTEX pVertex,
  1180. ULONG nVertex,
  1181. PGRADIENT_TRIANGLE pMesh,
  1182. ULONG nMesh,
  1183. ULONG ulMode,
  1184. PRECTL prclClip,
  1185. PRECTL prclMeshExtents,
  1186. PPOINTL pptlDitherOrg
  1187. )
  1188. {
  1189. PFN_GRADIENT pfnG;
  1190. PFN_GRADRECT pfnTemp;
  1191. BOOL bStatus = TRUE;
  1192. LONG dyTri = prclClip->bottom - prclClip->top;
  1193. PTRIANGLEDATA ptData;
  1194. //
  1195. // allocate structure to hold scan line data for all triangles
  1196. // drawn during this call
  1197. //
  1198. ptData = (PTRIANGLEDATA)PALLOCMEM(sizeof(TRIANGLEDATA) + (dyTri-1) * sizeof(TRIEDGE),'gdEg');
  1199. if (ptData)
  1200. {
  1201. //
  1202. // find a palette for the output surface
  1203. //
  1204. XEPALOBJ epal(pSurfDst->ppal());
  1205. if (!epal.bValid())
  1206. {
  1207. PDEVOBJ pdo(pSurfDst->hdev());
  1208. epal.ppalSet(pdo.ppalSurf());
  1209. }
  1210. if (epal.bValid())
  1211. {
  1212. //
  1213. // find out scan line routine to use to draw pixels
  1214. //
  1215. bDetermineTriangleFillRoutine(pSurfDst,&epal,&pfnG,&pfnTemp);
  1216. //
  1217. // Init global data
  1218. //
  1219. ptData->rcl = *prclClip;
  1220. ptData->DrawMode = ulMode;
  1221. ptData->pxlo = pxlo;
  1222. ptData->ppalDstSurf = &epal;
  1223. ptData->ptDitherOrg = *pptlDitherOrg;
  1224. //
  1225. // if triangle does not need to be split, draw each one.
  1226. // Triangles need to be split if any edge exceeds a length
  1227. // that will cause math problems.
  1228. //
  1229. if (
  1230. ((prclMeshExtents->right - prclMeshExtents->left) < MAX_EDGE_LENGTH) &&
  1231. ((prclMeshExtents->bottom - prclMeshExtents->top) < MAX_EDGE_LENGTH)
  1232. )
  1233. {
  1234. //
  1235. // no split needed
  1236. //
  1237. ULONG ulIndex;
  1238. for (ulIndex = 0;ulIndex<nMesh;ulIndex++)
  1239. {
  1240. PTRIVERTEX pv0 = &pVertex[pMesh[ulIndex].Vertex1];
  1241. PTRIVERTEX pv1 = &pVertex[pMesh[ulIndex].Vertex2];
  1242. PTRIVERTEX pv2 = &pVertex[pMesh[ulIndex].Vertex3];
  1243. if (bIsTriangleInBounds(pv0,pv1,pv2,ptData))
  1244. {
  1245. bStatus = bCalculateAndDrawTriangle(pSurfDst,pv0,pv1,pv2,ptData,pfnG);
  1246. }
  1247. }
  1248. }
  1249. else
  1250. {
  1251. //
  1252. // some triangles exceed maximum length, need to scan through triangles
  1253. // and split triangles that exceed maximum edge length. This routine
  1254. // works in a pseudo recursive manner, by splitting one triangle, then
  1255. // splitting one of those 2 and so on. maximum depth is:
  1256. //
  1257. // 2 * ((log(2)(max dx,dy)) - 10)
  1258. //
  1259. // 10 = log(2) MAX_EDGE_LENGTH (2^14)
  1260. // LOG(2)(2^28) = 28
  1261. //
  1262. // 2 * (28 - 14) = 28
  1263. //
  1264. ULONG ulMaxVertex = nVertex + 28;
  1265. ULONG ulMaxMesh = nMesh + 28;
  1266. PBYTE pAlloc = NULL;
  1267. ULONG ulSizeAlloc = (sizeof(TRIVERTEX) * ulMaxVertex) +
  1268. (sizeof(GRADIENT_TRIANGLE) * ulMaxMesh) +
  1269. (sizeof(ULONG) * ulMaxMesh);
  1270. pAlloc = (PBYTE)PALLOCNOZ(ulSizeAlloc,'tvtG');
  1271. if (pAlloc != NULL)
  1272. {
  1273. //
  1274. // assign buffers
  1275. //
  1276. PTRIVERTEX pTempVertex = (PTRIVERTEX)pAlloc;
  1277. PGRADIENT_TRIANGLE pTempMesh = (PGRADIENT_TRIANGLE)(pAlloc + (sizeof(TRIVERTEX) * ulMaxVertex));
  1278. PULONG pRecurse = (PULONG)((PBYTE)pTempMesh + (sizeof(GRADIENT_TRIANGLE) * ulMaxMesh));
  1279. //
  1280. // copy initial triangle information
  1281. //
  1282. memcpy(pTempVertex,pVertex,sizeof(TRIVERTEX) * nVertex);
  1283. memcpy(pTempMesh,pMesh,sizeof(TRIVERTEX) * nMesh);
  1284. memset(pRecurse,0,nMesh * sizeof(ULONG));
  1285. //
  1286. // next free location in vertex and mesh arrays
  1287. //
  1288. ASSERTGDI(nMesh > 0, "bTriangleMesh: bad nMesh\n");
  1289. ULONG FreeVertex = nVertex;
  1290. ULONG FreeMesh = nMesh;
  1291. do
  1292. {
  1293. BOOL bSplit = FALSE;
  1294. //
  1295. // always operate on the last triangle in array
  1296. //
  1297. ULONG CurrentMesh = FreeMesh - 1;
  1298. //
  1299. // validate mesh pointers
  1300. //
  1301. if (
  1302. (pTempMesh[CurrentMesh].Vertex1 >= ulMaxVertex) ||
  1303. (pTempMesh[CurrentMesh].Vertex2 >= ulMaxVertex) ||
  1304. (pTempMesh[CurrentMesh].Vertex3 >= ulMaxVertex)
  1305. )
  1306. {
  1307. RIP("Error in triangle split routine:Vertex out of range\n");
  1308. break;
  1309. }
  1310. PTRIVERTEX pv0 = &pTempVertex[pTempMesh[CurrentMesh].Vertex1];
  1311. PTRIVERTEX pv1 = &pTempVertex[pTempMesh[CurrentMesh].Vertex2];
  1312. PTRIVERTEX pv2 = &pTempVertex[pTempMesh[CurrentMesh].Vertex3];
  1313. //
  1314. // check if triangle boundary is inside clip rect
  1315. //
  1316. if (bIsTriangleInBounds(pv0,pv1,pv2,ptData))
  1317. {
  1318. bSplit = bSplitTriangle(pTempVertex,&FreeVertex,pTempMesh,&FreeMesh,pRecurse);
  1319. if (!bSplit)
  1320. {
  1321. //
  1322. // draw triangle
  1323. //
  1324. bStatus = bCalculateAndDrawTriangle(pSurfDst,pv0,pv1,pv2,ptData,pfnG);
  1325. }
  1326. else
  1327. {
  1328. //
  1329. // validate array indcies
  1330. //
  1331. if ((FreeVertex > ulMaxVertex) ||
  1332. (FreeMesh > ulMaxMesh))
  1333. {
  1334. RIP("Error in triangle split routine: indicies out of range\n");
  1335. break;
  1336. }
  1337. }
  1338. }
  1339. //
  1340. // if triangle was not split, then remove from list.
  1341. //
  1342. if (!bSplit)
  1343. {
  1344. //
  1345. // remove triangle just drawn. If this is the second triangle of a
  1346. // split, then remove the added vertex and the original triangle as
  1347. // well
  1348. //
  1349. do
  1350. {
  1351. FreeMesh--;
  1352. if (pRecurse[FreeMesh])
  1353. {
  1354. FreeVertex--;
  1355. }
  1356. } while ((FreeMesh != 0) && (pRecurse[FreeMesh] == 1));
  1357. }
  1358. } while (FreeMesh != 0);
  1359. VFREEMEM(pAlloc);
  1360. }
  1361. else
  1362. {
  1363. WARNING1("Memory allocation failed for temp triangle buffers\n");
  1364. bStatus = FALSE;
  1365. }
  1366. }
  1367. }
  1368. else
  1369. {
  1370. RIP("EngGradientFill:Error reading palette from surface\n");
  1371. bStatus = FALSE;
  1372. }
  1373. //
  1374. // free triangle data buffer
  1375. //
  1376. VFREEMEM(ptData);
  1377. }
  1378. else
  1379. {
  1380. bStatus = FALSE;
  1381. }
  1382. return(bStatus);
  1383. }
  1384. /**************************************************************************\
  1385. * vCalcRectOffsets
  1386. *
  1387. * calc params for gradient rect
  1388. *
  1389. * Arguments:
  1390. *
  1391. * pGradRect - gradietn rect data
  1392. *
  1393. * Return Value:
  1394. *
  1395. * status
  1396. *
  1397. * History:
  1398. *
  1399. * 2/14/1997 Mark Enstrom [marke]
  1400. *
  1401. \**************************************************************************/
  1402. BOOL
  1403. bCalcGradientRectOffsets(
  1404. PGRADIENTRECTDATA pGradRect
  1405. )
  1406. {
  1407. LONG yScanTop = MAX(pGradRect->rclClip.top,pGradRect->rclGradient.top);
  1408. LONG yScanBottom = MIN(pGradRect->rclClip.bottom,pGradRect->rclGradient.bottom);
  1409. LONG yScanLeft = MAX(pGradRect->rclClip.left,pGradRect->rclGradient.left);
  1410. LONG yScanRight = MIN(pGradRect->rclClip.right,pGradRect->rclGradient.right);
  1411. //
  1412. // calc actual widht, check for early out
  1413. //
  1414. pGradRect->ptDraw.x = yScanLeft;
  1415. pGradRect->ptDraw.y = yScanTop;
  1416. pGradRect->szDraw.cx = yScanRight - yScanLeft;
  1417. pGradRect->szDraw.cy = yScanBottom - yScanTop;
  1418. LONG ltemp = pGradRect->rclClip.left - pGradRect->rclGradient.left;
  1419. if (ltemp <= 0)
  1420. {
  1421. ltemp = 0;
  1422. }
  1423. pGradRect->xScanAdjust = ltemp;
  1424. ltemp = pGradRect->rclClip.top - pGradRect->rclGradient.top;
  1425. if (ltemp <= 0)
  1426. {
  1427. ltemp = 0;
  1428. }
  1429. pGradRect->yScanAdjust = ltemp;
  1430. return((pGradRect->szDraw.cx > 0) && (pGradRect->szDraw.cy > 0));
  1431. }
  1432. /**************************************************************************\
  1433. * bRectangleMesh
  1434. *
  1435. * Draw rectangle mesh
  1436. *
  1437. * Arguments:
  1438. *
  1439. * pSurfDst - destination surface
  1440. * pxlo - clip obj
  1441. * pVertex - vertex list
  1442. * nVertex - # in vertex list
  1443. * pMesh - mesh list
  1444. * nMesh - # in mesh list
  1445. * ulMode - draw mode and attributes
  1446. * prclClip - bounding rect
  1447. * pptlDitherOrg - dither org
  1448. *
  1449. * Return Value:
  1450. *
  1451. * status
  1452. *
  1453. * History:
  1454. *
  1455. * 2/17/1997 Mark Enstrom [marke]
  1456. *
  1457. \**************************************************************************/
  1458. BOOL
  1459. bRectangleMesh(
  1460. PSURFACE pSurfDst,
  1461. XLATEOBJ *pxlo,
  1462. PTRIVERTEX pVertex,
  1463. ULONG nVertex,
  1464. PGRADIENT_RECT pMesh,
  1465. ULONG nMesh,
  1466. ULONG ulMode,
  1467. PRECTL prclClip,
  1468. PPOINTL pptlDitherOrg
  1469. )
  1470. {
  1471. PFN_GRADIENT pfnTemp;
  1472. PFN_GRADRECT pfnG;
  1473. BOOL bStatus = TRUE;
  1474. LONG dyTri = prclClip->bottom - prclClip->top;
  1475. GRADIENTRECTDATA grData;
  1476. XEPALOBJ epal(pSurfDst->ppal());
  1477. if (!epal.bValid())
  1478. {
  1479. PDEVOBJ pdo(pSurfDst->hdev());
  1480. epal.ppalSet(pdo.ppalSurf());
  1481. }
  1482. if (epal.bValid())
  1483. {
  1484. //
  1485. // find out scan line routine to use to draw pixels
  1486. //
  1487. bDetermineTriangleFillRoutine(pSurfDst,&epal,&pfnTemp,&pfnG);
  1488. grData.pxlo = pxlo;
  1489. grData.ppalDstSurf = &epal;
  1490. grData.ptDitherOrg = *pptlDitherOrg;
  1491. //
  1492. // draw each rectangle
  1493. //
  1494. grData.rclClip = *prclClip;
  1495. ULONG ulIndex;
  1496. for (ulIndex=0;ulIndex<nMesh;ulIndex++)
  1497. {
  1498. ULONG ulRect0 = pMesh[ulIndex].UpperLeft;
  1499. ULONG ulRect1 = pMesh[ulIndex].LowerRight;
  1500. //
  1501. // make sure index are in array
  1502. //
  1503. if (
  1504. (ulRect0 > (nVertex-1)) ||
  1505. (ulRect1 > (nVertex-1))
  1506. )
  1507. {
  1508. bStatus = FALSE;
  1509. break;
  1510. }
  1511. TRIVERTEX tvert0 = pVertex[ulRect0];
  1512. TRIVERTEX tvert1 = pVertex[ulRect1];
  1513. PTRIVERTEX pv0 = &tvert0;
  1514. PTRIVERTEX pv1 = &tvert1;
  1515. PTRIVERTEX pvt;
  1516. //
  1517. // make sure rectangle endpoints are properly ordered
  1518. //
  1519. if (ulMode == GRADIENT_FILL_RECT_H)
  1520. {
  1521. if (pv0->x > pv1->x)
  1522. {
  1523. SWAP_VERTEX(pv0,pv1,pvt);
  1524. }
  1525. if (pv0->y > pv1->y)
  1526. {
  1527. //
  1528. // must swap y
  1529. //
  1530. LONG ltemp = pv1->y;
  1531. pv1->y = pv0->y;
  1532. pv0->y = ltemp;
  1533. }
  1534. }
  1535. else
  1536. {
  1537. if (pv0->y > pv1->y)
  1538. {
  1539. SWAP_VERTEX(pv0,pv1,pvt);
  1540. }
  1541. if (pv0->x > pv1->x)
  1542. {
  1543. //
  1544. // must swap x
  1545. //
  1546. LONG ltemp = pv1->x;
  1547. pv1->x = pv0->x;
  1548. pv0->x = ltemp;
  1549. }
  1550. }
  1551. //
  1552. // gradient definition rectangle
  1553. //
  1554. grData.rclGradient.left = pv0->x;
  1555. grData.rclGradient.top = pv0->y;
  1556. grData.rclGradient.right = pv1->x;
  1557. grData.rclGradient.bottom = pv1->y;
  1558. grData.ulMode = ulMode;
  1559. LONG dxGrad = grData.rclGradient.right - grData.rclGradient.left;
  1560. LONG dyGrad = grData.rclGradient.bottom - grData.rclGradient.top;
  1561. //
  1562. // make sure rect not empty
  1563. //
  1564. if ((dxGrad > 0) && (dyGrad > 0))
  1565. {
  1566. //
  1567. // calculate color gradients for x and y
  1568. //
  1569. grData.llRed = ((LONGLONG)pv0->Red) << 40;
  1570. grData.llGreen = ((LONGLONG)pv0->Green) << 40;
  1571. grData.llBlue = ((LONGLONG)pv0->Blue) << 40;
  1572. grData.llAlpha = ((LONGLONG)pv0->Alpha) << 40;
  1573. if (ulMode == GRADIENT_FILL_RECT_H)
  1574. {
  1575. grData.lldRdY = 0;
  1576. grData.lldGdY = 0;
  1577. grData.lldBdY = 0;
  1578. grData.lldAdY = 0;
  1579. LONGLONG lldRed = (LONGLONG)(pv1->Red) << 40;
  1580. LONGLONG lldGreen = (LONGLONG)(pv1->Green) << 40;
  1581. LONGLONG lldBlue = (LONGLONG)(pv1->Blue) << 40;
  1582. LONGLONG lldAlpha = (LONGLONG)(pv1->Alpha) << 40;
  1583. lldRed -= (LONGLONG)(pv0->Red) << 40;
  1584. lldGreen -= (LONGLONG)(pv0->Green) << 40;
  1585. lldBlue -= (LONGLONG)(pv0->Blue) << 40;
  1586. lldAlpha -= (LONGLONG)(pv0->Alpha) << 40;
  1587. grData.lldRdX = MDiv64(lldRed ,(LONGLONG)1,(LONGLONG)dxGrad);
  1588. grData.lldGdX = MDiv64(lldGreen,(LONGLONG)1,(LONGLONG)dxGrad);
  1589. grData.lldBdX = MDiv64(lldBlue ,(LONGLONG)1,(LONGLONG)dxGrad);
  1590. grData.lldAdX = MDiv64(lldAlpha,(LONGLONG)1,(LONGLONG)dxGrad);
  1591. }
  1592. else
  1593. {
  1594. grData.lldRdX = 0;
  1595. grData.lldGdX = 0;
  1596. grData.lldBdX = 0;
  1597. grData.lldAdX = 0;
  1598. LONGLONG lldRed = (LONGLONG)(pv1->Red) << 40;
  1599. LONGLONG lldGreen = (LONGLONG)(pv1->Green) << 40;
  1600. LONGLONG lldBlue = (LONGLONG)(pv1->Blue) << 40;
  1601. LONGLONG lldAlpha = (LONGLONG)(pv1->Alpha) << 40;
  1602. lldRed -= (LONGLONG)(pv0->Red) << 40;
  1603. lldGreen -= (LONGLONG)(pv0->Green) << 40;
  1604. lldBlue -= (LONGLONG)(pv0->Blue) << 40;
  1605. lldAlpha -= (LONGLONG)(pv0->Alpha) << 40;
  1606. grData.lldRdY = MDiv64(lldRed ,(LONGLONG)1,(LONGLONG)dyGrad);
  1607. grData.lldGdY = MDiv64(lldGreen,(LONGLONG)1,(LONGLONG)dyGrad);
  1608. grData.lldBdY = MDiv64(lldBlue ,(LONGLONG)1,(LONGLONG)dyGrad);
  1609. grData.lldAdY = MDiv64(lldAlpha,(LONGLONG)1,(LONGLONG)dyGrad);
  1610. }
  1611. //
  1612. // calculate common offsets
  1613. //
  1614. if (bCalcGradientRectOffsets(&grData))
  1615. {
  1616. //
  1617. // call specific drawing routine if output
  1618. // not totally clipped
  1619. //
  1620. (*pfnG)(pSurfDst,&grData);
  1621. }
  1622. }
  1623. }
  1624. }
  1625. else
  1626. {
  1627. WARNING("bRectangleMesh: can't get surface palette\n");
  1628. }
  1629. return(bStatus);
  1630. }
  1631. /******************************Public*Routine******************************\
  1632. * EngGradientFill
  1633. *
  1634. * Draw gradient fill to memory surface. If complex clipping is used, then
  1635. * draw to a temp dib and blt to destination through clip.
  1636. *
  1637. * Arguments:
  1638. *
  1639. * psoDst - destination surface
  1640. * pco - clip obj
  1641. * pVertex - vertex list
  1642. * nVertex - # in vertex list
  1643. * pMesh - mesh list
  1644. * nMesh - # in mesh list
  1645. * ulMode - draw mode and attributes
  1646. *
  1647. * Return Value:
  1648. *
  1649. * Status
  1650. *
  1651. * History:
  1652. *
  1653. * 11/20/1996 Mark Enstrom [marke]
  1654. *
  1655. \**************************************************************************/
  1656. BOOL
  1657. APIENTRY
  1658. EngGradientFill(
  1659. SURFOBJ *psoDst,
  1660. CLIPOBJ *pco,
  1661. XLATEOBJ *pxlo,
  1662. TRIVERTEX *pVertex,
  1663. ULONG nVertex,
  1664. PVOID pMesh,
  1665. ULONG nMesh,
  1666. RECTL *prclExtents,
  1667. POINTL *ptlDitherOrg,
  1668. ULONG ulMode
  1669. )
  1670. {
  1671. ASSERTGDI(psoDst != NULL, "ERROR EngGradientFill: No destination surface\n");
  1672. BOOL bStatus = TRUE;
  1673. PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
  1674. PSURFACE pSurfDstTmp = NULL;
  1675. ULONG ulTri;
  1676. BOOL bForceDstAlloc = FALSE;
  1677. BOOL bAllocDstSurf = FALSE;
  1678. RECTL rclDstTrim;
  1679. RECTL rclDstWk;
  1680. CLIPOBJ *pcoDstWk = pco;
  1681. SURFMEM surfTmpDst;
  1682. ULONG ulIndex;
  1683. PDEVOBJ pdo(pSurfDst->hdev());
  1684. BOOL bCopyFromDst = TRUE;
  1685. ASSERTGDI(pdo.bValid(), "Invalid HDEV");
  1686. ASSERTGDI((ulMode == GRADIENT_FILL_TRIANGLE) ||
  1687. (ulMode == GRADIENT_FILL_RECT_H) ||
  1688. (ulMode == GRADIENT_FILL_RECT_V),
  1689. "Invalid gradient mode");
  1690. //
  1691. // sync with driver
  1692. //
  1693. {
  1694. pdo.vSync(psoDst,NULL,0);
  1695. }
  1696. //
  1697. // trim rclDst to clip bounding box
  1698. //
  1699. rclDstTrim = *prclExtents;
  1700. //
  1701. // clip extents to destination clip rect
  1702. //
  1703. if ((pco != NULL) && (pco->iDComplexity > DC_TRIVIAL))
  1704. {
  1705. if (rclDstTrim.left < pco->rclBounds.left)
  1706. {
  1707. rclDstTrim.left = pco->rclBounds.left;
  1708. }
  1709. if (rclDstTrim.right > pco->rclBounds.right)
  1710. {
  1711. rclDstTrim.right = pco->rclBounds.right;
  1712. }
  1713. if (rclDstTrim.top < pco->rclBounds.top)
  1714. {
  1715. rclDstTrim.top = pco->rclBounds.top;
  1716. }
  1717. if (rclDstTrim.bottom > pco->rclBounds.bottom)
  1718. {
  1719. rclDstTrim.bottom = pco->rclBounds.bottom;
  1720. }
  1721. }
  1722. //
  1723. // rclDstWk specifies size of temp surface needed (if temp surface is created)
  1724. // coordinates in this temp surface are referenced to prclExtents, even though the
  1725. // surface may be clipped to a smaller extent
  1726. //
  1727. rclDstWk = rclDstTrim;
  1728. //
  1729. // Force Complex clipping to go through temp surface
  1730. //
  1731. if ((pco != NULL) &&
  1732. (pco->iDComplexity != DC_TRIVIAL) &&
  1733. (pco->iDComplexity != DC_RECT))
  1734. {
  1735. bForceDstAlloc = TRUE;
  1736. }
  1737. //
  1738. // get a dst surface that can be written to, remember since it will have to
  1739. // be written back.
  1740. //
  1741. //
  1742. // If the gradient fill shape is a rectangle, we don't need
  1743. // to copy bits from the destination since they'll all
  1744. // be overwritten
  1745. //
  1746. if ((ulMode == GRADIENT_FILL_RECT_H) ||
  1747. (ulMode == GRADIENT_FILL_RECT_V))
  1748. {
  1749. bCopyFromDst = FALSE;
  1750. }
  1751. pSurfDstTmp = psSetupDstSurface(
  1752. pSurfDst,
  1753. &rclDstWk,
  1754. surfTmpDst,
  1755. bForceDstAlloc,
  1756. bCopyFromDst);
  1757. if (pSurfDstTmp != NULL)
  1758. {
  1759. if (pSurfDstTmp != pSurfDst)
  1760. {
  1761. bAllocDstSurf = TRUE;
  1762. }
  1763. if (bAllocDstSurf)
  1764. {
  1765. //
  1766. // drawing lies completely in temp rectangle, src surface is read
  1767. // into tmp DIB before drawing, so no clipping is needed when this
  1768. // is copied to destination surface
  1769. //
  1770. pcoDstWk = NULL;
  1771. //
  1772. // subtract rect origin
  1773. //
  1774. for (ulIndex=0;ulIndex<nVertex;ulIndex++)
  1775. {
  1776. pVertex[ulIndex].x -= rclDstTrim.left;
  1777. pVertex[ulIndex].y -= rclDstTrim.top;
  1778. }
  1779. //
  1780. // adjust dither org
  1781. //
  1782. ptlDitherOrg->x += rclDstTrim.left;
  1783. ptlDitherOrg->y += rclDstTrim.top;
  1784. }
  1785. //
  1786. // limit recorded triangle to clipped output
  1787. //
  1788. ERECTL *prclClip;
  1789. LONG dyTri = rclDstWk.bottom - rclDstWk.top;
  1790. if ((pcoDstWk == NULL) || (pcoDstWk->iDComplexity == DC_TRIVIAL))
  1791. {
  1792. prclClip = NULL;
  1793. }
  1794. else
  1795. {
  1796. prclClip = (ERECTL *)&pcoDstWk->rclBounds;
  1797. }
  1798. //
  1799. // draw gradients
  1800. //
  1801. if (ulMode == GRADIENT_FILL_TRIANGLE)
  1802. {
  1803. bStatus = bTriangleMesh(pSurfDstTmp,
  1804. pxlo,
  1805. pVertex,
  1806. nVertex,
  1807. (PGRADIENT_TRIANGLE)pMesh,
  1808. nMesh,
  1809. ulMode,
  1810. &rclDstWk,
  1811. prclExtents,
  1812. ptlDitherOrg
  1813. );
  1814. }
  1815. else
  1816. {
  1817. ASSERTGDI((ulMode == GRADIENT_FILL_RECT_H) ||
  1818. (ulMode == GRADIENT_FILL_RECT_V),
  1819. "Unhandle 'ulMode'");
  1820. bStatus = bRectangleMesh(
  1821. pSurfDstTmp,
  1822. pxlo,
  1823. pVertex,
  1824. nVertex,
  1825. (PGRADIENT_RECT)pMesh,
  1826. nMesh,
  1827. ulMode,
  1828. &rclDstWk,
  1829. ptlDitherOrg
  1830. );
  1831. }
  1832. //
  1833. // write temp destination surface to real dst
  1834. //
  1835. if (bAllocDstSurf)
  1836. {
  1837. PDEVOBJ pdoDst(pSurfDst->hdev());
  1838. ASSERTGDI(pdoDst.bValid(), "Invalid HDEV");
  1839. POINTL ptlCopy = {0,0};
  1840. (*PPFNGET(pdoDst,CopyBits,pSurfDst->flags()))(
  1841. pSurfDst->pSurfobj(),
  1842. pSurfDstTmp->pSurfobj(),
  1843. pco,
  1844. &xloIdent,
  1845. &rclDstTrim,
  1846. &ptlCopy);
  1847. //
  1848. // undo temporary offseting
  1849. //
  1850. for (ulIndex=0;ulIndex<nVertex;ulIndex++)
  1851. {
  1852. pVertex[ulIndex].x += rclDstTrim.left;
  1853. pVertex[ulIndex].y += rclDstTrim.top;
  1854. }
  1855. ptlDitherOrg->x -= rclDstTrim.left;
  1856. ptlDitherOrg->y -= rclDstTrim.top;
  1857. }
  1858. }
  1859. else
  1860. {
  1861. EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1862. bStatus = FALSE;
  1863. }
  1864. return(bStatus);
  1865. }
  1866. /******************************Public*Routine******************************\
  1867. * vCalcMeshExtent
  1868. *
  1869. * Verify mesh, calculate bounding rect of drawing.
  1870. *
  1871. * Arguments:
  1872. *
  1873. * pVertex - vertex array
  1874. * nVertex - number of vertex in array
  1875. * pMesh - array of rect or tri
  1876. * nMesh - number in mesh array
  1877. * ulMode - triangle or rectangle
  1878. * prclExt - return extent rect
  1879. *
  1880. * Return Value:
  1881. *
  1882. * TRUE if mesh is valid
  1883. *
  1884. * History:
  1885. *
  1886. * 12/3/1996 Mark Enstrom [marke]
  1887. *
  1888. \**************************************************************************/
  1889. BOOL
  1890. bCalcMeshExtent(
  1891. PTRIVERTEX pVertex,
  1892. ULONG nVertex,
  1893. PVOID pMesh,
  1894. ULONG nMesh,
  1895. ULONG ulMode,
  1896. RECTL *prclExt
  1897. )
  1898. {
  1899. LONG xmin = LONG_MAX;
  1900. LONG xmax = LONG_MIN;
  1901. LONG ymin = LONG_MAX;
  1902. LONG ymax = LONG_MIN;
  1903. BOOL bRet = TRUE;
  1904. ULONG ulIndex;
  1905. //
  1906. // triangle or rectangle case
  1907. //
  1908. if (
  1909. (ulMode ==GRADIENT_FILL_RECT_H) ||
  1910. (ulMode == GRADIENT_FILL_RECT_V)
  1911. )
  1912. {
  1913. //
  1914. // verify rectangle mesh, remember extents
  1915. //
  1916. PGRADIENT_RECT pGradRect = (PGRADIENT_RECT)pMesh;
  1917. for (ulIndex=0;ulIndex<nMesh;ulIndex++)
  1918. {
  1919. RECTL rcl;
  1920. ULONG vul = pGradRect->UpperLeft;
  1921. ULONG vlr = pGradRect->LowerRight;
  1922. if ((vul <= nVertex) && (vlr <= nVertex))
  1923. {
  1924. LONG VertLeftX = pVertex[vul].x;
  1925. LONG VertLeftY = pVertex[vul].y;
  1926. LONG VertRightX = pVertex[vlr].x;
  1927. LONG VertRightY = pVertex[vlr].y;
  1928. if (VertLeftX < xmin)
  1929. {
  1930. xmin = VertLeftX;
  1931. }
  1932. if (VertLeftX > xmax)
  1933. {
  1934. xmax = VertLeftX;
  1935. }
  1936. if (VertLeftY < ymin)
  1937. {
  1938. ymin = VertLeftY;
  1939. }
  1940. if (VertLeftY > ymax)
  1941. {
  1942. ymax = VertLeftY;
  1943. }
  1944. if (VertRightX < xmin)
  1945. {
  1946. xmin = VertRightX;
  1947. }
  1948. if (VertRightX > xmax)
  1949. {
  1950. xmax = VertRightX;
  1951. }
  1952. if (VertRightY < ymin)
  1953. {
  1954. ymin = VertRightY;
  1955. }
  1956. if (VertRightY > ymax)
  1957. {
  1958. ymax = VertRightY;
  1959. }
  1960. }
  1961. else
  1962. {
  1963. //
  1964. // error in mesh/vertex array, return null
  1965. // bounding rect
  1966. //
  1967. prclExt->left = 0;
  1968. prclExt->right = 0;
  1969. prclExt->top = 0;
  1970. prclExt->bottom = 0;
  1971. return(FALSE);
  1972. }
  1973. pGradRect++;
  1974. }
  1975. }
  1976. else if (ulMode == GRADIENT_FILL_TRIANGLE)
  1977. {
  1978. //
  1979. // verify triangle mesh, remember extents
  1980. //
  1981. PGRADIENT_TRIANGLE pGradTri = (PGRADIENT_TRIANGLE)pMesh;
  1982. for (ulIndex=0;ulIndex<nMesh;ulIndex++)
  1983. {
  1984. LONG lVertex[3];
  1985. LONG vIndex;
  1986. lVertex[0] = pGradTri->Vertex1;
  1987. lVertex[1] = pGradTri->Vertex2;
  1988. lVertex[2] = pGradTri->Vertex3;
  1989. for (vIndex=0;vIndex<3;vIndex++)
  1990. {
  1991. ULONG TriVertex = lVertex[vIndex];
  1992. if (TriVertex < nVertex)
  1993. {
  1994. LONG VertX = pVertex[TriVertex].x;
  1995. LONG VertY = pVertex[TriVertex].y;
  1996. if (VertX < xmin)
  1997. {
  1998. xmin = VertX;
  1999. }
  2000. if (VertX > xmax)
  2001. {
  2002. xmax = VertX;
  2003. }
  2004. if (VertY < ymin)
  2005. {
  2006. ymin = VertY;
  2007. }
  2008. if (VertY > ymax)
  2009. {
  2010. ymax = VertY;
  2011. }
  2012. }
  2013. else
  2014. {
  2015. //
  2016. // error in mesh/vertex array, return null
  2017. // bounding rect
  2018. //
  2019. prclExt->left = 0;
  2020. prclExt->right = 0;
  2021. prclExt->top = 0;
  2022. prclExt->bottom = 0;
  2023. return(FALSE);
  2024. }
  2025. }
  2026. pGradTri++;
  2027. }
  2028. }
  2029. else
  2030. {
  2031. bRet = FALSE;
  2032. }
  2033. //
  2034. // are any parameter out of coordinate space bounds 2^28
  2035. //
  2036. LONG lIntMax = 0x08000000;
  2037. LONG lIntMin = -lIntMax;
  2038. if (
  2039. (xmin < lIntMin) || (xmin > lIntMax) ||
  2040. (xmax < lIntMin) || (xmax > lIntMax) ||
  2041. (ymin < lIntMin) || (ymin > lIntMax) ||
  2042. (ymax < lIntMin) || (ymax > lIntMax)
  2043. )
  2044. {
  2045. prclExt->left = 0;
  2046. prclExt->right = 0;
  2047. prclExt->top = 0;
  2048. prclExt->bottom = 0;
  2049. return(FALSE);
  2050. }
  2051. prclExt->left = xmin;
  2052. prclExt->right = xmax;
  2053. prclExt->top = ymin;
  2054. prclExt->bottom = ymax;
  2055. return(bRet);
  2056. }
  2057. /******************************Public*Routine******************************\
  2058. * GreGradientFill
  2059. *
  2060. * Arguments:
  2061. *
  2062. * hdc - dc
  2063. * pLocalVertex - Position and color
  2064. * nVertex - number of vertex
  2065. * pLocalMesh - each three USHORTs define 1 triangle
  2066. * nMesh - Number of triangles
  2067. * ulMode - drawing mode (rect/tri) and options
  2068. *
  2069. * Return Value:
  2070. *
  2071. * Status
  2072. *
  2073. * History:
  2074. *
  2075. * 23-Jun-1997 Added rotation support for rectangles -by- Ori Gershony [orig]
  2076. *
  2077. * 16-Jul-1996 -by- Mark Enstrom [marke]
  2078. *
  2079. \**************************************************************************/
  2080. BOOL
  2081. GreGradientFill(
  2082. HDC hdc,
  2083. PTRIVERTEX pLocalVertex,
  2084. ULONG nVertex,
  2085. PVOID pLocalMesh,
  2086. ULONG nMesh,
  2087. ULONG ulMode
  2088. )
  2089. {
  2090. GDITraceHandle(GreGradientFill, "(%X, %p, %u, %p, %u, %u)\n", (va_list)&hdc,
  2091. hdc);
  2092. BOOL bStatus = FALSE;
  2093. PTRIVERTEX pLocalVertexTmp=NULL;
  2094. PVOID pLocalMeshTmp=NULL;
  2095. //
  2096. // limit ulMode (direct from user)
  2097. //
  2098. ulMode &= GRADIENT_FILL_OP_FLAG;
  2099. //
  2100. // validate DST DC
  2101. //
  2102. DCOBJ dcoDst(hdc);
  2103. if (dcoDst.bValid())
  2104. {
  2105. //
  2106. // lock device
  2107. //
  2108. DEVLOCKBLTOBJ dlo;
  2109. if (dlo.bLock(dcoDst))
  2110. {
  2111. EXFORMOBJ xoDst(dcoDst, WORLD_TO_DEVICE);
  2112. //
  2113. // Break each rotated rectangle into two triangles. This will double
  2114. // the number of vertices used (4 per two triangles).
  2115. //
  2116. if (xoDst.bRotation() &&
  2117. ((ulMode == GRADIENT_FILL_RECT_H) || (ulMode == GRADIENT_FILL_RECT_V)))
  2118. {
  2119. //
  2120. // Allocate two triangles for each rectangle
  2121. //
  2122. ULONG ulSizeM = nMesh * 2 * sizeof(GRADIENT_TRIANGLE);
  2123. ULONG ulSizeV = nVertex * 2 * sizeof(TRIVERTEX);
  2124. //
  2125. // Let's make sure nMesh and nVertex are not so high as to cause overflow--this
  2126. // can cause us to allocate too small a buffer and then commit an access
  2127. // violation. Also make sure we have enough memory.
  2128. //
  2129. if ((nVertex > MAXULONG/2) ||
  2130. (nMesh > MAXULONG/2) ||
  2131. ((nVertex * 2) > (MAXIMUM_POOL_ALLOC / sizeof(TRIVERTEX))) ||
  2132. ((nMesh * 2) > ((MAXIMUM_POOL_ALLOC - ulSizeV) / (sizeof(GRADIENT_TRIANGLE)))))
  2133. {
  2134. WARNING("GreGradientFill: can't allocate input buffer\n");
  2135. EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2136. return(FALSE);
  2137. }
  2138. //
  2139. // Allocate memory and assign to the pointers
  2140. //
  2141. pLocalVertexTmp = (PTRIVERTEX)PALLOCNOZ(ulSizeV + ulSizeM,'pmtG');
  2142. if (!pLocalVertexTmp)
  2143. {
  2144. EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2145. return FALSE;
  2146. }
  2147. pLocalMeshTmp = (PVOID)((PBYTE)pLocalVertexTmp + ulSizeV);
  2148. //
  2149. // First copy the old Vertices
  2150. //
  2151. ULONG vertexNum;
  2152. for (vertexNum=0; vertexNum < nVertex; vertexNum++)
  2153. {
  2154. ((PTRIVERTEX)pLocalVertexTmp)[vertexNum] = ((PTRIVERTEX) pLocalVertex)[vertexNum];
  2155. }
  2156. //
  2157. // Now walk the rectangle list and generate triangles/vertices as needed:
  2158. //
  2159. // v1 vertexNum
  2160. // *------------------*
  2161. // | |
  2162. // | |
  2163. // *------------------*
  2164. // vertexNum+1 v2
  2165. //
  2166. for (ULONG rectNum=0; rectNum < nMesh; rectNum++)
  2167. {
  2168. ULONG v1,v2;
  2169. v1 = ((PGRADIENT_RECT)pLocalMesh)[rectNum].UpperLeft;
  2170. v2 = ((PGRADIENT_RECT)pLocalMesh)[rectNum].LowerRight;
  2171. if ((v1 >= nVertex) || (v2 >= nVertex))
  2172. {
  2173. WARNING("GreGradientFill: vertex is out of range\n");
  2174. EngSetLastError(ERROR_INVALID_PARAMETER);
  2175. VFREEMEM(pLocalVertexTmp);
  2176. return(FALSE);
  2177. }
  2178. pLocalVertexTmp[vertexNum].x = pLocalVertex[v2].x;
  2179. pLocalVertexTmp[vertexNum].y = pLocalVertex[v1].y;
  2180. pLocalVertexTmp[vertexNum+1].x = pLocalVertex[v1].x;
  2181. pLocalVertexTmp[vertexNum+1].y = pLocalVertex[v2].y;
  2182. if (ulMode == GRADIENT_FILL_RECT_V)
  2183. {
  2184. //
  2185. // vertexNum has same color as v1, vertexNum+1 has same color as v2
  2186. //
  2187. pLocalVertexTmp[vertexNum].Red = pLocalVertex[v1].Red;
  2188. pLocalVertexTmp[vertexNum].Green = pLocalVertex[v1].Green;
  2189. pLocalVertexTmp[vertexNum].Blue = pLocalVertex[v1].Blue;
  2190. pLocalVertexTmp[vertexNum].Alpha = pLocalVertex[v1].Alpha;
  2191. pLocalVertexTmp[vertexNum+1].Red = pLocalVertex[v2].Red;
  2192. pLocalVertexTmp[vertexNum+1].Green = pLocalVertex[v2].Green;
  2193. pLocalVertexTmp[vertexNum+1].Blue = pLocalVertex[v2].Blue;
  2194. pLocalVertexTmp[vertexNum+1].Alpha = pLocalVertex[v2].Alpha;
  2195. }
  2196. else
  2197. {
  2198. //
  2199. // vertexNum has same color as v2, vertexNum+1 has same color as v1
  2200. //
  2201. pLocalVertexTmp[vertexNum].Red = pLocalVertex[v2].Red;
  2202. pLocalVertexTmp[vertexNum].Green = pLocalVertex[v2].Green;
  2203. pLocalVertexTmp[vertexNum].Blue = pLocalVertex[v2].Blue;
  2204. pLocalVertexTmp[vertexNum].Alpha = pLocalVertex[v2].Alpha;
  2205. pLocalVertexTmp[vertexNum+1].Red = pLocalVertex[v1].Red;
  2206. pLocalVertexTmp[vertexNum+1].Green = pLocalVertex[v1].Green;
  2207. pLocalVertexTmp[vertexNum+1].Blue = pLocalVertex[v1].Blue;
  2208. pLocalVertexTmp[vertexNum+1].Alpha = pLocalVertex[v1].Alpha;
  2209. }
  2210. //
  2211. // Now add vertices for the two triangles
  2212. //
  2213. ((PGRADIENT_TRIANGLE)pLocalMeshTmp)[rectNum*2].Vertex1 = v1;
  2214. ((PGRADIENT_TRIANGLE)pLocalMeshTmp)[rectNum*2].Vertex2 = vertexNum;
  2215. ((PGRADIENT_TRIANGLE)pLocalMeshTmp)[rectNum*2].Vertex3 = vertexNum+1;
  2216. ((PGRADIENT_TRIANGLE)pLocalMeshTmp)[rectNum*2+1].Vertex1 = v2;
  2217. ((PGRADIENT_TRIANGLE)pLocalMeshTmp)[rectNum*2+1].Vertex2 = vertexNum;
  2218. ((PGRADIENT_TRIANGLE)pLocalMeshTmp)[rectNum*2+1].Vertex3 = vertexNum+1;
  2219. vertexNum += 2;
  2220. }
  2221. //
  2222. // Now modify the arguments so that this change is transparent to the rest of the code
  2223. //
  2224. pLocalMesh = pLocalMeshTmp;
  2225. pLocalVertex = pLocalVertexTmp;
  2226. ulMode = GRADIENT_FILL_TRIANGLE;
  2227. nVertex = vertexNum;
  2228. nMesh *= 2;
  2229. }
  2230. //
  2231. // should be able to rotate triangle with no problem. Rotated
  2232. // rectangles should have already been converted to triangles.
  2233. //
  2234. ULONG ulIndex;
  2235. ERECTL erclDst(POS_INFINITY,POS_INFINITY,NEG_INFINITY,NEG_INFINITY);
  2236. //
  2237. // Translate to device space. Use integer points, not fixed point
  2238. //
  2239. for (ulIndex=0;ulIndex<nVertex;ulIndex++)
  2240. {
  2241. EPOINTL eptl(pLocalVertex[ulIndex].x,pLocalVertex[ulIndex].y);
  2242. xoDst.bXform(eptl);
  2243. //Shift all the points one pixel to the right to include the right edge of the rect.
  2244. if(MIRRORED_DC(dcoDst.pdc)) {
  2245. ++eptl.x;
  2246. }
  2247. pLocalVertex[ulIndex].x = eptl.x + dcoDst.eptlOrigin().x;
  2248. pLocalVertex[ulIndex].y = eptl.y + dcoDst.eptlOrigin().y;
  2249. }
  2250. //
  2251. // verify mesh and calc mesh extents
  2252. //
  2253. bStatus = bCalcMeshExtent(pLocalVertex,nVertex,pLocalMesh,nMesh,ulMode,&erclDst);
  2254. if (bStatus)
  2255. {
  2256. //
  2257. // set up clipping, check if totally excluded
  2258. //
  2259. ECLIPOBJ eco(dcoDst.prgnEffRao(), erclDst);
  2260. if (!(eco.erclExclude().bEmpty()))
  2261. {
  2262. //
  2263. // Accumulate bounds. We can do this before knowing if the operation is
  2264. // successful because bounds can be loose.
  2265. //
  2266. //
  2267. if (dcoDst.fjAccum())
  2268. {
  2269. ERECTL erclBound = erclDst;
  2270. //
  2271. // erclDst is adjusted from DC origin,
  2272. // so that it should be substracted.
  2273. //
  2274. erclBound -= dcoDst.eptlOrigin();
  2275. dcoDst.vAccumulate(erclBound);
  2276. }
  2277. SURFACE *pSurfDst;
  2278. if ((pSurfDst = dcoDst.pSurface()) != NULL)
  2279. {
  2280. PDEVOBJ pdo(pSurfDst->hdev());
  2281. DEVEXCLUDEOBJ dxo(dcoDst,&erclDst,&eco);
  2282. EXLATEOBJ xlo;
  2283. XLATEOBJ *pxlo;
  2284. //
  2285. // Inc the target surface uniqueness
  2286. //
  2287. INC_SURF_UNIQ(pSurfDst);
  2288. if ((pdo.bPrinter()) || (pSurfDst->iFormat() <= BMF_8BPP))
  2289. {
  2290. //
  2291. // 16bpp or greater does not require a translation object.
  2292. //
  2293. // color translate is from RGB (PAL_BGR) 32 to device
  2294. //
  2295. XEPALOBJ palDst(pSurfDst->ppal());
  2296. XEPALOBJ palDstDC(dcoDst.ppal());
  2297. XEPALOBJ palSrc(gppalRGB);
  2298. bStatus = xlo.bInitXlateObj(
  2299. dcoDst.pdc->hcmXform(),
  2300. dcoDst.pdc->GetICMMode(),
  2301. palSrc,
  2302. palDst,
  2303. palDstDC,
  2304. palDstDC,
  2305. dcoDst.pdc->crTextClr(),
  2306. dcoDst.pdc->crBackClr(),
  2307. 0
  2308. );
  2309. pxlo = xlo.pxlo();
  2310. }
  2311. else
  2312. {
  2313. pxlo = NULL;
  2314. }
  2315. //
  2316. // must have window offset for dither org
  2317. //
  2318. POINTL ptlDitherOrg = dcoDst.pdc->eptlOrigin();
  2319. ptlDitherOrg.x = -ptlDitherOrg.x;
  2320. ptlDitherOrg.y = -ptlDitherOrg.y;
  2321. //
  2322. // call driver/engine drawing
  2323. //
  2324. PFN_DrvGradientFill pfnGradientFill;
  2325. if (pSurfDst->iFormat() == BMF_8BPP)
  2326. {
  2327. // Drivers can't really support GradientFill at
  2328. // 8BPP. Instead of calling them and running
  2329. // the risk of having them mess up, let's call
  2330. // the engine instead.
  2331. pfnGradientFill = EngGradientFill;
  2332. }
  2333. else
  2334. {
  2335. pfnGradientFill =
  2336. PPFNGET(pdo,GradientFill, pSurfDst->flags());
  2337. }
  2338. bStatus = bStatus && (*pfnGradientFill)(
  2339. pSurfDst->pSurfobj(),
  2340. &eco,
  2341. pxlo,
  2342. pLocalVertex,
  2343. nVertex,
  2344. pLocalMesh,
  2345. nMesh,
  2346. &erclDst,
  2347. &ptlDitherOrg,
  2348. ulMode
  2349. );
  2350. }
  2351. else
  2352. {
  2353. bStatus = TRUE;
  2354. }
  2355. }
  2356. else
  2357. {
  2358. bStatus = TRUE;
  2359. }
  2360. }
  2361. else
  2362. {
  2363. WARNING1("GreGradientFill: Invalid mesh or vertex\n");
  2364. }
  2365. }
  2366. else
  2367. {
  2368. bStatus = dcoDst.bFullScreen();
  2369. }
  2370. }
  2371. else
  2372. {
  2373. bStatus = FALSE;
  2374. }
  2375. //
  2376. // If allocated memory to convert rectangles to triangles, free it before
  2377. // leaving this function.
  2378. //
  2379. if (pLocalVertexTmp)
  2380. {
  2381. VFREEMEM(pLocalVertexTmp);
  2382. }
  2383. return(bStatus);
  2384. }
  2385. /******************************Public*Routine******************************\
  2386. * NtGdiTriangleMesh
  2387. *
  2388. * Kernel mode stub for GradientFill
  2389. *
  2390. * Arguments:
  2391. *
  2392. * hdc - dc
  2393. * pLocalVertex - Position and color
  2394. * nVertex - number of vertex
  2395. * pLocalMesh - triangle or rectangle mesh
  2396. * nMesh - Number of triangles
  2397. * ulMode - drawing mode (rect/tri) and options
  2398. *
  2399. * Return Value:
  2400. *
  2401. * Status
  2402. *
  2403. * History:
  2404. *
  2405. * 17-Jul-1996 -by- Mark Enstrom [marke]
  2406. *
  2407. \**************************************************************************/
  2408. BOOL
  2409. NtGdiGradientFill(
  2410. HDC hdc,
  2411. PTRIVERTEX pVertex,
  2412. ULONG nVertex,
  2413. PVOID pMesh,
  2414. ULONG nMesh,
  2415. ULONG ulMode
  2416. )
  2417. {
  2418. PTRIVERTEX pLocalVertex;
  2419. PVOID pLocalMesh;
  2420. //
  2421. // make sure ulMode is not being mis-used
  2422. //
  2423. if ((ulMode & ~GRADIENT_FILL_OP_FLAG) != 0)
  2424. {
  2425. WARNING("NtGdiGradientFill: illegal parameter\n");
  2426. EngSetLastError(ERROR_INVALID_PARAMETER);
  2427. return(FALSE);
  2428. }
  2429. ulMode &= GRADIENT_FILL_OP_FLAG;
  2430. //
  2431. // validate parameters, make sure one of the mode
  2432. // flags is set, but no invalid mode is set
  2433. //
  2434. if (
  2435. (pVertex == NULL) || (pMesh == NULL) ||
  2436. (nVertex == 0) || (nMesh == 0) ||
  2437. (nVertex >= 0x80000000) || (nMesh >= 0x80000000) ||
  2438. (
  2439. (ulMode != GRADIENT_FILL_RECT_H) &&
  2440. (ulMode != GRADIENT_FILL_RECT_V) &&
  2441. (ulMode != GRADIENT_FILL_TRIANGLE)
  2442. )
  2443. )
  2444. {
  2445. WARNING("NtGdiGradientFill: illegal parameter\n");
  2446. EngSetLastError(ERROR_INVALID_PARAMETER);
  2447. return(FALSE);
  2448. }
  2449. //
  2450. // attempt to allocate a buffer to copy entire vertex and mesh array
  2451. //
  2452. if (nVertex > (MAXIMUM_POOL_ALLOC / sizeof(TRIVERTEX)))
  2453. {
  2454. WARNING("NtGdiGradientFill: nVertex is too large\n");
  2455. EngSetLastError(ERROR_INVALID_PARAMETER);
  2456. return(FALSE);
  2457. }
  2458. ULONG ulSizeV = nVertex * sizeof(TRIVERTEX);
  2459. ULONG ulSizeM;
  2460. BOOL bRet = TRUE;
  2461. if (ulMode == GRADIENT_FILL_TRIANGLE)
  2462. {
  2463. if (nMesh > ((MAXIMUM_POOL_ALLOC - ulSizeV) / (sizeof(GRADIENT_TRIANGLE))))
  2464. {
  2465. WARNING("NtGdiGradientFill: nMesh is too large\n");
  2466. EngSetLastError(ERROR_INVALID_PARAMETER);
  2467. return(FALSE);
  2468. }
  2469. ulSizeM = nMesh * sizeof(GRADIENT_TRIANGLE);
  2470. }
  2471. else
  2472. {
  2473. if (nMesh > ((MAXIMUM_POOL_ALLOC - ulSizeV) / (sizeof(GRADIENT_RECT))))
  2474. {
  2475. WARNING("NtGdiGradientFill: nMesh is too large\n");
  2476. EngSetLastError(ERROR_INVALID_PARAMETER);
  2477. return(FALSE);
  2478. }
  2479. ulSizeM = nMesh * sizeof(GRADIENT_RECT);
  2480. }
  2481. //
  2482. // alloc memory for data buffers
  2483. //
  2484. if ((ulSizeM + ulSizeV) >= MAXIMUM_POOL_ALLOC)
  2485. {
  2486. WARNING("NtGdiGradientFill: can't allocate input buffer\n");
  2487. EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2488. return(FALSE);
  2489. }
  2490. pLocalVertex = (PTRIVERTEX)PALLOCNOZ(ulSizeV + ulSizeM,'pmtG');
  2491. if (pLocalVertex)
  2492. {
  2493. pLocalMesh = (PVOID)((PBYTE)pLocalVertex + ulSizeV);
  2494. //
  2495. // probe then copy buffers
  2496. //
  2497. __try
  2498. {
  2499. ProbeForRead(pVertex,ulSizeV,sizeof(BYTE));
  2500. RtlCopyMemory(pLocalVertex,pVertex,ulSizeV);
  2501. ProbeForRead(pMesh,ulSizeM,sizeof(BYTE));
  2502. RtlCopyMemory(pLocalMesh,pMesh,ulSizeM);
  2503. }
  2504. __except(EXCEPTION_EXECUTE_HANDLER)
  2505. {
  2506. WARNINGX(2);
  2507. bRet = FALSE;
  2508. }
  2509. if (bRet)
  2510. {
  2511. bRet = GreGradientFill(
  2512. hdc,
  2513. pLocalVertex,
  2514. nVertex,
  2515. pLocalMesh,
  2516. nMesh,
  2517. ulMode
  2518. );
  2519. }
  2520. VFREEMEM(pLocalVertex);
  2521. }
  2522. else
  2523. {
  2524. EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2525. bRet = FALSE;
  2526. }
  2527. return(bRet);
  2528. }