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.

1138 lines
28 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 - 2000 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Quad Transforms
  8. *
  9. * History:
  10. *
  11. * 03/17/1999 ikkof
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. INT solveQuadraticEquationForQuadTransform(REAL a, REAL b, REAL c, REAL* x);
  17. // Constants used in GpQuadAnalyzer
  18. #define EdgeHorizontal 0
  19. #define EdgeDown 1
  20. #define EdgeUp 2
  21. VOID
  22. GpQuadAnalyzer::SetQuadAnalyzer(const GpPointF* points)
  23. {
  24. Left = Right = points[0].X;
  25. Top = Bottom = points[0].Y;
  26. for(INT i = 0; i < 4; i++)
  27. {
  28. INT j = i + 1;
  29. if(j == 4)
  30. j = 0;
  31. if(points[i].Y < points[j].Y)
  32. {
  33. Directions[i] = EdgeDown;
  34. Y1[i] = points[i].Y;
  35. Y2[i] = points[j].Y;
  36. X1[i] = points[i].X;
  37. DxDy[i] = (points[j].X - points[i].X)/(points[j].Y - points[i].Y);
  38. }
  39. else if(points[i].Y > points[j].Y)
  40. {
  41. Directions[i] = EdgeUp;
  42. Y1[i] = points[j].Y;
  43. Y2[i] = points[i].Y;
  44. X1[i] = points[j].X;
  45. DxDy[i] = (points[j].X - points[i].X)/(points[j].Y - points[i].Y);
  46. }
  47. else // Horizontal
  48. {
  49. Directions[i] = EdgeHorizontal;
  50. Y1[i] = points[i].Y;
  51. Y2[i] = points[i].Y;
  52. X1[i] = points[i].X;
  53. DxDy[i] = 0; // It is not used.
  54. }
  55. if(points[i].X < Left)
  56. Left = points[i].X;
  57. else if(points[i].X > Right)
  58. Right = points[i].X;
  59. if(points[i].Y < Top)
  60. Top = points[i].Y;
  61. else if(points[i].Y > Bottom)
  62. Bottom = points[i].Y;
  63. }
  64. }
  65. // Get the x-spans of a quad and returns the number of
  66. // pairs of x-spans.
  67. INT
  68. GpQuadAnalyzer::GetXSpans(REAL* xSpans, REAL y)
  69. {
  70. if(y < Top || y >= Bottom)
  71. return 0;
  72. INT count = 0;
  73. for(INT i = 0; i < 4; i++)
  74. {
  75. if(Directions[i] != EdgeHorizontal && y >= Y1[i] && y < Y2[i])
  76. xSpans[count++] = X1[i] + DxDy[i]*(y - Y1[i]);
  77. }
  78. return (count >> 1);
  79. }
  80. VOID
  81. GpBilinearTransform::Initialize()
  82. {
  83. GpMemset(&SrcRect, 0, sizeof(GpRectF));
  84. GpMemset(&DstBounds, 0, sizeof(GpRectF));
  85. GpMemset(&A, 0, sizeof(GpPointF));
  86. GpMemset(&B, 0, sizeof(GpPointF));
  87. GpMemset(&C, 0, sizeof(GpPointF));
  88. GpMemset(&D, 0, sizeof(GpPointF));
  89. C_VV = C_V = 0;
  90. FixedValue = -1.0f;
  91. #ifdef TEST_QUADTRANSFORMS
  92. // For testing purpose only.
  93. GpMemset(&Verteces[0], 0, 4*sizeof(GpPointF));
  94. #endif
  95. }
  96. /**************************************************************************\
  97. *
  98. * P0 P1
  99. * ------------
  100. * | \
  101. * | \
  102. * | \
  103. * | \
  104. * ----------------\
  105. * P2 P3
  106. *
  107. \**************************************************************************/
  108. GpStatus
  109. GpBilinearTransform::SetBilinearTransform(
  110. const GpRectF& rect,
  111. const GpPointF* points,
  112. INT count,
  113. REAL fixed
  114. )
  115. {
  116. BOOL test = ((points != NULL) && (count == 3 || count == 4));
  117. ASSERT(test);
  118. if(!test)
  119. return InvalidParameter;
  120. SrcRect = rect;
  121. REAL left, right, top, bottom;
  122. left = right = points[0].X;
  123. top = bottom = points[0].Y;
  124. for(INT i = 1; i < count; i++)
  125. {
  126. if(points[i].X < left)
  127. left = points[i].X;
  128. else if(points[i].X > right)
  129. right = points[i].X;
  130. if(points[i].Y < top)
  131. top = points[i].Y;
  132. else if(points[i].Y > bottom)
  133. bottom = points[i].Y;
  134. }
  135. GpPointF quad[4];
  136. quad[0] = points[0];
  137. quad[1] = points[1];
  138. quad[3] = points[2];
  139. if(count == 4)
  140. {
  141. A.X = points[0].X - points[1].X - points[2].X + points[3].X;
  142. A.Y = points[0].Y - points[1].Y - points[2].Y + points[3].Y;
  143. quad[2] = points[3];
  144. }
  145. else
  146. {
  147. // This is a palallelogram.
  148. A.X = 0;
  149. A.Y = 0;
  150. // Obtain the fourth vertex.
  151. REAL x3 = points[1].X + points[2].X - points[0].X;
  152. REAL y3 = points[1].Y + points[2].Y - points[0].Y;
  153. if(x3 < left)
  154. left = x3;
  155. else if(x3 > right)
  156. right = x3;
  157. if(y3 < top)
  158. top = y3;
  159. else if(y3 > bottom)
  160. bottom = y3;
  161. quad[2].X = x3;
  162. quad[2].Y = y3;
  163. }
  164. B.X = points[1].X - points[0].X;
  165. B.Y = points[1].Y - points[0].Y;
  166. C.X = points[2].X - points[0].X;
  167. C.Y = points[2].Y - points[0].Y;
  168. D = points[0];
  169. if(A.X != C.X || A.Y != C.Y)
  170. C_VV = A.X*C.Y - A.Y*C.X;
  171. else
  172. C_VV = 0;
  173. C_V = B.X*C.Y - B.Y*C.X;
  174. DstBounds.X = left;
  175. DstBounds.Y = top;
  176. DstBounds.Width = right - left;
  177. DstBounds.Height = bottom - top;
  178. QAnalyzer.SetQuadAnalyzer(&quad[0]);
  179. FixedValue = fixed;
  180. #ifdef TEST_QUADTRANSFORMS
  181. // For testing purpose only.
  182. GpMemcpy(&Verteces[0], points, count*sizeof(GpPointF));
  183. if(count == 3)
  184. {
  185. // Set the fourth vertex.
  186. Verteces[3].X = points[1].X + points[2].X - points[0].X;
  187. Verteces[3].Y = points[1].Y + points[2].Y - points[0].Y;
  188. }
  189. #endif
  190. return Ok;
  191. }
  192. /**************************************************************************\
  193. *
  194. * Function Description:
  195. *
  196. * Solve the quadratic equation of a branch which reduces
  197. * to x = - c/b when a is very small. This returns the number of
  198. * appropriate solution which is either 0 or 1.
  199. *
  200. * a x^2 + b x + c = 0.
  201. *
  202. * 12/22/1999 ikkof
  203. * Created it.
  204. \**************************************************************************/
  205. INT solveQuadraticEquationForQuadTransform(REAL a, REAL b, REAL c, REAL* x)
  206. {
  207. INT n = 0;
  208. REAL x1 = 0, x2 = 0;
  209. if(a != 0)
  210. {
  211. REAL D = b*b - 4*a*c;
  212. if(D > 0)
  213. {
  214. n = 2;
  215. D = REALSQRT(D);
  216. if(b >= 0)
  217. {
  218. x1 = (2*c)/(-b - D);
  219. x2 = (-b - D)/(2*a);
  220. }
  221. else
  222. {
  223. x1 = (2*c)/(-b + D);
  224. x2 = (-b + D)/(2*a);
  225. }
  226. if(x1 < 0 || x1 > 1)
  227. {
  228. if(x2 >= 0 && x2 <= 1)
  229. {
  230. REAL temp = x1;
  231. x1 = x2;
  232. x2 = temp;
  233. }
  234. }
  235. }
  236. else if(D == 0)
  237. {
  238. n = 1;
  239. x1 = - b/(2*a);
  240. }
  241. }
  242. else
  243. {
  244. // This is a linear equation.
  245. if(b != 0)
  246. {
  247. n = 1;
  248. x1 = - c/b;
  249. }
  250. }
  251. x[0] = x1;
  252. x[1] = x2;
  253. return n;
  254. }
  255. /**************************************************************************\
  256. *
  257. * Function Description:
  258. *
  259. * This returns the x-spans of the current quad at given y
  260. * between xmin and xmax.
  261. *
  262. * Arguments:
  263. *
  264. * [OUT] xSpans - the x-spans
  265. * [IN] y - y-coordinate to evaluate.
  266. * [IN] xmin - the minimum x (inclusive)
  267. * [IN] xmax - the maximum x (exclusive)
  268. *
  269. * Return Value:
  270. *
  271. * INT - Retuns the number of x-span pairs (0, 1, or 2).
  272. *
  273. * Created:
  274. *
  275. * 01/04/2000 ikkof
  276. *
  277. \**************************************************************************/
  278. INT
  279. GpBilinearTransform::GetXSpans(
  280. INT* xSpans,
  281. INT y,
  282. INT xmin,
  283. INT xmax
  284. )
  285. {
  286. REAL realY = TOREAL(y);
  287. if(
  288. realY < DstBounds.Y
  289. || realY >= DstBounds.Y + DstBounds.Height
  290. || TOREAL(xmax) < DstBounds.X
  291. || TOREAL(xmin) >= DstBounds.X + DstBounds.Width
  292. )
  293. return 0; // Do the quick rejection.
  294. REAL x[4];
  295. INT index = (QAnalyzer.GetXSpans(&x[0], realY) << 1);
  296. // Sort x in ascending order.
  297. if(index >= 2)
  298. {
  299. for(INT i = 0; i < index - 1; i++)
  300. {
  301. for(INT j = i + 1; j < index; j++)
  302. {
  303. if(x[j] < x[i])
  304. {
  305. REAL temp = x[i];
  306. x[i] = x[j];
  307. x[j] = temp;
  308. }
  309. }
  310. }
  311. }
  312. else
  313. return 0; // No x-span in the given y.
  314. // Check for the first span.
  315. if(x[0] >= xmax || x[1] <= xmin)
  316. {
  317. x[0] = x[2];
  318. x[1] = x[3];
  319. index -= 2;
  320. }
  321. else
  322. {
  323. x[0] = max(x[0], xmin);
  324. x[1] = min(x[1], xmax);
  325. }
  326. if(index >= 4)
  327. {
  328. // Check for the second span
  329. if(x[2] >= xmax || x[3] <= xmin)
  330. index -= 2;
  331. else
  332. {
  333. x[2] = max(x[2], xmin);
  334. x[3] = min(x[3], xmax);
  335. }
  336. }
  337. INT j = 0;
  338. for(INT i = 0; i < index; i += 2)
  339. {
  340. // Use Ceiling for both since xmin is inclusive
  341. // and xmax is exclusive (hence the real inclusive
  342. // span is being bounded by Celing and Floor).
  343. xSpans[j] = GpCeiling(x[i]);
  344. xSpans[j + 1] = GpCeiling(x[i+1]);
  345. if(xSpans[j + 1] > xSpans[j])
  346. j += 2;
  347. }
  348. return j/2;
  349. }
  350. BOOL
  351. GpBilinearTransform::GetSourceParameter(
  352. REAL* u,
  353. REAL* v,
  354. const GpPointF& point
  355. )
  356. {
  357. if (FixedValue >= 0)
  358. {
  359. *u = FixedValue;
  360. *v = FixedValue;
  361. return TRUE;
  362. }
  363. REAL b, c, vv[2];
  364. GpPointF dD;
  365. dD.X = D.X - point.X;
  366. dD.Y = D.Y - point.Y;
  367. b = C_V + A.X*dD.Y - A.Y*dD.X;
  368. c = B.X*dD.Y - B.Y*dD.X;
  369. INT num = solveQuadraticEquationForQuadTransform(C_VV, b, c, &vv[0]);
  370. if(num == 0)
  371. return FALSE;
  372. REAL u1 = 0, v1 = 0, u2 = 0, v2 = 0;
  373. BOOL firstSolutionOk = FALSE;
  374. BOOL secondSolutionOk = FALSE;
  375. firstSolutionOk = TRUE;
  376. v1 = vv[0];
  377. REAL denomX = A.X*v1 + B.X;
  378. REAL denomY = A.Y*v1 + B.Y;
  379. if(REALABS(denomX) > REALABS(denomY))
  380. {
  381. u1 = - (C.X*v1 + dD.X)/denomX;
  382. }
  383. else if(REALABS(denomY) > 0)
  384. {
  385. u1 = - (C.Y*v1 + dD.Y)/denomY;
  386. }
  387. else // Both denomX and denomY = 0.
  388. firstSolutionOk = FALSE;
  389. if(num == 2)
  390. {
  391. // Allow 1 % error between 0 and 1.
  392. if(u1 < -0.02f || u1 > 1.02f || v1 < -0.02f || v1 > 1.02f || !firstSolutionOk)
  393. {
  394. // We may be picking a wrong solution. Evaluate the other.
  395. secondSolutionOk = TRUE;
  396. v2 = vv[1];
  397. denomX = A.X*v2 + B.X;
  398. denomY = A.Y*v2 + B.Y;
  399. if(REALABS(denomX) > REALABS(denomY))
  400. {
  401. u2 = - (C.X*v2 + dD.X)/denomX;
  402. }
  403. else if(REALABS(denomY) > 0)
  404. {
  405. u2 = - (C.Y*v2 + dD.Y)/denomY;
  406. }
  407. else // Both denomX and denomY = 0.
  408. secondSolutionOk = FALSE;
  409. // Allow 1 % error between 0 and 1.
  410. if(secondSolutionOk
  411. && u2 >= - 0.02f && u2 <= 1.02f && v2 >= -0.02f && v2 <= 1.02f)
  412. {
  413. REAL temp = u1;
  414. u1 = u2;
  415. u2 = temp;
  416. temp = v1;
  417. v1 = v2;
  418. v2 = temp;
  419. }
  420. else secondSolutionOk = FALSE;
  421. }
  422. }
  423. if(firstSolutionOk || secondSolutionOk > 0)
  424. {
  425. u[0] = u1;
  426. v[0] = v1;
  427. u[1] = u2;
  428. v[1] = v2;
  429. return TRUE; // success
  430. }
  431. else
  432. return FALSE; // no valid parameter.
  433. }
  434. /**************************************************************************\
  435. *
  436. * Function Description:
  437. *
  438. * This returns the x-spans and uv arrays of the current quad at given y
  439. * between xmin and xmax.
  440. *
  441. * Arguments:
  442. *
  443. * [OUT] u - u-array
  444. * [OUT] v - v-array
  445. * [OUT] xSpans - the x-spans
  446. * [IN] y - y-coordinate to evaluate.
  447. * [IN] xmin - the minimum x (inclusive)
  448. * [IN] xmax - the maximum x (exclusive)
  449. *
  450. * Return Value:
  451. *
  452. * INT - Retuns the number of x-span pairs (0, 1, or 2).
  453. *
  454. * Created:
  455. *
  456. * 01/04/2000 ikkof
  457. *
  458. \**************************************************************************/
  459. INT
  460. GpBilinearTransform::GetSourceParameterArrays(
  461. REAL* u,
  462. REAL* v,
  463. INT* xSpans,
  464. INT y,
  465. INT xmin,
  466. INT xmax
  467. )
  468. {
  469. ASSERT(u && v && xSpans);
  470. INT pairCount = GetXSpans(xSpans, y, xmin, xmax);
  471. INT count = 0;
  472. REAL u1[2], v1[2];
  473. GpMemset(&u1[0], 0, 2*sizeof(REAL));
  474. GpMemset(&v1[0], 0, 2*sizeof(REAL));
  475. for(INT k = 0; k < pairCount; k++)
  476. {
  477. GpPointF destPt;
  478. destPt.Y = TOREAL(y);
  479. destPt.X = TOREAL(xSpans[2*k]);
  480. BOOL firstPoint = TRUE;
  481. INT width = xSpans[2*k + 1] - xSpans[2*k];
  482. for(INT i = 0; i < width; i++)
  483. {
  484. BOOL success = GetSourceParameter(&u1[0], &v1[0], destPt);
  485. if(!success)
  486. WARNING(("There is no solution for quadratic equation."));
  487. *(u + count) = u1[0];
  488. *(v + count) = v1[0];
  489. count++;
  490. destPt.X += 1;
  491. }
  492. }
  493. return pairCount;
  494. }
  495. /**************************************************************************\
  496. *
  497. * This converts lines to quadratic Beziers.
  498. *
  499. * [IN] points: the line points
  500. * [IN] count: the number of line points.
  501. * [OUT] q: the quadratic Bezier control points.
  502. *
  503. * The array size of q must be larger than or equal to 2*count - 1.
  504. *
  505. \**************************************************************************/
  506. GpStatus
  507. GpBilinearTransform::ConvertLines(
  508. const GpPointF* points,
  509. INT count,
  510. GpPointF* q)
  511. {
  512. ASSERT(points && q);
  513. ASSERT(count >= 2);
  514. REAL mx, my, nx, ny;
  515. GpPointF pt1, pt2;
  516. pt1 = points[0];
  517. INT j = 0;
  518. for(INT i = 1; i < count; i++)
  519. {
  520. pt2 = points[i];
  521. mx = (pt2.X - pt1.X)/SrcRect.Width;
  522. my = (pt2.Y - pt1.Y)/SrcRect.Height;
  523. nx = (pt1.X - SrcRect.X)/SrcRect.Width;
  524. ny = (pt1.Y - SrcRect.Y)/SrcRect.Height;
  525. GpPointF c0, c1, c2;
  526. REAL temp;
  527. temp = mx*my;
  528. c2.X = temp*A.X;
  529. c2.Y = temp*A.Y;
  530. temp = mx*ny + my*nx;
  531. c1.X = temp*A.X + mx*B.X + my*C.X;
  532. c1.Y = temp*A.Y + mx*B.Y + my*C.Y;
  533. temp = nx*ny;
  534. c0.X = temp*A.X + nx*B.X + ny*C.X + D.X;
  535. c0.Y = temp*A.Y + nx*B.Y + ny*C.Y + D.Y;
  536. if(j == 0)
  537. q[j++] = c0;
  538. q[j].X = c0.X + c1.X/2;
  539. q[j++].Y = c0.Y + c1.Y/2;
  540. q[j].X = c0.X + c1.X + c2.X;
  541. q[j++].Y = c0.Y + c1.Y + c2.Y;
  542. pt1 = pt2;
  543. }
  544. return Ok;
  545. }
  546. /**************************************************************************\
  547. *
  548. * This converts lines to quadratic Beziers.
  549. *
  550. * [IN] points: the line points
  551. * [IN] count: the number of line points.
  552. * [OUT] data: the quadratic Bezier control points.
  553. *
  554. * The array size of q must be larger than or equal to 2*(2*count - 1).
  555. *
  556. \**************************************************************************/
  557. GpStatus
  558. GpBilinearTransform::ConvertLines(
  559. const GpPointF* points,
  560. INT count,
  561. REALD* data)
  562. {
  563. ASSERT(points && data);
  564. ASSERT(count >= 2);
  565. REALD mx, my, nx, ny;
  566. GpPointF pt1, pt2;
  567. pt1 = points[0];
  568. INT j = 0;
  569. for(INT i = 1; i < count; i++)
  570. {
  571. pt2 = points[i];
  572. mx = (pt2.X - pt1.X)/SrcRect.Width;
  573. my = (pt2.Y - pt1.Y)/SrcRect.Height;
  574. nx = (pt1.X - SrcRect.X)/SrcRect.Width;
  575. ny = (pt1.Y - SrcRect.Y)/SrcRect.Height;
  576. GpPointD c0, c1, c2;
  577. REALD temp;
  578. temp = mx*my;
  579. c2.X = temp*A.X;
  580. c2.Y = temp*A.Y;
  581. temp = mx*ny + my*nx;
  582. c1.X = temp*A.X + mx*B.X + my*C.X;
  583. c1.Y = temp*A.Y + mx*B.Y + my*C.Y;
  584. temp = nx*ny;
  585. c0.X = temp*A.X + nx*B.X + ny*C.X + D.X;
  586. c0.Y = temp*A.Y + nx*B.Y + ny*C.Y + D.Y;
  587. if(j == 0)
  588. {
  589. *data++ = c0.X;
  590. *data++ = c0.Y;
  591. j++;
  592. }
  593. *data++ = c0.X + c1.X/2;
  594. *data++ = c0.Y + c1.Y/2;
  595. *data++ = c0.X + c1.X + c2.X;
  596. *data++ = c0.Y + c1.Y + c2.Y;
  597. j += 2;
  598. pt1 = pt2;
  599. }
  600. return Ok;
  601. }
  602. /**************************************************************************\
  603. *
  604. * This converts cubic Beziers to 6-th order Beziers.
  605. *
  606. * [IN] points: the cubic Bezier control points
  607. * [IN] count: the number of the control points.
  608. * [OUT] q: the 6-th order Bezier control points.
  609. *
  610. * The array size of q must be larger than or equal to 2*count - 1.
  611. *
  612. \**************************************************************************/
  613. GpStatus
  614. GpBilinearTransform::ConvertCubicBeziers(
  615. const GpPointF* srcQ,
  616. INT count,
  617. GpPointF* q
  618. )
  619. {
  620. ASSERT(srcQ && q);
  621. ASSERT(count > 3 && (count % 3 == 1));
  622. GpPointF a0, a1, a2, a3;
  623. INT j = 0;
  624. for(INT i = 1; i < count; i += 3)
  625. {
  626. a0.X = (srcQ[i - 1].X - SrcRect.X)/SrcRect.Width;
  627. a0.Y = (srcQ[i - 1].Y - SrcRect.Y)/SrcRect.Height;
  628. a1.X = 3*(srcQ[i].X - srcQ[i - 1].X)/SrcRect.Width;
  629. a1.Y = 3*(srcQ[i].Y - srcQ[i - 1].Y)/SrcRect.Height;
  630. a2.X = 3*(srcQ[i - 1].X - srcQ[i].X - srcQ[i].X + srcQ[i + 1].X)/SrcRect.Width;
  631. a2.Y = 3*(srcQ[i - 1].Y - srcQ[i].Y - srcQ[i].Y + srcQ[i + 1].Y)/SrcRect.Height;
  632. a3.X = (srcQ[i + 2].X - srcQ[i - 1].X + 3*(srcQ[i].X - srcQ[i + 1].X))/SrcRect.Width;
  633. a3.Y = (srcQ[i + 2].Y - srcQ[i - 1].Y + 3*(srcQ[i].Y - srcQ[i + 1].Y))/SrcRect.Height;
  634. REAL temp;
  635. GpPointF c[7];
  636. temp = a3.X*a3.Y;
  637. c[6].X = temp*A.X;
  638. c[6].Y = temp*A.Y;
  639. temp = a3.X*a2.Y + a2.X*a3.Y;
  640. c[5].X = temp*A.X;
  641. c[5].Y = temp*A.Y;
  642. temp = a3.X*a1.Y + a2.X*a2.Y + a1.X*a3.Y;
  643. c[4].X = temp*A.X;
  644. c[4].Y = temp*A.Y;
  645. temp = a3.X*a0.Y + a2.X*a1.Y + a1.X*a2.Y + a0.X*a3.Y;
  646. c[3].X = temp*A.X + a3.X*B.X + a3.Y*C.X;
  647. c[3].Y = temp*A.Y + a3.X*B.Y + a3.Y*C.Y;
  648. temp = a2.X*a0.Y + a1.X*a1.Y + a0.X*a2.Y;
  649. c[2].X = temp*A.X + a2.X*B.X + a2.Y*C.X;
  650. c[2].Y = temp*A.Y + a2.X*B.Y + a2.Y*C.Y;
  651. temp = a1.X*a0.Y + a0.X*a1.Y;
  652. c[1].X = temp*A.X + a1.X*B.X + a1.Y*C.X;
  653. c[1].Y = temp*A.Y + a1.X*B.Y + a1.Y*C.Y;
  654. temp = a0.X*a0.Y;
  655. c[0].X = temp*A.X + a0.X*B.X + a0.Y*C.X + D.X;
  656. c[0].Y = temp*A.Y + a0.X*B.Y + a0.Y*C.Y + D.Y;
  657. if(j == 0)
  658. q[j++] = c[0];
  659. q[j].X = c[0].X + c[1].X/6;
  660. q[j++].Y = c[0].Y + c[1].Y/6;
  661. q[j].X = c[0].X + c[1].X/3 + c[2].X/15;
  662. q[j++].Y = c[0].Y + c[1].Y/3 + c[2].Y/15;
  663. q[j].X = c[0].X + c[1].X/2 + c[2].X/5 + c[3].X/20;
  664. q[j++].Y = c[0].Y + c[1].Y/2 + c[2].Y/5 + c[3].Y/20;
  665. q[j].X = c[0].X + 2*c[1].X/3 + 2*c[2].X/5 + c[3].X/5 + c[4].X/15;
  666. q[j++].Y = c[0].Y + 2*c[1].Y/3 + 2*c[2].Y/5 + c[3].Y/5 + c[4].Y/15;
  667. q[j].X = c[0].X + 5*c[1].X/6 + 2*c[2].X/3 + c[3].X/2 + c[4].X/3 + c[5].X/6;
  668. q[j++].Y = c[0].Y + 5*c[1].Y/6 + 2*c[2].Y/3 + c[3].Y/2 + c[4].Y/3 + c[5].Y/6;
  669. q[j].X = c[0].X + c[1].X + c[2].X + c[3].X + c[4].X + c[5].X + c[6].X;
  670. q[j++].Y = c[0].Y + c[1].Y + c[2].Y + c[3].Y + c[4].Y + c[5].Y + c[6].Y;
  671. }
  672. return Ok;
  673. }
  674. /**************************************************************************\
  675. *
  676. * This converts cubic Beziers to 6-th order Beziers.
  677. *
  678. * [IN] points: the cubic Bezier control points
  679. * [IN] count: the number of the control points.
  680. * [OUT] q: the 6-th order Bezier control points.
  681. *
  682. * The array size of q must be larger than or equal to 2*count - 1.
  683. *
  684. \**************************************************************************/
  685. GpStatus
  686. GpBilinearTransform::ConvertCubicBeziers(
  687. const GpPointF* srcQ,
  688. INT count,
  689. REALD* data
  690. )
  691. {
  692. ASSERT(srcQ && data);
  693. ASSERT(count > 3 && (count % 3 == 1));
  694. GpPointD a0, a1, a2, a3;
  695. INT j = 0;
  696. for(INT i = 1; i < count; i += 3)
  697. {
  698. a0.X = (srcQ[i - 1].X - SrcRect.X)/SrcRect.Width;
  699. a0.Y = (srcQ[i - 1].Y - SrcRect.Y)/SrcRect.Height;
  700. a1.X = 3*(srcQ[i].X - srcQ[i - 1].X)/SrcRect.Width;
  701. a1.Y = 3*(srcQ[i].Y - srcQ[i - 1].Y)/SrcRect.Height;
  702. a2.X = 3*(srcQ[i - 1].X - srcQ[i].X - srcQ[i].X + srcQ[i + 1].X)/SrcRect.Width;
  703. a2.Y = 3*(srcQ[i - 1].Y - srcQ[i].Y - srcQ[i].Y + srcQ[i + 1].Y)/SrcRect.Height;
  704. a3.X = (srcQ[i + 2].X - srcQ[i - 1].X + 3*(srcQ[i].X - srcQ[i + 1].X))/SrcRect.Width;
  705. a3.Y = (srcQ[i + 2].Y - srcQ[i - 1].Y + 3*(srcQ[i].Y - srcQ[i + 1].Y))/SrcRect.Height;
  706. REALD temp;
  707. GpPointD c[7];
  708. temp = a3.X*a3.Y;
  709. c[6].X = temp*A.X;
  710. c[6].Y = temp*A.Y;
  711. temp = a3.X*a2.Y + a2.X*a3.Y;
  712. c[5].X = temp*A.X;
  713. c[5].Y = temp*A.Y;
  714. temp = a3.X*a1.Y + a2.X*a2.Y + a1.X*a3.Y;
  715. c[4].X = temp*A.X;
  716. c[4].Y = temp*A.Y;
  717. temp = a3.X*a0.Y + a2.X*a1.Y + a1.X*a2.Y + a0.X*a3.Y;
  718. c[3].X = temp*A.X + a3.X*B.X + a3.Y*C.X;
  719. c[3].Y = temp*A.Y + a3.X*B.Y + a3.Y*C.Y;
  720. temp = a2.X*a0.Y + a1.X*a1.Y + a0.X*a2.Y;
  721. c[2].X = temp*A.X + a2.X*B.X + a2.Y*C.X;
  722. c[2].Y = temp*A.Y + a2.X*B.Y + a2.Y*C.Y;
  723. temp = a1.X*a0.Y + a0.X*a1.Y;
  724. c[1].X = temp*A.X + a1.X*B.X + a1.Y*C.X;
  725. c[1].Y = temp*A.Y + a1.X*B.Y + a1.Y*C.Y;
  726. temp = a0.X*a0.Y;
  727. c[0].X = temp*A.X + a0.X*B.X + a0.Y*C.X + D.X;
  728. c[0].Y = temp*A.Y + a0.X*B.Y + a0.Y*C.Y + D.Y;
  729. if(j == 0)
  730. {
  731. *data++ = c[0].X;
  732. *data++ = c[0].Y;
  733. j++;
  734. }
  735. *data++ = c[0].X + c[1].X/6;
  736. *data++ = c[0].Y + c[1].Y/6;
  737. *data++ = c[0].X + c[1].X/3 + c[2].X/15;
  738. *data++ = c[0].Y + c[1].Y/3 + c[2].Y/15;
  739. *data++ = c[0].X + c[1].X/2 + c[2].X/5 + c[3].X/20;
  740. *data++ = c[0].Y + c[1].Y/2 + c[2].Y/5 + c[3].Y/20;
  741. *data++ = c[0].X + 2*c[1].X/3 + 2*c[2].X/5 + c[3].X/5 + c[4].X/15;
  742. *data++ = c[0].Y + 2*c[1].Y/3 + 2*c[2].Y/5 + c[3].Y/5 + c[4].Y/15;
  743. *data++ = c[0].X + 5*c[1].X/6 + 2*c[2].X/3 + c[3].X/2 + c[4].X/3 + c[5].X/6;
  744. *data++ = c[0].Y + 5*c[1].Y/6 + 2*c[2].Y/3 + c[3].Y/2 + c[4].Y/3 + c[5].Y/6;
  745. *data++ = c[0].X + c[1].X + c[2].X + c[3].X + c[4].X + c[5].X + c[6].X;
  746. *data++ = c[0].Y + c[1].Y + c[2].Y + c[3].Y + c[4].Y + c[5].Y + c[6].Y;
  747. j += 6;
  748. }
  749. return Ok;
  750. }
  751. /**************************************************************************\
  752. *
  753. * P0 P1
  754. * ------------
  755. * | \
  756. * | \
  757. * | \
  758. * | \
  759. * ----------------\
  760. * P2 P3
  761. *
  762. \**************************************************************************/
  763. GpPerspectiveTransform::GpPerspectiveTransform(
  764. const GpRectF& rect,
  765. const GpPointF* pts,
  766. INT count
  767. )
  768. {
  769. ASSERT(count == 3 || count == 4)
  770. SrcRect = rect;
  771. REAL left, right, top, bottom;
  772. left = right = pts[0].X;
  773. top = bottom = pts[0].Y;
  774. for(INT i = 1; i < count; i++)
  775. {
  776. if(pts[i].X < left)
  777. left = pts[i].X;
  778. else if(pts[i].X > right)
  779. right = pts[i].X;
  780. if(pts[i].Y < top)
  781. top = pts[i].Y;
  782. else if(pts[i].Y > bottom)
  783. bottom = pts[i].Y;
  784. }
  785. if(count == 4)
  786. {
  787. REAL dx1, dx2, dy1, dy2;
  788. REAL sx, sy, det;
  789. dx1 = pts[1].X - pts[3].X;
  790. dy1 = pts[1].Y - pts[3].Y;
  791. dx2 = pts[2].X - pts[3].X;
  792. dy2 = pts[2].Y - pts[3].Y;
  793. sx = pts[0].X - pts[1].X - pts[2].X + pts[3].X;
  794. sy = pts[0].Y - pts[1].Y - pts[2].Y + pts[3].Y;
  795. det = dx1*dy2 - dy1*dx2;
  796. M02 = (sx*dy2 - sy*dx2)/det;
  797. M12 = (dx1*sy - dy1*sx)/det;
  798. }
  799. else
  800. {
  801. // This is a palallelogram.
  802. M02 = 0;
  803. M12 = 0;
  804. // Obtain the fourth vertex.
  805. REAL x3 = pts[1].X + pts[2].X - pts[0].X;
  806. REAL y3 = pts[1].Y + pts[2].Y - pts[0].Y;
  807. if(x3 < left)
  808. left = x3;
  809. else if(x3 > right)
  810. right = x3;
  811. if(y3 < top)
  812. top = y3;
  813. else if(y3 > bottom)
  814. bottom = y3;
  815. }
  816. M00 = pts[1].X - pts[0].X + M02*pts[1].X;
  817. M01 = pts[1].Y - pts[0].Y + M02*pts[1].Y;
  818. M10 = pts[2].X - pts[0].X + M12*pts[2].X;
  819. M11 = pts[2].Y - pts[0].Y + M12*pts[2].Y;
  820. M20 = pts[0].X;
  821. M21 = pts[0].Y;
  822. M22 = 1;
  823. DstBounds.X = left;
  824. DstBounds.Y = top;
  825. DstBounds.Width = right - left;
  826. DstBounds.Height = bottom - top;
  827. }
  828. /**************************************************************************\
  829. *
  830. * This converts the points to the perspective points
  831. *
  832. * [IN] points: the point data
  833. * [IN] count: the number of points.
  834. * [OUT] q: the perspective point data.
  835. *
  836. * The array size of q must be larger than or equal to count.
  837. *
  838. \**************************************************************************/
  839. GpStatus
  840. GpPerspectiveTransform::ConvertPoints(
  841. const GpPointF* points,
  842. INT count,
  843. GpPoint3F* q
  844. )
  845. {
  846. ASSERT(points && q);
  847. ASSERT(count > 0);
  848. const GpPointF* pts = points;
  849. GpPoint3F* qPts = q;
  850. while(count > 0)
  851. {
  852. REAL u, v;
  853. u = (pts->X - SrcRect.X)/SrcRect.Width;
  854. v = (pts->Y - SrcRect.Y)/SrcRect.Height;
  855. qPts->X = u*M00 + v*M10 + M20;
  856. qPts->Y = u*M01 + v*M11 + M21;
  857. qPts->Z = u*M02 + v*M12 + 1;
  858. pts++;
  859. qPts++;
  860. count--;
  861. }
  862. return Ok;
  863. }
  864. /**************************************************************************\
  865. *
  866. * This converts the points to the perspective points
  867. *
  868. * [IN] points: the point data
  869. * [IN] count: the number of points.
  870. * [OUT] xpoints: the perspective point data.
  871. *
  872. *
  873. \**************************************************************************/
  874. GpStatus
  875. GpPerspectiveTransform::ConvertPoints(
  876. const GpPointF* points,
  877. INT count,
  878. GpXPoints* xpoints
  879. )
  880. {
  881. ASSERT(points && xpoints && count > 0);
  882. if(!points || !xpoints || count <= 0)
  883. return InvalidParameter;
  884. REALD* data = xpoints->Data;
  885. /*
  886. REALD* data = (REALD*) GpMalloc(3*count*sizeof(REALD));
  887. if(!data)
  888. return OutOfMemory;
  889. // Use this data for xpoints.
  890. xpoints->SetData(data, 3, count, FALSE);
  891. */
  892. const GpPointF* pts = points;
  893. while(count > 0)
  894. {
  895. REAL u, v;
  896. u = (pts->X - SrcRect.X)/SrcRect.Width;
  897. v = (pts->Y - SrcRect.Y)/SrcRect.Height;
  898. *data++ = u*M00 + v*M10 + M20;
  899. *data++ = u*M01 + v*M11 + M21;
  900. *data++ = u*M02 + v*M12 + 1;
  901. pts++;
  902. count--;
  903. }
  904. return Ok;
  905. }
  906. class GpQuadData
  907. {
  908. GpBilinearTransform BLTransform;
  909. GpQuadData();
  910. GpStatus SetQuad(
  911. const GpRectF& rect,
  912. const GpPointF* points
  913. );
  914. GpStatus OutputSpan(ARGB* buffer, INT compositingMode,
  915. INT y, INT &xMin, INT &xMax);
  916. };
  917. GpStatus
  918. GpQuadData::SetQuad(
  919. const GpRectF& rect,
  920. const GpPointF* points
  921. )
  922. {
  923. return BLTransform.SetBilinearTransform(rect, points, 4);
  924. }