Audio plugin host https://kx.studio/carla
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.

835 lines
22KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. const int juce_edgeTableDefaultEdgesPerLine = 32;
  16. //==============================================================================
  17. EdgeTable::EdgeTable (Rectangle<int> area, const Path& path, const AffineTransform& transform)
  18. : bounds (area),
  19. // this is a very vague heuristic to make a rough guess at a good table size
  20. // for a given path, such that it's big enough to mostly avoid remapping, but also
  21. // not so big that it's wasteful for simple paths.
  22. maxEdgesPerLine (jmax (juce_edgeTableDefaultEdgesPerLine / 2,
  23. 4 * (int) std::sqrt (path.data.size()))),
  24. lineStrideElements (maxEdgesPerLine * 2 + 1)
  25. {
  26. allocate();
  27. int* t = table;
  28. for (int i = bounds.getHeight(); --i >= 0;)
  29. {
  30. *t = 0;
  31. t += lineStrideElements;
  32. }
  33. auto leftLimit = bounds.getX() * 256;
  34. auto topLimit = bounds.getY() * 256;
  35. auto rightLimit = bounds.getRight() * 256;
  36. auto heightLimit = bounds.getHeight() * 256;
  37. PathFlatteningIterator iter (path, transform);
  38. while (iter.next())
  39. {
  40. auto y1 = roundToInt (iter.y1 * 256.0f);
  41. auto y2 = roundToInt (iter.y2 * 256.0f);
  42. if (y1 != y2)
  43. {
  44. y1 -= topLimit;
  45. y2 -= topLimit;
  46. auto startY = y1;
  47. int direction = -1;
  48. if (y1 > y2)
  49. {
  50. std::swap (y1, y2);
  51. direction = 1;
  52. }
  53. if (y1 < 0)
  54. y1 = 0;
  55. if (y2 > heightLimit)
  56. y2 = heightLimit;
  57. if (y1 < y2)
  58. {
  59. const double startX = 256.0f * iter.x1;
  60. const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
  61. auto stepSize = jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier)));
  62. do
  63. {
  64. auto step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
  65. auto x = roundToInt (startX + multiplier * ((y1 + (step >> 1)) - startY));
  66. if (x < leftLimit)
  67. x = leftLimit;
  68. else if (x >= rightLimit)
  69. x = rightLimit - 1;
  70. addEdgePoint (x, y1 >> 8, direction * step);
  71. y1 += step;
  72. }
  73. while (y1 < y2);
  74. }
  75. }
  76. }
  77. sanitiseLevels (path.isUsingNonZeroWinding());
  78. }
  79. EdgeTable::EdgeTable (Rectangle<int> rectangleToAdd)
  80. : bounds (rectangleToAdd),
  81. maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
  82. lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1)
  83. {
  84. allocate();
  85. table[0] = 0;
  86. auto x1 = rectangleToAdd.getX() << 8;
  87. auto x2 = rectangleToAdd.getRight() << 8;
  88. int* t = table;
  89. for (int i = rectangleToAdd.getHeight(); --i >= 0;)
  90. {
  91. t[0] = 2;
  92. t[1] = x1;
  93. t[2] = 255;
  94. t[3] = x2;
  95. t[4] = 0;
  96. t += lineStrideElements;
  97. }
  98. }
  99. EdgeTable::EdgeTable (const RectangleList<int>& rectanglesToAdd)
  100. : bounds (rectanglesToAdd.getBounds()),
  101. maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
  102. lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
  103. needToCheckEmptiness (true)
  104. {
  105. allocate();
  106. clearLineSizes();
  107. for (auto& r : rectanglesToAdd)
  108. {
  109. auto x1 = r.getX() << 8;
  110. auto x2 = r.getRight() << 8;
  111. auto y = r.getY() - bounds.getY();
  112. for (int j = r.getHeight(); --j >= 0;)
  113. addEdgePointPair (x1, x2, y++, 255);
  114. }
  115. sanitiseLevels (true);
  116. }
  117. EdgeTable::EdgeTable (const RectangleList<float>& rectanglesToAdd)
  118. : bounds (rectanglesToAdd.getBounds().getSmallestIntegerContainer()),
  119. maxEdgesPerLine (rectanglesToAdd.getNumRectangles() * 2),
  120. lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1)
  121. {
  122. bounds.setHeight (bounds.getHeight() + 1);
  123. allocate();
  124. clearLineSizes();
  125. for (auto& r : rectanglesToAdd)
  126. {
  127. auto x1 = roundToInt (r.getX() * 256.0f);
  128. auto x2 = roundToInt (r.getRight() * 256.0f);
  129. auto y1 = roundToInt (r.getY() * 256.0f) - (bounds.getY() << 8);
  130. auto y2 = roundToInt (r.getBottom() * 256.0f) - (bounds.getY() << 8);
  131. if (x2 <= x1 || y2 <= y1)
  132. continue;
  133. auto y = y1 >> 8;
  134. auto lastLine = y2 >> 8;
  135. if (y == lastLine)
  136. {
  137. addEdgePointPair (x1, x2, y, y2 - y1);
  138. }
  139. else
  140. {
  141. addEdgePointPair (x1, x2, y++, 255 - (y1 & 255));
  142. while (y < lastLine)
  143. addEdgePointPair (x1, x2, y++, 255);
  144. jassert (y < bounds.getHeight());
  145. addEdgePointPair (x1, x2, y, y2 & 255);
  146. }
  147. }
  148. sanitiseLevels (true);
  149. }
  150. EdgeTable::EdgeTable (Rectangle<float> rectangleToAdd)
  151. : bounds ((int) std::floor (rectangleToAdd.getX()),
  152. roundToInt (rectangleToAdd.getY() * 256.0f) >> 8,
  153. 2 + (int) rectangleToAdd.getWidth(),
  154. 2 + (int) rectangleToAdd.getHeight()),
  155. maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
  156. lineStrideElements ((juce_edgeTableDefaultEdgesPerLine * 2) + 1)
  157. {
  158. jassert (! rectangleToAdd.isEmpty());
  159. allocate();
  160. table[0] = 0;
  161. auto x1 = roundToInt (rectangleToAdd.getX() * 256.0f);
  162. auto x2 = roundToInt (rectangleToAdd.getRight() * 256.0f);
  163. auto y1 = roundToInt (rectangleToAdd.getY() * 256.0f) - (bounds.getY() << 8);
  164. auto y2 = roundToInt (rectangleToAdd.getBottom() * 256.0f) - (bounds.getY() << 8);
  165. jassert (y1 < 256);
  166. if (x2 <= x1 || y2 <= y1)
  167. {
  168. bounds.setHeight (0);
  169. return;
  170. }
  171. int lineY = 0;
  172. int* t = table;
  173. if ((y1 >> 8) == (y2 >> 8))
  174. {
  175. t[0] = 2;
  176. t[1] = x1;
  177. t[2] = y2 - y1;
  178. t[3] = x2;
  179. t[4] = 0;
  180. ++lineY;
  181. t += lineStrideElements;
  182. }
  183. else
  184. {
  185. t[0] = 2;
  186. t[1] = x1;
  187. t[2] = 255 - (y1 & 255);
  188. t[3] = x2;
  189. t[4] = 0;
  190. ++lineY;
  191. t += lineStrideElements;
  192. while (lineY < (y2 >> 8))
  193. {
  194. t[0] = 2;
  195. t[1] = x1;
  196. t[2] = 255;
  197. t[3] = x2;
  198. t[4] = 0;
  199. ++lineY;
  200. t += lineStrideElements;
  201. }
  202. jassert (lineY < bounds.getHeight());
  203. t[0] = 2;
  204. t[1] = x1;
  205. t[2] = y2 & 255;
  206. t[3] = x2;
  207. t[4] = 0;
  208. ++lineY;
  209. t += lineStrideElements;
  210. }
  211. while (lineY < bounds.getHeight())
  212. {
  213. t[0] = 0;
  214. t += lineStrideElements;
  215. ++lineY;
  216. }
  217. }
  218. EdgeTable::EdgeTable (const EdgeTable& other)
  219. {
  220. operator= (other);
  221. }
  222. EdgeTable& EdgeTable::operator= (const EdgeTable& other)
  223. {
  224. bounds = other.bounds;
  225. maxEdgesPerLine = other.maxEdgesPerLine;
  226. lineStrideElements = other.lineStrideElements;
  227. needToCheckEmptiness = other.needToCheckEmptiness;
  228. allocate();
  229. copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight());
  230. return *this;
  231. }
  232. EdgeTable::~EdgeTable()
  233. {
  234. }
  235. //==============================================================================
  236. static size_t getEdgeTableAllocationSize (int lineStride, int height) noexcept
  237. {
  238. // (leave an extra line at the end for use as scratch space)
  239. return (size_t) (lineStride * (2 + jmax (0, height)));
  240. }
  241. void EdgeTable::allocate()
  242. {
  243. table.malloc (getEdgeTableAllocationSize (lineStrideElements, bounds.getHeight()));
  244. }
  245. void EdgeTable::clearLineSizes() noexcept
  246. {
  247. int* t = table;
  248. for (int i = bounds.getHeight(); --i >= 0;)
  249. {
  250. *t = 0;
  251. t += lineStrideElements;
  252. }
  253. }
  254. void EdgeTable::copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept
  255. {
  256. while (--numLines >= 0)
  257. {
  258. memcpy (dest, src, (size_t) (src[0] * 2 + 1) * sizeof (int));
  259. src += srcLineStride;
  260. dest += destLineStride;
  261. }
  262. }
  263. void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
  264. {
  265. // Convert the table from relative windings to absolute levels..
  266. int* lineStart = table;
  267. for (int y = bounds.getHeight(); --y >= 0;)
  268. {
  269. auto num = lineStart[0];
  270. if (num > 0)
  271. {
  272. auto* items = reinterpret_cast<LineItem*> (lineStart + 1);
  273. auto* itemsEnd = items + num;
  274. // sort the X coords
  275. std::sort (items, itemsEnd);
  276. auto* src = items;
  277. auto correctedNum = num;
  278. int level = 0;
  279. while (src < itemsEnd)
  280. {
  281. level += src->level;
  282. auto x = src->x;
  283. ++src;
  284. while (src < itemsEnd && src->x == x)
  285. {
  286. level += src->level;
  287. ++src;
  288. --correctedNum;
  289. }
  290. auto corrected = std::abs (level);
  291. if (corrected >> 8)
  292. {
  293. if (useNonZeroWinding)
  294. {
  295. corrected = 255;
  296. }
  297. else
  298. {
  299. corrected &= 511;
  300. if (corrected >> 8)
  301. corrected = 511 - corrected;
  302. }
  303. }
  304. items->x = x;
  305. items->level = corrected;
  306. ++items;
  307. }
  308. lineStart[0] = correctedNum;
  309. (items - 1)->level = 0; // force the last level to 0, just in case something went wrong in creating the table
  310. }
  311. lineStart += lineStrideElements;
  312. }
  313. }
  314. void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine)
  315. {
  316. if (newNumEdgesPerLine != maxEdgesPerLine)
  317. {
  318. maxEdgesPerLine = newNumEdgesPerLine;
  319. jassert (bounds.getHeight() > 0);
  320. auto newLineStrideElements = maxEdgesPerLine * 2 + 1;
  321. HeapBlock<int> newTable (getEdgeTableAllocationSize (newLineStrideElements, bounds.getHeight()));
  322. copyEdgeTableData (newTable, newLineStrideElements, table, lineStrideElements, bounds.getHeight());
  323. table.swapWith (newTable);
  324. lineStrideElements = newLineStrideElements;
  325. }
  326. }
  327. inline void EdgeTable::remapWithExtraSpace (int numPoints)
  328. {
  329. remapTableForNumEdges (numPoints * 2);
  330. jassert (numPoints < maxEdgesPerLine);
  331. }
  332. void EdgeTable::optimiseTable()
  333. {
  334. int maxLineElements = 0;
  335. for (int i = bounds.getHeight(); --i >= 0;)
  336. maxLineElements = jmax (maxLineElements, table[i * lineStrideElements]);
  337. remapTableForNumEdges (maxLineElements);
  338. }
  339. void EdgeTable::addEdgePoint (const int x, const int y, const int winding)
  340. {
  341. jassert (y >= 0 && y < bounds.getHeight());
  342. auto* line = table + lineStrideElements * y;
  343. auto numPoints = line[0];
  344. if (numPoints >= maxEdgesPerLine)
  345. {
  346. remapWithExtraSpace (numPoints);
  347. line = table + lineStrideElements * y;
  348. }
  349. line[0] = numPoints + 1;
  350. line += numPoints * 2;
  351. line[1] = x;
  352. line[2] = winding;
  353. }
  354. void EdgeTable::addEdgePointPair (int x1, int x2, int y, int winding)
  355. {
  356. jassert (y >= 0 && y < bounds.getHeight());
  357. auto* line = table + lineStrideElements * y;
  358. auto numPoints = line[0];
  359. if (numPoints + 1 >= maxEdgesPerLine)
  360. {
  361. remapWithExtraSpace (numPoints + 1);
  362. line = table + lineStrideElements * y;
  363. }
  364. line[0] = numPoints + 2;
  365. line += numPoints * 2;
  366. line[1] = x1;
  367. line[2] = winding;
  368. line[3] = x2;
  369. line[4] = -winding;
  370. }
  371. void EdgeTable::translate (float dx, int dy) noexcept
  372. {
  373. bounds.translate ((int) std::floor (dx), dy);
  374. int* lineStart = table;
  375. auto intDx = (int) (dx * 256.0f);
  376. for (int i = bounds.getHeight(); --i >= 0;)
  377. {
  378. auto* line = lineStart;
  379. lineStart += lineStrideElements;
  380. auto num = *line++;
  381. while (--num >= 0)
  382. {
  383. *line += intDx;
  384. line += 2;
  385. }
  386. }
  387. }
  388. void EdgeTable::multiplyLevels (float amount)
  389. {
  390. int* lineStart = table;
  391. auto multiplier = (int) (amount * 256.0f);
  392. for (int y = 0; y < bounds.getHeight(); ++y)
  393. {
  394. auto numPoints = lineStart[0];
  395. auto* item = reinterpret_cast<LineItem*> (lineStart + 1);
  396. lineStart += lineStrideElements;
  397. while (--numPoints > 0)
  398. {
  399. item->level = jmin (255, (item->level * multiplier) >> 8);
  400. ++item;
  401. }
  402. }
  403. }
  404. void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherLine)
  405. {
  406. jassert (y >= 0 && y < bounds.getHeight());
  407. auto* srcLine = table + lineStrideElements * y;
  408. auto srcNum1 = *srcLine;
  409. if (srcNum1 == 0)
  410. return;
  411. auto srcNum2 = *otherLine;
  412. if (srcNum2 == 0)
  413. {
  414. *srcLine = 0;
  415. return;
  416. }
  417. auto right = bounds.getRight() << 8;
  418. // optimise for the common case where our line lies entirely within a
  419. // single pair of points, as happens when clipping to a simple rect.
  420. if (srcNum2 == 2 && otherLine[2] >= 255)
  421. {
  422. clipEdgeTableLineToRange (srcLine, otherLine[1], jmin (right, otherLine[3]));
  423. return;
  424. }
  425. bool isUsingTempSpace = false;
  426. const int* src1 = srcLine + 1;
  427. auto x1 = *src1++;
  428. const int* src2 = otherLine + 1;
  429. auto x2 = *src2++;
  430. int destIndex = 0, destTotal = 0;
  431. int level1 = 0, level2 = 0;
  432. int lastX = std::numeric_limits<int>::min(), lastLevel = 0;
  433. while (srcNum1 > 0 && srcNum2 > 0)
  434. {
  435. int nextX;
  436. if (x1 <= x2)
  437. {
  438. if (x1 == x2)
  439. {
  440. level2 = *src2++;
  441. x2 = *src2++;
  442. --srcNum2;
  443. }
  444. nextX = x1;
  445. level1 = *src1++;
  446. x1 = *src1++;
  447. --srcNum1;
  448. }
  449. else
  450. {
  451. nextX = x2;
  452. level2 = *src2++;
  453. x2 = *src2++;
  454. --srcNum2;
  455. }
  456. if (nextX > lastX)
  457. {
  458. if (nextX >= right)
  459. break;
  460. lastX = nextX;
  461. auto nextLevel = (level1 * (level2 + 1)) >> 8;
  462. jassert (isPositiveAndBelow (nextLevel, 256));
  463. if (nextLevel != lastLevel)
  464. {
  465. if (destTotal >= maxEdgesPerLine)
  466. {
  467. srcLine[0] = destTotal;
  468. if (isUsingTempSpace)
  469. {
  470. auto tempSize = (size_t) srcNum1 * 2 * sizeof (int);
  471. auto oldTemp = static_cast<int*> (alloca (tempSize));
  472. memcpy (oldTemp, src1, tempSize);
  473. remapTableForNumEdges (jmax (256, destTotal * 2));
  474. srcLine = table + lineStrideElements * y;
  475. auto* newTemp = table + lineStrideElements * bounds.getHeight();
  476. memcpy (newTemp, oldTemp, tempSize);
  477. src1 = newTemp;
  478. }
  479. else
  480. {
  481. remapTableForNumEdges (jmax (256, destTotal * 2));
  482. srcLine = table + lineStrideElements * y;
  483. }
  484. }
  485. ++destTotal;
  486. lastLevel = nextLevel;
  487. if (! isUsingTempSpace)
  488. {
  489. isUsingTempSpace = true;
  490. auto* temp = table + lineStrideElements * bounds.getHeight();
  491. memcpy (temp, src1, (size_t) srcNum1 * 2 * sizeof (int));
  492. src1 = temp;
  493. }
  494. srcLine[++destIndex] = nextX;
  495. srcLine[++destIndex] = nextLevel;
  496. }
  497. }
  498. }
  499. if (lastLevel > 0)
  500. {
  501. if (destTotal >= maxEdgesPerLine)
  502. {
  503. srcLine[0] = destTotal;
  504. remapTableForNumEdges (jmax (256, destTotal * 2));
  505. srcLine = table + lineStrideElements * y;
  506. }
  507. ++destTotal;
  508. srcLine[++destIndex] = right;
  509. srcLine[++destIndex] = 0;
  510. }
  511. srcLine[0] = destTotal;
  512. }
  513. void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2) noexcept
  514. {
  515. int* lastItem = dest + (dest[0] * 2 - 1);
  516. if (x2 < lastItem[0])
  517. {
  518. if (x2 <= dest[1])
  519. {
  520. dest[0] = 0;
  521. return;
  522. }
  523. while (x2 < lastItem[-2])
  524. {
  525. --(dest[0]);
  526. lastItem -= 2;
  527. }
  528. lastItem[0] = x2;
  529. lastItem[1] = 0;
  530. }
  531. if (x1 > dest[1])
  532. {
  533. while (lastItem[0] > x1)
  534. lastItem -= 2;
  535. auto itemsRemoved = (int) (lastItem - (dest + 1)) / 2;
  536. if (itemsRemoved > 0)
  537. {
  538. dest[0] -= itemsRemoved;
  539. memmove (dest + 1, lastItem, (size_t) dest[0] * (sizeof (int) * 2));
  540. }
  541. dest[1] = x1;
  542. }
  543. }
  544. //==============================================================================
  545. void EdgeTable::clipToRectangle (Rectangle<int> r)
  546. {
  547. auto clipped = r.getIntersection (bounds);
  548. if (clipped.isEmpty())
  549. {
  550. needToCheckEmptiness = false;
  551. bounds.setHeight (0);
  552. }
  553. else
  554. {
  555. auto top = clipped.getY() - bounds.getY();
  556. auto bottom = clipped.getBottom() - bounds.getY();
  557. if (bottom < bounds.getHeight())
  558. bounds.setHeight (bottom);
  559. for (int i = 0; i < top; ++i)
  560. table[lineStrideElements * i] = 0;
  561. if (clipped.getX() > bounds.getX() || clipped.getRight() < bounds.getRight())
  562. {
  563. auto x1 = clipped.getX() << 8;
  564. auto x2 = jmin (bounds.getRight(), clipped.getRight()) << 8;
  565. int* line = table + lineStrideElements * top;
  566. for (int i = bottom - top; --i >= 0;)
  567. {
  568. if (line[0] != 0)
  569. clipEdgeTableLineToRange (line, x1, x2);
  570. line += lineStrideElements;
  571. }
  572. }
  573. needToCheckEmptiness = true;
  574. }
  575. }
  576. void EdgeTable::excludeRectangle (Rectangle<int> r)
  577. {
  578. auto clipped = r.getIntersection (bounds);
  579. if (! clipped.isEmpty())
  580. {
  581. auto top = clipped.getY() - bounds.getY();
  582. auto bottom = clipped.getBottom() - bounds.getY();
  583. const int rectLine[] = { 4, std::numeric_limits<int>::min(), 255,
  584. clipped.getX() << 8, 0,
  585. clipped.getRight() << 8, 255,
  586. std::numeric_limits<int>::max(), 0 };
  587. for (int i = top; i < bottom; ++i)
  588. intersectWithEdgeTableLine (i, rectLine);
  589. needToCheckEmptiness = true;
  590. }
  591. }
  592. void EdgeTable::clipToEdgeTable (const EdgeTable& other)
  593. {
  594. auto clipped = other.bounds.getIntersection (bounds);
  595. if (clipped.isEmpty())
  596. {
  597. needToCheckEmptiness = false;
  598. bounds.setHeight (0);
  599. }
  600. else
  601. {
  602. auto top = clipped.getY() - bounds.getY();
  603. auto bottom = clipped.getBottom() - bounds.getY();
  604. if (bottom < bounds.getHeight())
  605. bounds.setHeight (bottom);
  606. if (clipped.getRight() < bounds.getRight())
  607. bounds.setRight (clipped.getRight());
  608. for (int i = 0; i < top; ++i)
  609. table[lineStrideElements * i] = 0;
  610. auto* otherLine = other.table + other.lineStrideElements * (clipped.getY() - other.bounds.getY());
  611. for (int i = top; i < bottom; ++i)
  612. {
  613. intersectWithEdgeTableLine (i, otherLine);
  614. otherLine += other.lineStrideElements;
  615. }
  616. needToCheckEmptiness = true;
  617. }
  618. }
  619. void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels)
  620. {
  621. y -= bounds.getY();
  622. if (y < 0 || y >= bounds.getHeight())
  623. return;
  624. needToCheckEmptiness = true;
  625. if (numPixels <= 0)
  626. {
  627. table[lineStrideElements * y] = 0;
  628. return;
  629. }
  630. auto* tempLine = static_cast<int*> (alloca ((size_t) (numPixels * 2 + 4) * sizeof (int)));
  631. int destIndex = 0, lastLevel = 0;
  632. while (--numPixels >= 0)
  633. {
  634. auto alpha = *mask;
  635. mask += maskStride;
  636. if (alpha != lastLevel)
  637. {
  638. tempLine[++destIndex] = (x << 8);
  639. tempLine[++destIndex] = alpha;
  640. lastLevel = alpha;
  641. }
  642. ++x;
  643. }
  644. if (lastLevel > 0)
  645. {
  646. tempLine[++destIndex] = (x << 8);
  647. tempLine[++destIndex] = 0;
  648. }
  649. tempLine[0] = destIndex >> 1;
  650. intersectWithEdgeTableLine (y, tempLine);
  651. }
  652. bool EdgeTable::isEmpty() noexcept
  653. {
  654. if (needToCheckEmptiness)
  655. {
  656. needToCheckEmptiness = false;
  657. int* t = table;
  658. for (int i = bounds.getHeight(); --i >= 0;)
  659. {
  660. if (t[0] > 1)
  661. return false;
  662. t += lineStrideElements;
  663. }
  664. bounds.setHeight (0);
  665. }
  666. return bounds.getHeight() == 0;
  667. }
  668. } // namespace juce