JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_EdgeTable.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255 6263 6386)
30
32 : bounds (area),
33 // this is a very vague heuristic to make a rough guess at a good table size
34 // for a given path, such that it's big enough to mostly avoid remapping, but also
35 // not so big that it's wasteful for simple paths.
36 maxEdgesPerLine (jmax (defaultEdgesPerLine / 2,
37 4 * (int) std::sqrt (path.data.size()))),
38 lineStrideElements (maxEdgesPerLine * 2 + 1)
39{
40 allocate();
41 int* t = table;
42
43 for (int i = bounds.getHeight(); --i >= 0;)
44 {
45 *t = 0;
46 t += lineStrideElements;
47 }
48
49 auto leftLimit = scale * static_cast<int64_t> (bounds.getX());
50 auto topLimit = scale * static_cast<int64_t> (bounds.getY());
51 auto rightLimit = scale * static_cast<int64_t> (bounds.getRight());
52 auto heightLimit = scale * static_cast<int64_t> (bounds.getHeight());
53
54 PathFlatteningIterator iter (path, transform);
55
56 while (iter.next())
57 {
58 const auto scaleIterY = [] (auto y)
59 {
60 return static_cast<int64_t> (y * 256.0f + (y >= 0 ? 0.5f : -0.5f));
61 };
62
63 auto y1 = scaleIterY (iter.y1);
64 auto y2 = scaleIterY (iter.y2);
65
66 if (y1 != y2)
67 {
68 y1 -= topLimit;
69 y2 -= topLimit;
70
71 auto startY = y1;
72 int direction = -1;
73
74 if (y1 > y2)
75 {
76 std::swap (y1, y2);
77 direction = 1;
78 }
79
80 if (y1 < 0)
81 y1 = 0;
82
83 if (y2 > heightLimit)
84 y2 = heightLimit;
85
86 if (y1 < y2)
87 {
88 const double startX = 256.0f * iter.x1;
89 const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
90 auto stepSize = static_cast<int64_t> (jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier))));
91
92 do
93 {
94 auto step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
95 auto x = static_cast<int64_t> (startX + multiplier * static_cast<double> ((y1 + (step >> 1)) - startY));
96 auto clampedX = static_cast<int> (jlimit (leftLimit, rightLimit - 1, x));
97
98 addEdgePoint (clampedX, static_cast<int> (y1 / scale), static_cast<int> (direction * step));
99 y1 += step;
100 }
101 while (y1 < y2);
102 }
103 }
104 }
105
106 sanitiseLevels (path.isUsingNonZeroWinding());
107}
108
110 : bounds (rectangleToAdd),
111 maxEdgesPerLine (defaultEdgesPerLine),
112 lineStrideElements (defaultEdgesPerLine * 2 + 1)
113{
114 allocate();
115 table[0] = 0;
116
117 auto x1 = scale * rectangleToAdd.getX();
118 auto x2 = scale * rectangleToAdd.getRight();
119 int* t = table;
120
121 for (int i = rectangleToAdd.getHeight(); --i >= 0;)
122 {
123 t[0] = 2;
124 t[1] = x1;
125 t[2] = 255;
126 t[3] = x2;
127 t[4] = 0;
128 t += lineStrideElements;
129 }
130}
131
133 : bounds (rectanglesToAdd.getBounds()),
134 maxEdgesPerLine (defaultEdgesPerLine),
135 lineStrideElements (defaultEdgesPerLine * 2 + 1),
136 needToCheckEmptiness (true)
137{
138 allocate();
139 clearLineSizes();
140
141 for (auto& r : rectanglesToAdd)
142 {
143 auto x1 = scale * r.getX();
144 auto x2 = scale * r.getRight();
145 auto y = r.getY() - bounds.getY();
146
147 for (int j = r.getHeight(); --j >= 0;)
148 addEdgePointPair (x1, x2, y++, 255);
149 }
150
151 sanitiseLevels (true);
152}
153
155 : bounds (rectanglesToAdd.getBounds().getSmallestIntegerContainer()),
156 maxEdgesPerLine (rectanglesToAdd.getNumRectangles() * 2),
157 lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1)
158{
159 bounds.setHeight (bounds.getHeight() + 1);
160 allocate();
161 clearLineSizes();
162
163 for (auto& r : rectanglesToAdd)
164 {
165 auto x1 = roundToInt ((float) scale * r.getX());
166 auto x2 = roundToInt ((float) scale * r.getRight());
167
168 auto y1 = roundToInt ((float) scale * r.getY()) - (bounds.getY() * scale);
169 auto y2 = roundToInt ((float) scale * r.getBottom()) - (bounds.getY() * scale);
170
171 if (x2 <= x1 || y2 <= y1)
172 continue;
173
174 auto y = y1 / scale;
175 auto lastLine = y2 / scale;
176
177 if (y == lastLine)
178 {
179 addEdgePointPair (x1, x2, y, y2 - y1);
180 }
181 else
182 {
183 addEdgePointPair (x1, x2, y++, 255 - (y1 & 255));
184
185 while (y < lastLine)
186 addEdgePointPair (x1, x2, y++, 255);
187
188 jassert (y < bounds.getHeight());
189 addEdgePointPair (x1, x2, y, y2 & 255);
190 }
191 }
192
193 sanitiseLevels (true);
194}
195
197 : bounds ((int) std::floor (rectangleToAdd.getX()),
198 roundToInt (rectangleToAdd.getY() * 256.0f) / scale,
199 2 + (int) rectangleToAdd.getWidth(),
200 2 + (int) rectangleToAdd.getHeight()),
201 maxEdgesPerLine (defaultEdgesPerLine),
202 lineStrideElements ((defaultEdgesPerLine * 2) + 1)
203{
204 jassert (! rectangleToAdd.isEmpty());
205 allocate();
206 table[0] = 0;
207
208 auto x1 = roundToInt ((float) scale * rectangleToAdd.getX());
209 auto x2 = roundToInt ((float) scale * rectangleToAdd.getRight());
210 auto y1 = roundToInt ((float) scale * rectangleToAdd.getY()) - (bounds.getY() * scale);
211 auto y2 = roundToInt ((float) scale * rectangleToAdd.getBottom()) - (bounds.getY() * scale);
212 jassert (y1 < 256);
213
214 if (x2 <= x1 || y2 <= y1)
215 {
216 bounds.setHeight (0);
217 return;
218 }
219
220 int lineY = 0;
221 int* t = table;
222
223 if ((y1 / scale) == (y2 / scale))
224 {
225 t[0] = 2;
226 t[1] = x1;
227 t[2] = y2 - y1;
228 t[3] = x2;
229 t[4] = 0;
230 ++lineY;
231 t += lineStrideElements;
232 }
233 else
234 {
235 t[0] = 2;
236 t[1] = x1;
237 t[2] = 255 - (y1 & 255);
238 t[3] = x2;
239 t[4] = 0;
240 ++lineY;
241 t += lineStrideElements;
242
243 while (lineY < (y2 / scale))
244 {
245 t[0] = 2;
246 t[1] = x1;
247 t[2] = 255;
248 t[3] = x2;
249 t[4] = 0;
250 ++lineY;
251 t += lineStrideElements;
252 }
253
254 jassert (lineY < bounds.getHeight());
255 t[0] = 2;
256 t[1] = x1;
257 t[2] = y2 & 255;
258 t[3] = x2;
259 t[4] = 0;
260 ++lineY;
261 t += lineStrideElements;
262 }
263
264 while (lineY < bounds.getHeight())
265 {
266 t[0] = 0;
267 t += lineStrideElements;
268 ++lineY;
269 }
270}
271
276
278{
279 bounds = other.bounds;
280 maxEdgesPerLine = other.maxEdgesPerLine;
281 lineStrideElements = other.lineStrideElements;
282 needToCheckEmptiness = other.needToCheckEmptiness;
283
284 allocate();
285 copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight());
286 return *this;
287}
288
292
293//==============================================================================
294static size_t getEdgeTableAllocationSize (int lineStride, int height) noexcept
295{
296 // (leave an extra line at the end for use as scratch space)
297 return (size_t) (lineStride * (2 + jmax (0, height)));
298}
299
300void EdgeTable::allocate()
301{
302 table.malloc (getEdgeTableAllocationSize (lineStrideElements, bounds.getHeight()));
303}
304
305void EdgeTable::clearLineSizes() noexcept
306{
307 int* t = table;
308
309 for (int i = bounds.getHeight(); --i >= 0;)
310 {
311 *t = 0;
312 t += lineStrideElements;
313 }
314}
315
316void EdgeTable::copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept
317{
318 while (--numLines >= 0)
319 {
320 memcpy (dest, src, (size_t) (src[0] * 2 + 1) * sizeof (int));
321 src += srcLineStride;
322 dest += destLineStride;
323 }
324}
325
326void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
327{
328 // Convert the table from relative windings to absolute levels..
329 int* lineStart = table;
330
331 for (int y = bounds.getHeight(); --y >= 0;)
332 {
333 auto num = lineStart[0];
334
335 if (num > 0)
336 {
337 auto* items = reinterpret_cast<LineItem*> (lineStart + 1);
338 auto* itemsEnd = items + num;
339
340 // sort the X coords
341 std::sort (items, itemsEnd);
342
343 auto* src = items;
344 auto correctedNum = num;
345 int level = 0;
346
347 while (src < itemsEnd)
348 {
349 level += src->level;
350 auto x = src->x;
351 ++src;
352
353 while (src < itemsEnd && src->x == x)
354 {
355 level += src->level;
356 ++src;
357 --correctedNum;
358 }
359
360 auto corrected = std::abs (level);
361
362 if (corrected / scale)
363 {
364 if (useNonZeroWinding)
365 {
366 corrected = 255;
367 }
368 else
369 {
370 corrected &= 511;
371
372 if (corrected / scale)
373 corrected = 511 - corrected;
374 }
375 }
376
377 items->x = x;
378 items->level = corrected;
379 ++items;
380 }
381
383 (items - 1)->level = 0; // force the last level to 0, just in case something went wrong in creating the table
384 }
385
386 lineStart += lineStrideElements;
387 }
388}
389
390void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine)
391{
392 if (newNumEdgesPerLine != maxEdgesPerLine)
393 {
394 maxEdgesPerLine = newNumEdgesPerLine;
395
396 jassert (bounds.getHeight() > 0);
397 auto newLineStrideElements = maxEdgesPerLine * 2 + 1;
398
399 HeapBlock<int> newTable (getEdgeTableAllocationSize (newLineStrideElements, bounds.getHeight()));
400
401 copyEdgeTableData (newTable, newLineStrideElements, table, lineStrideElements, bounds.getHeight());
402
403 table.swapWith (newTable);
404 lineStrideElements = newLineStrideElements;
405 }
406}
407
408inline void EdgeTable::remapWithExtraSpace (int numPoints)
409{
410 remapTableForNumEdges (numPoints * 2);
411 jassert (numPoints < maxEdgesPerLine);
412}
413
415{
416 int maxLineElements = 0;
417
418 for (int i = bounds.getHeight(); --i >= 0;)
419 maxLineElements = jmax (maxLineElements, table[i * lineStrideElements]);
420
421 remapTableForNumEdges (maxLineElements);
422}
423
424void EdgeTable::addEdgePoint (const int x, const int y, const int winding)
425{
426 jassert (y >= 0 && y < bounds.getHeight());
427
428 auto* line = table + lineStrideElements * y;
429 auto numPoints = line[0];
430
431 if (numPoints >= maxEdgesPerLine)
432 {
433 remapWithExtraSpace (numPoints);
434 line = table + lineStrideElements * y;
435 }
436
437 line[0] = numPoints + 1;
438 line += numPoints * 2;
439 line[1] = x;
440 line[2] = winding;
441}
442
443void EdgeTable::addEdgePointPair (int x1, int x2, int y, int winding)
444{
445 jassert (y >= 0 && y < bounds.getHeight());
446
447 auto* line = table + lineStrideElements * y;
448 auto numPoints = line[0];
449
450 if (numPoints + 1 >= maxEdgesPerLine)
451 {
452 remapWithExtraSpace (numPoints + 1);
453 line = table + lineStrideElements * y;
454 }
455
456 line[0] = numPoints + 2;
457 line += numPoints * 2;
458 line[1] = x1;
459 line[2] = winding;
460 line[3] = x2;
461 line[4] = -winding;
462}
463
464void EdgeTable::translate (float dx, int dy) noexcept
465{
466 bounds.translate ((int) std::floor (dx), dy);
467
468 int* lineStart = table;
469 auto intDx = (int) (dx * 256.0f);
470
471 for (int i = bounds.getHeight(); --i >= 0;)
472 {
473 auto* line = lineStart;
474 lineStart += lineStrideElements;
475 auto num = *line++;
476
477 while (--num >= 0)
478 {
479 *line += intDx;
480 line += 2;
481 }
482 }
483}
484
486{
487 int* lineStart = table;
488 auto multiplier = (int) (amount * 256.0f);
489
490 for (int y = 0; y < bounds.getHeight(); ++y)
491 {
492 auto numPoints = lineStart[0];
493 auto* item = reinterpret_cast<LineItem*> (lineStart + 1);
494 lineStart += lineStrideElements;
495
496 while (--numPoints > 0)
497 {
498 item->level = jmin (255, (item->level * multiplier) / scale);
499 ++item;
500 }
501 }
502}
503
504void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherLine)
505{
506 jassert (y >= 0 && y < bounds.getHeight());
507
508 auto* srcLine = table + lineStrideElements * y;
509 auto srcNum1 = *srcLine;
510
511 if (srcNum1 == 0)
512 return;
513
514 auto srcNum2 = *otherLine;
515
516 if (srcNum2 == 0)
517 {
518 *srcLine = 0;
519 return;
520 }
521
522 auto right = bounds.getRight() * scale;
523
524 // optimise for the common case where our line lies entirely within a
525 // single pair of points, as happens when clipping to a simple rect.
526 if (srcNum2 == 2 && otherLine[2] >= 255)
527 {
528 clipEdgeTableLineToRange (srcLine, otherLine[1], jmin (right, otherLine[3]));
529 return;
530 }
531
532 bool isUsingTempSpace = false;
533
534 const int* src1 = srcLine + 1;
535 auto x1 = *src1++;
536
537 const int* src2 = otherLine + 1;
538 auto x2 = *src2++;
539
540 int destIndex = 0, destTotal = 0;
541 int level1 = 0, level2 = 0;
542 int lastX = std::numeric_limits<int>::min(), lastLevel = 0;
543
544 while (srcNum1 > 0 && srcNum2 > 0)
545 {
546 int nextX;
547
548 if (x1 <= x2)
549 {
550 if (x1 == x2)
551 {
552 level2 = *src2++;
553 x2 = *src2++;
554 --srcNum2;
555 }
556
557 nextX = x1;
558 level1 = *src1++;
559 x1 = *src1++;
560 --srcNum1;
561 }
562 else
563 {
564 nextX = x2;
565 level2 = *src2++;
566 x2 = *src2++;
567 --srcNum2;
568 }
569
570 if (nextX > lastX)
571 {
572 if (nextX >= right)
573 break;
574
575 lastX = nextX;
576
577 auto nextLevel = (level1 * (level2 + 1)) / scale;
579
580 if (nextLevel != lastLevel)
581 {
582 if (destTotal >= maxEdgesPerLine)
583 {
584 srcLine[0] = destTotal;
585
587 {
588 auto tempSize = (size_t) srcNum1 * 2 * sizeof (int);
589 auto oldTemp = static_cast<int*> (alloca (tempSize));
591
592 remapTableForNumEdges (jmax (256, destTotal * 2));
593 srcLine = table + lineStrideElements * y;
594
595 auto* newTemp = table + lineStrideElements * bounds.getHeight();
597 src1 = newTemp;
598 }
599 else
600 {
601 remapTableForNumEdges (jmax (256, destTotal * 2));
602 srcLine = table + lineStrideElements * y;
603 }
604 }
605
606 ++destTotal;
608
609 if (! isUsingTempSpace)
610 {
611 isUsingTempSpace = true;
612 auto* temp = table + lineStrideElements * bounds.getHeight();
613 memcpy (temp, src1, (size_t) srcNum1 * 2 * sizeof (int));
614 src1 = temp;
615 }
616
619 }
620 }
621 }
622
623 if (lastLevel > 0)
624 {
625 if (destTotal >= maxEdgesPerLine)
626 {
627 srcLine[0] = destTotal;
628 remapTableForNumEdges (jmax (256, destTotal * 2));
629 srcLine = table + lineStrideElements * y;
630 }
631
632 ++destTotal;
634 srcLine[++destIndex] = 0;
635 }
636
637 srcLine[0] = destTotal;
638}
639
640void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2) noexcept
641{
642 int* lastItem = dest + (dest[0] * 2 - 1);
643
644 if (x2 < lastItem[0])
645 {
646 if (x2 <= dest[1])
647 {
648 dest[0] = 0;
649 return;
650 }
651
652 while (x2 < lastItem[-2])
653 {
654 --(dest[0]);
655 lastItem -= 2;
656 }
657
658 lastItem[0] = x2;
659 lastItem[1] = 0;
660 }
661
662 if (x1 > dest[1])
663 {
664 while (lastItem[0] > x1)
665 lastItem -= 2;
666
667 auto itemsRemoved = (int) (lastItem - (dest + 1)) / 2;
668
669 if (itemsRemoved > 0)
670 {
671 dest[0] -= itemsRemoved;
672 memmove (dest + 1, lastItem, (size_t) dest[0] * (sizeof (int) * 2));
673 }
674
675 dest[1] = x1;
676 }
677}
678
679
680//==============================================================================
681void EdgeTable::clipToRectangle (Rectangle<int> r)
682{
683 auto clipped = r.getIntersection (bounds);
684
685 if (clipped.isEmpty())
686 {
687 needToCheckEmptiness = false;
688 bounds.setHeight (0);
689 }
690 else
691 {
692 auto top = clipped.getY() - bounds.getY();
693 auto bottom = clipped.getBottom() - bounds.getY();
694
695 if (bottom < bounds.getHeight())
696 bounds.setHeight (bottom);
697
698 for (int i = 0; i < top; ++i)
699 table[lineStrideElements * i] = 0;
700
701 if (clipped.getX() > bounds.getX() || clipped.getRight() < bounds.getRight())
702 {
703 auto x1 = scale * clipped.getX();
704 auto x2 = scale * jmin (bounds.getRight(), clipped.getRight());
705 int* line = table + lineStrideElements * top;
706
707 for (int i = bottom - top; --i >= 0;)
708 {
709 if (line[0] != 0)
710 clipEdgeTableLineToRange (line, x1, x2);
711
712 line += lineStrideElements;
713 }
714 }
715
716 needToCheckEmptiness = true;
717 }
718}
719
720void EdgeTable::excludeRectangle (Rectangle<int> r)
721{
722 auto clipped = r.getIntersection (bounds);
723
724 if (! clipped.isEmpty())
725 {
726 auto top = clipped.getY() - bounds.getY();
727 auto bottom = clipped.getBottom() - bounds.getY();
728
729 const int rectLine[] = { 4, std::numeric_limits<int>::min(), 255,
730 scale * clipped.getX(), 0,
731 scale * clipped.getRight(), 255,
733
734 for (int i = top; i < bottom; ++i)
735 intersectWithEdgeTableLine (i, rectLine);
736
737 needToCheckEmptiness = true;
738 }
739}
740
741void EdgeTable::clipToEdgeTable (const EdgeTable& other)
742{
743 auto clipped = other.bounds.getIntersection (bounds);
744
745 if (clipped.isEmpty())
746 {
747 needToCheckEmptiness = false;
748 bounds.setHeight (0);
749 }
750 else
751 {
752 auto top = clipped.getY() - bounds.getY();
753 auto bottom = clipped.getBottom() - bounds.getY();
754
755 if (bottom < bounds.getHeight())
756 bounds.setHeight (bottom);
757
758 if (clipped.getRight() < bounds.getRight())
759 bounds.setRight (clipped.getRight());
760
761 for (int i = 0; i < top; ++i)
762 table[lineStrideElements * i] = 0;
763
764 auto* otherLine = other.table + other.lineStrideElements * (clipped.getY() - other.bounds.getY());
765
766 for (int i = top; i < bottom; ++i)
767 {
768 intersectWithEdgeTableLine (i, otherLine);
769 otherLine += other.lineStrideElements;
770 }
771
772 needToCheckEmptiness = true;
773 }
774}
775
776void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels)
777{
778 y -= bounds.getY();
779
780 if (y < 0 || y >= bounds.getHeight())
781 return;
782
783 needToCheckEmptiness = true;
784
785 if (numPixels <= 0)
786 {
787 table[lineStrideElements * y] = 0;
788 return;
789 }
790
791 auto* tempLine = static_cast<int*> (alloca ((size_t) (numPixels * 2 + 4) * sizeof (int)));
792 int destIndex = 0, lastLevel = 0;
793
794 while (--numPixels >= 0)
795 {
796 auto alpha = *mask;
797 mask += maskStride;
798
799 if (alpha != lastLevel)
800 {
801 tempLine[++destIndex] = (x * scale);
802 tempLine[++destIndex] = alpha;
803 lastLevel = alpha;
804 }
805
806 ++x;
807 }
808
809 if (lastLevel > 0)
810 {
811 tempLine[++destIndex] = (x * scale);
812 tempLine[++destIndex] = 0;
813 }
814
815 tempLine[0] = destIndex >> 1;
816
817 intersectWithEdgeTableLine (y, tempLine);
818}
819
820bool EdgeTable::isEmpty() noexcept
821{
822 if (needToCheckEmptiness)
823 {
824 needToCheckEmptiness = false;
825 int* t = table;
826
827 for (int i = bounds.getHeight(); --i >= 0;)
828 {
829 if (t[0] > 1)
830 return false;
831
832 t += lineStrideElements;
833 }
834
835 bounds.setHeight (0);
836 }
837
838 return bounds.getHeight() == 0;
839}
840
841JUCE_END_IGNORE_WARNINGS_MSVC
842
843} // namespace juce
Represents a 2D affine-transformation matrix.
A table of horizontal scan-line segments - used for rasterising Paths.
~EdgeTable()
Destructor.
EdgeTable(Rectangle< int > clipLimits, const Path &pathToAdd, const AffineTransform &transform)
Creates an edge table containing a path.
void optimiseTable()
Reduces the amount of space the table has allocated.
EdgeTable & operator=(const EdgeTable &)
Copies from another edge table.
void multiplyLevels(float factor)
Scales all the alpha-levels in the table by the given multiplier.
void swapWith(HeapBlock< ElementType, otherBlockThrows > &other) noexcept
Swaps this object's data with the data of another HeapBlock.
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory.
Flattens a Path object into a series of straight-line sections.
A path is a sequence of lines and curves that may either form a closed shape or be open-ended.
Definition juce_Path.h:65
Maintains a set of rectangles as a complex region.
Manages a rectangle and allows geometric operations to be performed on it.
ValueType getRight() const noexcept
Returns the x coordinate of the rectangle's right-hand-side.
ValueType getX() const noexcept
Returns the x coordinate of the rectangle's left-hand-side.
void setRight(ValueType newRight) noexcept
Adjusts the width so that the right-hand edge of the rectangle has this new value.
void setHeight(ValueType newHeight) noexcept
Changes the rectangle's height.
ValueType getY() const noexcept
Returns the y coordinate of the rectangle's top edge.
ValueType getHeight() const noexcept
Returns the height of the rectangle.
T floor(T... args)
floor
#define jassert(expression)
Platform-independent assertion macro.
T right(T... args)
typedef int
T max(T... args)
memcpy
memmove
T min(T... args)
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
T sort(T... args)
typedef int64_t
T swap(T... args)
typedef size_t
y1