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.

840 lines
16 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * mesh.cxx
  8. *
  9. * Abstract:
  10. *
  11. * Implementation of spline meshes
  12. *
  13. * Revision History:
  14. *
  15. * 01/18/1999 davidx
  16. * Created it.
  17. *
  18. \**************************************************************************/
  19. #include "precomp.hxx"
  20. //
  21. // Mesh constructor
  22. //
  23. Mesh::Mesh(
  24. INT gridRows,
  25. INT gridCols
  26. )
  27. {
  28. this->gridRows = gridRows;
  29. this->gridCols = gridCols;
  30. ptTemp = NULL;
  31. ptxTemp1 = ptxTemp2 = NULL;
  32. dstSize.cx = dstSize.cy = 2;
  33. mesh = new PointX[gridRows*gridCols];
  34. if (mesh == NULL)
  35. Error("Couldn't allocate memory to hold mesh grids\n");
  36. initMesh();
  37. }
  38. //
  39. // Mesh destructor
  40. //
  41. Mesh::~Mesh()
  42. {
  43. delete[] mesh;
  44. delete[] ptTemp;
  45. delete[] ptxTemp1;
  46. delete[] ptxTemp2;
  47. }
  48. //
  49. // Initialize mesh configuration
  50. //
  51. VOID
  52. Mesh::initMesh()
  53. {
  54. PointX* p = mesh;
  55. double sx = 1.0 / (gridCols-1);
  56. double sy = 1.0 / (gridRows-1);
  57. for (INT row=0; row < gridRows; row++)
  58. {
  59. double y = row * sy;
  60. for (INT col=0; col < gridCols; col++)
  61. {
  62. p->x = col * sx;
  63. p->y = y;
  64. p++;
  65. }
  66. }
  67. }
  68. //
  69. // Allocate temporary memory to hold
  70. //
  71. VOID
  72. Mesh::allocTempPoints()
  73. {
  74. // Check to see if we have already allocated
  75. // temporary memory for holding spline and bezier points
  76. if (ptTemp)
  77. return;
  78. INT count = max(gridRows, gridCols);
  79. ptxTemp1 = new PointX[count];
  80. ptxTemp2 = new PointX[3*count+1];
  81. ptTemp = new POINT[3*count+1];
  82. if (!ptxTemp1 || !ptxTemp2 || !ptTemp)
  83. Error("Out of memory\n");
  84. }
  85. //
  86. // Convert a spline curve to Bezier segments
  87. //
  88. VOID
  89. Mesh::spline2Bezier(
  90. const PointX* srcPts,
  91. PointX* dstPts,
  92. INT count
  93. )
  94. {
  95. const PointX* p;
  96. PointX tempPts[4];
  97. // We use the default tension of 0.5
  98. double a3 = 0.5 / 3;
  99. *dstPts = *srcPts;
  100. for (INT i=0; i < count; i++)
  101. {
  102. if (i > 1 && i < count-1)
  103. p = srcPts + (i-1);
  104. else
  105. {
  106. tempPts[0] = srcPts[(i > 0) ? (i-1) : 0];
  107. tempPts[1] = srcPts[i];
  108. tempPts[2] = srcPts[(i+1 < count) ? (i+1) : count];
  109. tempPts[3] = srcPts[(i+2 < count) ? (i+2) : count];
  110. p = tempPts;
  111. }
  112. dstPts[1].x = -a3*p[0].x + p[1].x + a3*p[2].x;
  113. dstPts[1].y = -a3*p[0].y + p[1].y + a3*p[2].y;
  114. dstPts[2].x = a3*p[1].x + p[2].x - a3*p[3].x;
  115. dstPts[2].y = a3*p[1].y + p[2].y - a3*p[3].y;
  116. dstPts[3] = p[2];
  117. dstPts += 3;
  118. }
  119. }
  120. //
  121. // Return the beizer control points corresponding to
  122. // the specified row of the mesh.
  123. //
  124. PointX*
  125. Mesh::getMeshRowBeziers(
  126. INT row,
  127. INT* pointCount,
  128. double sx,
  129. double sy
  130. )
  131. {
  132. allocTempPoints();
  133. PointX* ptx = mesh + indexOf(row);
  134. for (INT i=0; i < gridCols; i++)
  135. {
  136. ptxTemp1[i].x = ptx[i].x * sx;
  137. ptxTemp1[i].y = ptx[i].y * sy;
  138. }
  139. INT segments = gridCols-1;
  140. spline2Bezier(ptxTemp1, ptxTemp2, segments);
  141. *pointCount = 3*segments + 1;
  142. return ptxTemp2;
  143. }
  144. POINT*
  145. Mesh::getMeshRowBeziers(
  146. INT row,
  147. INT* pointCount
  148. )
  149. {
  150. PointX* ptx;
  151. ptx = getMeshRowBeziers(row, pointCount, dstSize.cx - 1, dstSize.cy - 1);
  152. PointX::convertToPOINT(ptx, ptTemp, *pointCount);
  153. return ptTemp;
  154. }
  155. //
  156. // Return the beizer control points corresponding to
  157. // the specified column of the mesh.
  158. //
  159. PointX*
  160. Mesh::getMeshColumnBeziers(
  161. INT col,
  162. INT* pointCount,
  163. double sx,
  164. double sy
  165. )
  166. {
  167. allocTempPoints();
  168. INT i, j;
  169. for (i=0, j=col; i < gridRows; i++, j+=gridCols)
  170. {
  171. ptxTemp1[i].x = mesh[j].x * sx;
  172. ptxTemp1[i].y = mesh[j].y * sy;
  173. }
  174. INT segments = gridRows-1;
  175. spline2Bezier(ptxTemp1, ptxTemp2, segments);
  176. *pointCount = 3*segments + 1;
  177. return ptxTemp2;
  178. }
  179. POINT*
  180. Mesh::getMeshColumnBeziers(
  181. INT col,
  182. INT* pointCount
  183. )
  184. {
  185. PointX* ptx;
  186. ptx = getMeshColumnBeziers(col, pointCount, dstSize.cx - 1, dstSize.cy - 1);
  187. PointX::convertToPOINT(ptxTemp2, ptTemp, *pointCount);
  188. return ptTemp;
  189. }
  190. //
  191. // Return the mesh control points for the specified row
  192. //
  193. POINT*
  194. Mesh::getMeshRowPoints(
  195. INT row,
  196. INT* pointCount
  197. )
  198. {
  199. allocTempPoints();
  200. POINT* pt = ptTemp;
  201. PointX* ptx = mesh + indexOf(row);
  202. double sx = dstSize.cx - 1;
  203. double sy = dstSize.cy - 1;
  204. for (INT j=0; j < gridCols; j++)
  205. {
  206. pt[j].x = ROUND2INT(ptx[j].x * sx);
  207. pt[j].y = ROUND2INT(ptx[j].y * sy);
  208. }
  209. return pt;
  210. }
  211. //
  212. // Return the specified mesh control point (given row & column)
  213. //
  214. VOID
  215. Mesh::getMeshPoint(
  216. INT row,
  217. INT col,
  218. POINT* point
  219. )
  220. {
  221. INT index = indexOf(row, col);
  222. point->x = ROUND2INT(mesh[index].x * (dstSize.cx - 1));
  223. point->y = ROUND2INT(mesh[index].y * (dstSize.cy - 1));
  224. }
  225. //
  226. // Set a mesh control point to the specified values
  227. //
  228. BOOL
  229. Mesh::setMeshPoint(
  230. INT row,
  231. INT col,
  232. INT x,
  233. INT y
  234. )
  235. {
  236. // special case for mesh control points along the border
  237. if ((row == 0 && y != 0) ||
  238. (row == gridRows-1 && y != dstSize.cy-1) ||
  239. (col == 0 && x != 0) ||
  240. (col == gridCols-1 && x != dstSize.cx-1))
  241. {
  242. return FALSE;
  243. }
  244. double tx, ty;
  245. tx = (double) x / (dstSize.cx - 1);
  246. ty = (double) y / (dstSize.cy - 1);
  247. // quick test to ensure the mesh control point
  248. // is well-ordered relative to its four neighbors
  249. if (col > 0 && tx <= mesh[indexOf(row, col-1)].x ||
  250. col < gridCols-1 && tx >= mesh[indexOf(row, col+1)].x ||
  251. row > 0 && ty <= mesh[indexOf(row-1, col)].y ||
  252. row < gridRows-1 && ty >= mesh[indexOf(row+1, col)].y)
  253. {
  254. return FALSE;
  255. }
  256. INT index = indexOf(row, col);
  257. PointX ptx = mesh[index];
  258. mesh[index].x = tx;
  259. mesh[index].y = ty;
  260. // verify the mesh row and mesh column is single-valued
  261. if (verifyRow(row) && verifyColumn(col))
  262. return TRUE;
  263. // if not, reject the mesh control point
  264. mesh[index] = ptx;
  265. return FALSE;
  266. }
  267. //
  268. // Verify that the specified mesh row is well-ordered
  269. //
  270. BOOL
  271. Mesh::verifyRow(INT row)
  272. {
  273. INT count;
  274. PointX* points = getMeshRowBeziers(row, &count, dstSize.cx, dstSize.cy);
  275. while (count > 3)
  276. {
  277. if (!verifyBezierX(points))
  278. return FALSE;
  279. points += 3;
  280. count -= 3;
  281. }
  282. return TRUE;
  283. }
  284. //
  285. // Verify that the specified mesh column is well-ordered
  286. //
  287. BOOL
  288. Mesh::verifyColumn(INT col)
  289. {
  290. INT count;
  291. PointX* points = getMeshColumnBeziers(col, &count, dstSize.cx, dstSize.cy);
  292. while (count > 3)
  293. {
  294. if (!verifyBezierY(points))
  295. return FALSE;
  296. points += 3;
  297. count -= 3;
  298. }
  299. return TRUE;
  300. }
  301. //
  302. // Check if a Bezier segment is well-ordered in the x-direction
  303. //
  304. BOOL
  305. Mesh::verifyBezierX(
  306. PointX* pts
  307. )
  308. {
  309. double a, b, c, d;
  310. // get the quadratic equation for x'(t)
  311. a = 3.0 * (3*pts[1].x + pts[3].x - pts[0].x - 3*pts[2].x);
  312. b = 6.0 * (pts[0].x - 2*pts[1].x + pts[2].x);
  313. c = 3.0 * (pts[1].x - pts[0].x);
  314. // solve t for x'(t) = 0
  315. d = b*b - 4*a*c;
  316. if (d <= 0 || a == 0)
  317. return TRUE;
  318. // if both solution are between 0 <= t <= 1
  319. // then the Bezier curve is not well-ordered in x-direction
  320. double t1, t2;
  321. d = sqrt(d);
  322. a = 0.5 / a;
  323. t1 = (d - b) * a;
  324. t2 = -(d + b) * a;
  325. return t1 < 0 || t1 > 1 ||
  326. t2 < 0 || t2 > 1;
  327. }
  328. //
  329. // Check if a Bezier segment is well-ordered in the y-direction
  330. //
  331. BOOL
  332. Mesh::verifyBezierY(
  333. PointX* pts
  334. )
  335. {
  336. double a, b, c, d;
  337. // get the quadratic equation for y'(t)
  338. a = 3.0 * (3*pts[1].y + pts[3].y - pts[0].y - 3*pts[2].y);
  339. b = 6.0 * (pts[0].y - 2*pts[1].y + pts[2].y);
  340. c = 3.0 * (pts[1].y - pts[0].y);
  341. // solve t for y'(t) = 0
  342. d = b*b - 4*a*c;
  343. if (d <= 0 || a == 0)
  344. return TRUE;
  345. // if both solution are between 0 <= t <= 1
  346. // then the Bezier curve is not well-ordered in y-direction
  347. double t1, t2;
  348. d = sqrt(d);
  349. a = 0.5 / a;
  350. t1 = (d - b) * a;
  351. t2 = -(d + b) * a;
  352. return t1 < 0 || t1 > 1 ||
  353. t2 < 0 || t2 > 1;
  354. }
  355. //
  356. // Return a new MeshIterator object so that we can
  357. // step along the y-direction and get the scale factors
  358. // for each scanline.
  359. //
  360. MeshIterator*
  361. Mesh::getYIterator(
  362. INT srcWidth,
  363. INT dstWidth,
  364. INT ySteps
  365. )
  366. {
  367. MeshIterator* iterator;
  368. iterator = new MeshIterator(srcWidth, dstWidth, ySteps, gridCols);
  369. if (iterator == NULL)
  370. Error("Out of memory\n");
  371. PointX* ptx;
  372. INT count;
  373. for (INT col=0; col < gridCols; col++)
  374. {
  375. ptx = getMeshColumnBeziers(col, &count, dstWidth-1, ySteps-1);
  376. // swap x and y coordinates
  377. for (INT i=0; i < count; i++)
  378. {
  379. double t = ptx[i].x;
  380. ptx[i].x = ptx[i].y;
  381. ptx[i].y = t;
  382. }
  383. iterator->addCurve(ptx, count);
  384. }
  385. return iterator;
  386. }
  387. //
  388. // Return a new MeshIterator object so that we can
  389. // step along the y-direction and get the scale factors
  390. // for each vertical column of pixels.
  391. //
  392. MeshIterator*
  393. Mesh::getXIterator(
  394. INT srcHeight,
  395. INT dstHeight,
  396. INT xSteps
  397. )
  398. {
  399. MeshIterator* iterator;
  400. iterator = new MeshIterator(srcHeight, dstHeight, xSteps, gridRows);
  401. if (iterator == NULL)
  402. Error("Out of memory\n");
  403. PointX* ptx;
  404. INT count;
  405. for (INT row=0; row < gridRows; row++)
  406. {
  407. ptx = getMeshRowBeziers(row, &count, xSteps-1, dstHeight-1);
  408. iterator->addCurve(ptx, count);
  409. }
  410. return iterator;
  411. }
  412. //
  413. // MeshIterator constructor
  414. //
  415. MeshIterator::MeshIterator(
  416. INT srcLen,
  417. INT dstLen,
  418. INT steps,
  419. INT maxCurves
  420. )
  421. {
  422. if (maxCurves > MAXCURVES)
  423. Error("Too many curves in MeshIterator constructor\n");
  424. this->srcLen = srcLen;
  425. this->dstLen = dstLen;
  426. this->steps = steps;
  427. this->maxCurves = maxCurves;
  428. curveCount = 0;
  429. for (INT i=0; i < MAXCURVES; i++)
  430. curves[i] = NULL;
  431. }
  432. //
  433. // MeshIterator - destructor
  434. //
  435. MeshIterator::~MeshIterator()
  436. {
  437. for (INT i=0; i < MAXCURVES; i++)
  438. delete curves[i];
  439. }
  440. //
  441. // MeshIterator - add another curve
  442. //
  443. VOID
  444. MeshIterator::addCurve(
  445. const PointX* pts,
  446. INT count
  447. )
  448. {
  449. if (curveCount == maxCurves)
  450. Error("Program error in MeshIterator::addCurve\n");
  451. FlatCurve* curve = new FlatCurve(pts, count);
  452. if (curve == NULL)
  453. Error("Out of memory\n");
  454. curves[curveCount++] = curve;
  455. }
  456. //
  457. // MeshIterator - get out positions
  458. //
  459. VOID
  460. MeshIterator::getOutPos(
  461. INT index,
  462. double* outpos
  463. )
  464. {
  465. if (curveCount != maxCurves ||
  466. index < 0 || index >= steps)
  467. {
  468. Error("Program error in MeshIterator::getOutPos\n");
  469. }
  470. INT i, j;
  471. double scale;
  472. double x = index;
  473. for (i=0; i < maxCurves; i++)
  474. stops[i] = curves[i]->getPos(x);
  475. scale = 1.0 / (srcLen-1);
  476. for (i=0; i < srcLen; i++)
  477. {
  478. j = i * (maxCurves-1) / (srcLen-1);
  479. INT i0 = (srcLen-1) * j / (maxCurves-1);
  480. if (i == i0)
  481. outpos[i] = stops[j];
  482. else
  483. {
  484. INT i1 = (srcLen-1) * (j+1) / (maxCurves-1);
  485. outpos[i] = stops[j] + (stops[j+1] - stops[j]) * (i-i0) / (i1-i0);
  486. }
  487. }
  488. outpos[srcLen] = dstLen;
  489. }
  490. //
  491. // FlatCurve constructor
  492. //
  493. FlatCurve::FlatCurve(
  494. const PointX* pts,
  495. INT count
  496. )
  497. {
  498. capacity = elementCount = 0;
  499. allocIncr = count * 3;
  500. allocIncr = (allocIncr + 31) & ~31;
  501. pointArray = NULL;
  502. lastIndex = 0;
  503. while (count > 3)
  504. {
  505. addBezierFlatten(pts);
  506. count -= 3;
  507. pts += 3;
  508. }
  509. }
  510. //
  511. // FlatCurve destructor
  512. //
  513. FlatCurve::~FlatCurve()
  514. {
  515. free(pointArray);
  516. }
  517. //
  518. // FlatCurve - add a flattened bezier segment
  519. //
  520. VOID
  521. FlatCurve::addBezierFlatten(
  522. const PointX* pts
  523. )
  524. {
  525. BOOL flatEnough;
  526. double dx, dy, distSq;
  527. PointX tempPts[4];
  528. static const double epsilon = 0.00001;
  529. static const double flatness = 1;
  530. static const double flatness2 = flatness*flatness;
  531. //
  532. // Determine if the Bezier curve is flat enough
  533. //
  534. // Algorithm
  535. // Given 3 points (Ax, Ay), (Bx, By), and (Cx, Cy),
  536. // the distance from C to line AB is:
  537. // dx = Bx - Ax
  538. // dy = By - Ay
  539. // L = sqrt(dx*dx + dy*dy)
  540. // dist = (dy * (Cx - Ax) - dx * (Cy - Ay))/ L
  541. //
  542. dx = pts[3].x - pts[0].x;
  543. dy = pts[3].y - pts[0].y;
  544. distSq = dx*dx + dy*dy;
  545. if (distSq < epsilon)
  546. {
  547. // if P0 and P3 are too close
  548. flatEnough = PointX::getSquareDist(pts[0], pts[1]) <= flatness2 &&
  549. PointX::getSquareDist(pts[2], pts[3]) <= flatness2;
  550. }
  551. else
  552. {
  553. // check if P1 is close enough to line P0-P3
  554. double s;
  555. s = dy*(pts[1].x - pts[0].x) - dx*(pts[1].y - pts[0].y);
  556. s *= s;
  557. distSq *= flatness2;
  558. if (s > distSq)
  559. flatEnough = FALSE;
  560. else
  561. {
  562. // check if P2 is close enough to line P0-P3
  563. s = dy*(pts[2].x - pts[0].x) - dx*(pts[2].y - pts[0].y);
  564. flatEnough = (s*s <= distSq);
  565. }
  566. }
  567. //
  568. // If Bezier segment is already flat enough, we're done
  569. //
  570. if (flatEnough)
  571. {
  572. addLine(pts[0], pts[3]);
  573. return;
  574. }
  575. //
  576. // Otherwise, we need to subdivide
  577. //
  578. tempPts[0] = pts[0];
  579. tempPts[1].x = (pts[0].x + pts[1].x) * 0.5;
  580. tempPts[1].y = (pts[0].y + pts[1].y) * 0.5;
  581. tempPts[2].x = (pts[0].x + pts[2].x) * 0.25 + pts[1].x * 0.5;
  582. tempPts[2].y = (pts[0].y + pts[2].y) * 0.25 + pts[1].y * 0.5;
  583. tempPts[3].x = (pts[0].x + pts[3].x) * 0.125 +
  584. (pts[1].x + pts[2].x) * 0.375;
  585. tempPts[3].y = (pts[0].y + pts[3].y) * 0.125 +
  586. (pts[1].y + pts[2].y) * 0.375;
  587. addBezierFlatten(tempPts);
  588. tempPts[0] = tempPts[3];
  589. tempPts[1].x = (pts[1].x + pts[3].x) * 0.25 + pts[2].x * 0.5;
  590. tempPts[1].y = (pts[1].y + pts[3].y) * 0.25 + pts[2].y * 0.5;
  591. tempPts[2].x = (pts[2].x + pts[3].x) * 0.5;
  592. tempPts[2].y = (pts[2].y + pts[3].y) * 0.5;
  593. tempPts[3] = pts[3];
  594. addBezierFlatten(tempPts);
  595. }
  596. //
  597. // FlatCurve - add a line segment
  598. //
  599. VOID
  600. FlatCurve::addLine(
  601. const PointX& p1,
  602. const PointX& p2
  603. )
  604. {
  605. // make sure we have enough space
  606. if (capacity < elementCount+2)
  607. {
  608. capacity += allocIncr;
  609. pointArray = (PointX*) realloc(pointArray, capacity*sizeof(PointX));
  610. if (pointArray == NULL)
  611. Error("Out of memory\n");
  612. }
  613. // add the first end point of the line, if necessary
  614. if (elementCount == 0 ||
  615. p1.x != pointArray[elementCount-1].x ||
  616. p1.y != pointArray[elementCount-1].y)
  617. {
  618. pointArray[elementCount++] = p1;
  619. }
  620. // add the second end point
  621. pointArray[elementCount++] = p2;
  622. }
  623. //
  624. // FlatCurve - calculate the value of the curve at a given position
  625. //
  626. double
  627. FlatCurve::getPos(
  628. double x
  629. )
  630. {
  631. while (lastIndex < elementCount && pointArray[lastIndex].x < x)
  632. lastIndex++;
  633. if (lastIndex == elementCount)
  634. return pointArray[elementCount-1].y;
  635. if (pointArray[lastIndex].x == x)
  636. return pointArray[lastIndex].y;
  637. double x0 = pointArray[lastIndex-1].x;
  638. double y0 = pointArray[lastIndex-1].y;
  639. return y0 + (x - x0) * (pointArray[lastIndex].y - y0) /
  640. (pointArray[lastIndex].x - x0);
  641. }