Vital
Loading...
Searching...
No Matches
line_editor.cpp
Go to the documentation of this file.
1#include "line_editor.h"
2
4#include "full_interface.h"
5#include "fonts.h"
6#include "skin.h"
7#include "shaders.h"
9#include "utils.h"
10
11namespace {
12 Point<float> pairToPoint(std::pair<float, float> pair) {
13 return { pair.first, pair.second };
14 }
15
16 std::pair<float, float> pointToPair(Point<float> point) {
17 return { point.x, point.y };
18 }
19} // namespace
20
22 OpenGlLineRenderer(kTotalPoints),
23 drag_circle_(Shaders::kCircleFragment),
24 hover_circle_(Shaders::kRingFragment),
25 grid_lines_(kMaxGridSizeX + kMaxGridSizeY + 1),
26 position_circle_(Shaders::kRingFragment),
27 point_circles_(LineGenerator::kMaxPoints, Shaders::kRingFragment),
28 power_circles_(LineGenerator::kMaxPoints, Shaders::kCircleFragment) {
29 addAndMakeVisible(drag_circle_);
30 addAndMakeVisible(hover_circle_);
31 addAndMakeVisible(grid_lines_);
32 addAndMakeVisible(position_circle_);
33 addAndMakeVisible(point_circles_);
34 addAndMakeVisible(power_circles_);
35
36#if !defined(NO_TEXT_ENTRY)
37 value_entry_ = std::make_unique<OpenGlTextEditor>("text_entry");
38 value_entry_->setMonospace();
39 value_entry_->setMultiLine(false);
40 value_entry_->setScrollToShowCursor(false);
41 value_entry_->addListener(this);
42 value_entry_->setSelectAllWhenFocused(true);
43 value_entry_->setKeyboardType(TextEditor::numericKeyboard);
44 value_entry_->setJustification(Justification::centred);
45 addChildComponent(value_entry_.get());
46 value_entry_->setAlwaysOnTop(true);
47 value_entry_->getImageComponent()->setAlwaysOnTop(true);
48 value_entry_->setVisible(false);
49#endif
50
51 hover_circle_.setThickness(1.0f);
52
53 active_ = true;
54 model_ = line_source;
55 size_ratio_ = 1.0f;
56 loop_ = true;
57 grid_size_x_ = 1;
58 grid_size_y_ = 1;
59 paint_ = false;
60 temporary_paint_toggle_ = false;
61 entering_phase_ = false;
62 entering_index_ = -1;
63 last_model_render_ = -1;
64 paint_pattern_ = {
65 std::pair<float, float>(0.0f, 1.0f),
66 std::pair<float, float>(1.0f, 0.0f)
67 };
68
69 last_phase_ = 0.0f;
70
71 setFill(true);
72 setFillCenter(-1.0f);
73
74 active_point_ = -1;
75 active_power_ = -1;
76 active_grid_section_ = -1;
77 last_voice_ = -1.0f;
78 last_last_voice_ = -1.0f;
79 dragging_ = false;
80 reset_positions_ = true;
81 allow_file_loading_ = true;
82 drag_circle_.setActive(false);
83 hover_circle_.setActive(false);
84 setWantsKeyboardFocus(true);
85}
86
88
89int LineEditor::getHoverPoint(Point<float> position) {
90 position.x = unpadX(position.x);
91 position.y = unpadY(position.y);
92
93 float grab_radius = kGrabRadius * size_ratio_;
94 float min_distance_squared = grab_radius * grab_radius;
95 int hover_point = -1;
96
97 int num_points = model_->getNumPoints();
98 for (int i = 0; i < num_points; ++i) {
99 std::pair<float, float> point_pair = model_->getPoint(i);
100 Point<float> point_position(point_pair.first, point_pair.second);
101 point_position.x *= getWidth();
102 point_position.y *= getHeight();
103 float distance_squared = position.getDistanceSquaredFrom(point_position);
104 if (distance_squared < min_distance_squared) {
105 min_distance_squared = distance_squared;
106 hover_point = i;
107 }
108 }
109
110 return hover_point;
111}
112
113int LineEditor::getHoverPower(Point<float> position) {
114 position.x = unpadX(position.x);
115 position.y = unpadY(position.y);
116
117 float grab_radius = kGrabRadius * size_ratio_;
118 float min_distance_squared = grab_radius * grab_radius;
119 int hover_power = -1;
120
121 int num_points = model_->getNumPoints();
122 for (int i = 0; i < num_points; ++i) {
123 if (powerActive(i)) {
124 Point<float> power_position = getPowerPosition(i);
125 power_position.x *= getWidth();
126 power_position.y *= getHeight();
127 float distance_squared = position.getDistanceSquaredFrom(power_position);
128 if (distance_squared < min_distance_squared) {
129 min_distance_squared = distance_squared;
130 hover_power = i;
131 }
132 }
133 }
134
135 return hover_power;
136}
137
138float LineEditor::getSnapRadiusX() {
139 static float kGridProximity = 0.02f;
140
141 if (grid_size_x_ <= 1)
142 return 0.0f;
143 return kGridProximity;
144}
145
146float LineEditor::getSnapRadiusY() {
147 static float kGridProximity = 0.04f;
148
149 if (grid_size_y_ <= 1)
150 return 0.0f;
151 return kGridProximity;
152}
153
154float LineEditor::getSnappedX(float x) {
155 return std::roundf(x * grid_size_x_) / grid_size_x_;
156}
157
158float LineEditor::getSnappedY(float y) {
159 return std::roundf(y * grid_size_y_) / grid_size_y_;
160}
161
162void LineEditor::addPointAt(Point<float> position) {
164 return;
165
166 int index = 0;
167 float x = position.x;
168 int num_points = model_->getNumPoints();
169 for (; index < num_points; ++index) {
170 if (model_->getPoint(index).first > x)
171 break;
172 }
173
174 model_->addPoint(index, pointToPair(position));
175 model_->render();
177
178 for (Listener* listener : listeners_)
179 listener->pointAdded(index, position);
180}
181
182void LineEditor::movePoint(int index, Point<float> position, bool snap) {
183 float min_x = getMinX(index);
184 float max_x = getMaxX(index);
185 int last_point_index = model_->getNumPoints() - 1;
186
187 Point<float> local_position(position.x / getWidth(), position.y / getHeight());
188
189 local_position.x = vital::utils::clamp(local_position.x, min_x, max_x);
190 local_position.y = vital::utils::clamp(local_position.y, 0.0f, 1.0f);
191 if (snap && grid_size_x_ > 0) {
192 float snap_radius = getSnapRadiusX();
193 float snapped_x = vital::utils::clamp(getSnappedX(local_position.x), min_x, max_x);
194 if (fabsf(snapped_x - local_position.x) < snap_radius)
195 local_position.x = snapped_x;
196 }
197 if (snap && grid_size_y_ > 0) {
198 float snap_radius = getSnapRadiusY();
199 float snapped_y = getSnappedY(local_position.y);
200 if (fabsf(snapped_y - local_position.y) < snap_radius)
201 local_position.y = snapped_y;
202 }
203
204 if (loop_ && model_->getPoint(0).second == model_->getPoint(last_point_index).second) {
205 if (index == 0)
206 model_->setPoint(last_point_index, pointToPair({ 1.0f, local_position.y }));
207 else if (index == last_point_index)
208 model_->setPoint(0, pointToPair({ 0.0f, local_position.y }));
209 }
210 model_->setPoint(index, pointToPair(local_position));
211
212 model_->render();
214
215 for (Listener* listener : listeners_)
216 listener->pointChanged(index, position, false);
217}
218
219void LineEditor::movePower(int index, Point<float> position, bool all, bool alternate) {
220 float delta_change = (position.y - last_mouse_position_.y) / getHeight();
221 int start = index;
222 int end = index;
223 if (all) {
224 start = 0;
225 end = model_->getNumPoints() - 2;
226 }
227
228 float alternate_mult = 1.0f;
229 if (!alternate && model_->getPoint(index).second < model_->getPoint((index + 1) % model_->getNumPoints()).second)
230 alternate_mult = -1.0f;
231
232 for (int i = start; i <= end; ++i) {
233 float from_y = model_->getPoint(i).second;
234 float to_y = model_->getPoint((i + 1) % model_->getNumPoints()).second;
235 if (from_y == to_y)
236 continue;
237
238 float max_power = vital::SynthLfo::kMaxPower;
239 float power = model_->getPower(i);
240 float delta_amount = delta_change * alternate_mult;
241 if (from_y < to_y && alternate)
242 delta_amount *= -1.0f;
243
244 power += delta_amount * kPowerMouseMultiplier;
245 model_->setPower(i, vital::utils::clamp(power, -max_power, max_power));
246 }
247 model_->render();
249
250 for (Listener* listener : listeners_)
251 listener->powersChanged(false);
252}
253
254void LineEditor::removePoint(int index) {
255 VITAL_ASSERT(model_->getNumPoints() > 1);
256
257 model_->removePoint(index);
258 model_->render();
259
261
262 for (Listener* listener : listeners_)
263 listener->pointRemoved(index);
264}
265
266float LineEditor::getMinX(int index) {
267 if (index == 0)
268 return 0.0f;
269
270 int last_point_index = model_->getNumPoints() - 1;
271 if (index == last_point_index)
272 return 1.0f;
273 return model_->getPoint(index - 1).first;
274}
275
276float LineEditor::getMaxX(int index) {
277 if (index == 0)
278 return 0.0f;
279
280 int last_point_index = model_->getNumPoints() - 1;
281 if (index == last_point_index)
282 return 1.0f;
283
284 return model_->getPoint(index + 1).first;
285}
286
287void LineEditor::respondToCallback(int point, int power, int option) {
288 if (option == kFlipHorizontal) {
291 for (Listener* listener : listeners_)
292 listener->pointChanged(0, pairToPoint(model_->getPoint(0)), true);
293 }
294 else if (option == kFlipVertical) {
297 for (Listener* listener : listeners_)
298 listener->pointChanged(0, pairToPoint(model_->getPoint(0)), true);
299 }
300 else if (option == kRemovePoint) {
301 if (point > 0 && point < numPoints() - 1)
302 removePoint(point);
303 }
304 else if (option == kResetPower) {
305 if (power >= 0 && power < numPoints() - 1) {
306 model_->setPower(power, 0.0f);
307 model_->render();
309 }
310 }
311 else if (option == kEnterPhase || option == kEnterValue) {
312 entering_phase_ = option == kEnterPhase;
313 entering_index_ = point;
314 if (entering_index_ >= 0 && entering_index_ < model_->getNumPoints())
316 }
317 else if (option == kCopy) {
318 json json_data = model_->stateToJson();
319 SystemClipboard::copyTextToClipboard(json_data.dump());
320 }
321 else if (option == kPaste) {
322 String text = SystemClipboard::getTextFromClipboard();
323
324 try {
325 json parsed_json_state = json::parse(text.toStdString(), nullptr, false);
326 if (LineGenerator::isValidJson(parsed_json_state))
327 model_->jsonToState(parsed_json_state);
328 }
329 catch (const json::exception& e) {
330 return;
331 }
332
333 for (Listener* listener : listeners_)
334 listener->fileLoaded();
335
337 }
338 else if (option == kSave) {
339 FullInterface* parent = findParentComponentOfClass<FullInterface>();
340 if (parent == nullptr)
341 return;
342
343 parent->saveLfo(model_->stateToJson());
344 }
345 else if (option == kInit) {
346 model_->initLinear();
347 for (Listener* listener : listeners_)
348 listener->fileLoaded();
350 }
351}
352
354 String text = SystemClipboard::getTextFromClipboard();
355 try {
356 json parsed_json_state = json::parse(text.toStdString(), nullptr, false);
357 return LineGenerator::isValidJson(parsed_json_state);
358 }
359 catch (const json::exception& e) {
360 return false;
361 }
362}
363
364void LineEditor::paintLine(const MouseEvent& e) {
365 float percent_x = e.position.x / getWidth();
366 float percent_y = std::max(0.0f, std::min(1.0f, e.position.y / getHeight()));
367 active_grid_section_ = std::max<int>(0, std::min<int>(grid_size_x_ * percent_x, grid_size_x_ - 1));
368
369 float from_x = (1.0f * active_grid_section_) / grid_size_x_;
370 float to_x = (active_grid_section_ + 1.0f) / grid_size_x_;
371
372 if (!e.mods.isAltDown() && grid_size_y_ > 0) {
373 float snap_radius = getSnapRadiusY();
374 float snapped_y = getSnappedY(percent_y);
375 if (fabsf(snapped_y - percent_y) < snap_radius)
376 percent_y = snapped_y;
377 }
378
379 int from_index = -1;
380 int start_num_points = model_->getNumPoints();
381 int to_index = start_num_points;
382 for (int i = 0; i < start_num_points; ++i) {
383 if (model_->getPoint(i).first < from_x)
384 from_index = i;
385
386 int reverse_index = start_num_points - i - 1;
387 if (model_->getPoint(reverse_index).first > to_x)
388 to_index = reverse_index;
389 }
390
391 std::vector<Point<float>> new_points;
392 float from_intersect = model_->getValueAtPhase(from_x);
393 float to_intersect = model_->getValueAtPhase(to_x);
394 if (model_->getPoint(from_index + 1).first != from_x) {
395 new_points.emplace_back(Point<float>(from_x, from_intersect));
396 to_index++;
397 start_num_points++;
398 }
399 from_index++;
400
401 if (model_->getPoint(to_index - 1).first != to_x) {
402 new_points.emplace_back(Point<float>(to_x, to_intersect));
403 start_num_points++;
404 }
405 else
406 to_index--;
407
408 VITAL_ASSERT(from_index < to_index);
409
410 int pattern_length = static_cast<int>(paint_pattern_.size());
411 int delta_size = pattern_length - std::max(0, (to_index - from_index - 1));
412 int num_points = start_num_points + delta_size;
413 if (num_points >= LineGenerator::kMaxPoints)
414 return;
415
416 for (const Point<float>& new_point : new_points)
417 addPointAt(new_point);
418
419 model_->setNumPoints(num_points);
420
421 if (delta_size > 0) {
422 for (int i = num_points - 1; i >= std::max(delta_size, to_index); --i) {
423 model_->setPoint(i, model_->getPoint(i - delta_size));
424 model_->setPower(i, model_->getPower(i - delta_size));
425 }
426
427 for (Listener* listener : listeners_)
428 listener->pointsAdded(from_index + 1, delta_size);
429 }
430 else if (delta_size < 0) {
431 for (int i = from_index + 1; i < num_points; ++i) {
432 model_->setPoint(i, model_->getPoint(i - delta_size));
433 model_->setPower(i, model_->getPower(i - delta_size));
434 }
435
436 for (Listener* listener : listeners_)
437 listener->pointsRemoved(from_index + 1, -delta_size);
438 }
439
440 for (int i = 0; i < pattern_length; ++i) {
441 std::pair<float, float> pattern_point = paint_pattern_[i];
442 float t = pattern_point.first;
443 pattern_point.first = from_x * (1.0f - t) + to_x * t;
444 pattern_point.second = 1.0f - pattern_point.second * (1.0 - percent_y);
445
446 int index = from_index + 1 + i;
447 model_->setPoint(index, pattern_point);
448 model_->setPower(index, 0.0f);
449 }
450
451 model_->render();
453}
454
455void LineEditor::mouseDown(const MouseEvent& e) {
456 enableTemporaryPaintToggle(e.mods.isCommandDown());
457 if (e.mods.isPopupMenu()) {
458 PopupItems options;
459
460 int active_point = getActivePoint();
461 if (active_point >= 0) {
462 if (active_point > 0 && active_point < model_->getNumPoints() - 1) {
463 options.addItem(kRemovePoint, "Remove Point");
464 options.addItem(kEnterPhase, "Enter Point Phase");
465 }
466 options.addItem(kEnterValue, "Enter Point Value");
467 options.addItem(-1, "");
468 }
469 int active_power = getActivePower();
470 if (active_power >= 0)
471 options.addItem(kResetPower, "Reset Power");
472
473 if (allow_file_loading_) {
474 options.addItem(kCopy, "Copy");
476 options.addItem(kPaste, "Paste");
477
478 options.addItem(kSave, "Save to LFOs");
479 options.addItem(kInit, "Initialize");
480 }
481
482 options.addItem(kFlipHorizontal, "Flip Horizontal");
483 options.addItem(kFlipVertical, "Flip Vertical");
484
485 SynthSection* parent = findParentComponentOfClass<SynthSection>();
486 int point = active_point_;
487 int power = active_power_;
488 parent->showPopupSelector(this, e.getPosition(), options,
489 [=](int selection) { respondToCallback(point, power, selection); });
490 }
491 else if (isPainting())
492 paintLine(e);
493 else
494 drawDown(e);
495}
496
497void LineEditor::drawDown(const MouseEvent& e) {
498 last_mouse_position_ = e.position;
499 int hover_point = getHoverPoint(e.position);
500 if (hover_point >= 0) {
501 active_point_ = hover_point;
502 active_power_ = -1;
503 dragging_ = true;
505 }
506 else {
507 int hover_power = getHoverPower(e.position);
508 if (hover_power >= 0) {
509 active_power_ = hover_power;
510 active_point_ = -1;
511 dragging_ = true;
513 }
514 }
515}
516
517void LineEditor::mouseDoubleClick(const MouseEvent& e) {
518 if (isPainting())
519 return;
520
521 int hover_point = getHoverPoint(e.position);
522 int hover_power = getHoverPower(e.position);
523 int num_points = model_->getNumPoints();
524
525 if (hover_point >= 0) {
526 if (hover_point == 0 || hover_point == num_points - 1)
527 return;
528 if (num_points <= 1)
529 return;
530
531 removePoint(hover_point);
532 }
533 else if (hover_power >= 0) {
534 if (e.mods.isShiftDown()) {
535 for (int i = 0; i < model_->getNumPoints() - 1; ++i)
536 model_->setPower(i, 0.0f);
537 }
538 else
539 model_->setPower(hover_power, 0.0f);
540 model_->render();
542 }
543 else {
544 if (num_points >= LineGenerator::kMaxPoints)
545 return;
546
547 Point<float> position = e.position;
548 position.x /= getWidth();
549 position.y /= getHeight();
550 addPointAt(position);
551 }
552 active_point_ = getHoverPoint(e.position);
553 active_power_ = -1;
555}
556
557void LineEditor::mouseMove(const MouseEvent& e) {
558 enableTemporaryPaintToggle(e.mods.isCommandDown());
559
560 if (isPainting()) {
561 float percent_x = e.position.x / getWidth();
562 int active_section = std::max<int>(0, std::min<int>(grid_size_x_ * percent_x, grid_size_x_ - 1));
563 if (active_section != active_grid_section_) {
564 active_grid_section_ = active_section;
566 }
567 }
568 else {
569 int hovered = getHoverPoint(e.position);
570 int power_hover = -1;
571 if (hovered < 0)
572 power_hover = getHoverPower(e.position);
573
574 if (active_point_ != hovered || active_power_ != power_hover) {
575 active_point_ = hovered;
576 active_power_ = power_hover;
578 }
579 }
580}
581
582void LineEditor::mouseDrag(const MouseEvent& e) {
583 if (isPainting())
584 paintLine(e);
585 else
586 drawDrag(e);
587
588 last_mouse_position_ = e.position;
589}
590
591void LineEditor::drawDrag(const MouseEvent& e) {
592 if (!dragging_)
593 return;
594
595 if (active_point_ >= 0)
596 movePoint(active_point_, e.position, !e.mods.isAltDown());
597 else if (active_power_ >= 0)
598 movePower(active_power_, e.position, e.mods.isShiftDown(), e.mods.isAltDown());
599
601}
602
603void LineEditor::mouseUp(const MouseEvent& e) {
604 if (!isPainting())
605 drawUp(e);
606
607 enableTemporaryPaintToggle(e.mods.isCommandDown());
608}
609
610void LineEditor::drawUp(const MouseEvent& e) {
611 dragging_ = false;
613
614 if (active_point_ >= 0) {
615 for (Listener* listener : listeners_)
616 listener->pointChanged(active_point_, pairToPoint(model_->getPoint(active_point_)), true);
617 }
618 else if (active_power_ >= 0) {
619 for (Listener* listener : listeners_)
620 listener->powersChanged(true);
621 }
622}
623
624void LineEditor::mouseExit(const MouseEvent& e) {
627}
628
629void LineEditor::mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) {
630 for (Listener* listener : listeners_)
631 listener->lineEditorScrolled(e, wheel);
632}
633
635 dragging_ = false;
636 active_point_ = -1;
637 active_power_ = -1;
638 active_grid_section_ = -1;
639
641}
642
644 int num_points = model_->getNumPoints();
645 int intermediate_points = kDrawPoints - num_points;
646 Point<float> prev_point = pairToPoint(model_->lastPoint());
647 float power = model_->lastPower();
648 prev_point.x -= 1.0f;
649
650 float width = getWidth();
651 float height = getHeight();
652
653 int draw_index = 0;
654 int point_index = 0;
655 for (int i = 0; i < intermediate_points; ++i) {
656 float t = i / (intermediate_points - 1.0f);
657
658 while (point_index < num_points && t >= model_->getPoint(point_index).first) {
659 prev_point = pairToPoint(model_->getPoint(point_index));
660 power = model_->getPower(point_index);
661 setXAt(kNumWrapPoints + draw_index, padX(width * model_->getPoint(point_index).first));
662 setYAt(kNumWrapPoints + draw_index, padY(height * model_->getPoint(point_index).second));
663 point_index++;
664 draw_index++;
665 }
666
667 Point<float> next_point;
668 if (point_index < num_points) {
669 next_point = pairToPoint(model_->getPoint(point_index));
670 }
671 else {
672 next_point = pairToPoint(model_->getPoint(0));
673 next_point.x += 1.0f;
674 }
675
676 float x_distance = next_point.x - prev_point.x;
677 float point_t = 0.0f;
678 if (x_distance > 0.0f)
679 point_t = (t - prev_point.x) / x_distance;
680
681 if (model_->smooth())
682 point_t = LineGenerator::smoothTransition(point_t);
683
684 point_t = vital::futils::powerScale(point_t, power);
685
686 float val = vital::utils::interpolate(prev_point.y, next_point.y, point_t);
687
688 setXAt(kNumWrapPoints + draw_index, padX(width * t));
689 setYAt(kNumWrapPoints + draw_index, padY(height * val));
690 draw_index++;
691 }
692
693 float end_val = model_->getPoint(num_points - 1).second;
694
695 for (; draw_index < kDrawPoints; ++draw_index) {
696 setXAt(kNumWrapPoints + draw_index, padX(width));
697 setYAt(kNumWrapPoints + draw_index, padY(height * end_val));
698 }
699
700 if (loop_) {
701 for (int i = 0; i < kNumWrapPoints; ++i) {
702 setXAt(i, xAt(kDrawPoints + i) - width);
703 setYAt(i, yAt(kDrawPoints + i));
706
711 }
712 }
713 else {
714 int last_index = kNumWrapPoints + kDrawPoints - 1;
715 for (int i = 0; i < kNumWrapPoints; ++i) {
720
721 setXAt(i + kDrawPoints + kNumWrapPoints, xAt(last_index));
722 setYAt(i + kDrawPoints + kNumWrapPoints, yAt(last_index));
725 }
726 }
727}
728
729inline float LineEditor::padY(float y) {
730 float pad = size_ratio_ * kPaddingY;
731 return y * (getHeight() - 2.0f * pad) / getHeight() + pad;
732}
733
734inline float LineEditor::unpadY(float y) {
735 float pad = size_ratio_ * kPaddingY;
736 return (y - pad) * getHeight() / (getHeight() - 2.0f * pad);
737}
738
739inline float LineEditor::padX(float x) {
740 if (loop_)
741 return x;
742 float pad = size_ratio_ * kPaddingX;
743 return x * (getWidth() - 2.0f * pad) / getWidth() + pad;
744}
745
746inline float LineEditor::unpadX(float x) {
747 if (loop_)
748 return x;
749 float pad = size_ratio_ * kPaddingX;
750 return (x - pad) * getWidth() / (getWidth() - 2.0f * pad);
751}
752
755 drag_circle_.init(open_gl);
756 hover_circle_.init(open_gl);
757 grid_lines_.init(open_gl);
758 point_circles_.init(open_gl);
759 power_circles_.init(open_gl);
760 position_circle_.init(open_gl);
761}
762
763void LineEditor::renderGrid(OpenGlWrapper& open_gl, bool animate) {
764 grid_lines_.setColor(findColour(Skin::kLightenScreen, true));
765 grid_lines_.render(open_gl, animate);
766}
767
768void LineEditor::renderPoints(OpenGlWrapper& open_gl, bool animate) {
769 Colour center = findColour(Skin::kWidgetCenterLine, true);
770 if (!active_)
771 center = findColour(Skin::kWidgetPrimaryDisabled, true);
772
773 Colour background = findColour(Skin::kWidgetBackground, true);
774 point_circles_.setColor(center);
775 point_circles_.setAltColor(background);
776 point_circles_.render(open_gl, animate);
777
778 power_circles_.setColor(center);
779 power_circles_.render(open_gl, animate);
780
781 drag_circle_.setColor(findColour(Skin::kWidgetAccent2, true));
782 drag_circle_.render(open_gl, animate);
783
784 hover_circle_.setColor(findColour(Skin::kWidgetAccent1, true));
785 hover_circle_.render(open_gl, animate);
786}
787
788void LineEditor::render(OpenGlWrapper& open_gl, bool animate) {
789 if (last_model_render_ != model_->getRenderCount()) {
790 reset_positions_ = true;
791 last_model_render_ = model_->getRenderCount();
792 }
794 renderGrid(open_gl, animate);
795 OpenGlLineRenderer::render(open_gl, animate);
796 renderPoints(open_gl, animate);
797 renderCorners(open_gl, animate);
798}
799
800Point<float> LineEditor::valuesToOpenGlPosition(float x, float y) {
801 float padding_x = 2.0f * size_ratio_ * kPaddingX / getWidth();
802 float padding_y = 2.0f * size_ratio_ * kPaddingY / getHeight();
803 float adjusted_x = (x * 2.0f - 1.0f) * (1.0f - padding_x);
804 float adjusted_y = (y * 2.0f - 1.0f) * (1.0f - padding_y);
805 return Point<float>(adjusted_x, adjusted_y);
806}
807
808Point<float> LineEditor::getPowerPosition(int index) {
809 VITAL_ASSERT(index >= 0 && index < model_->getNumPoints());
810 Point<float> from = pairToPoint(model_->getPoint(index));
811 Point<float> to;
812 if (index < model_->getNumPoints() - 1)
813 to = pairToPoint(model_->getPoint(index + 1));
814 else {
815 to = pairToPoint(model_->getPoint(0));
816 to.x += 1.0f;
817 }
818
819 float x = (from.x + to.x) / 2.0f;
820 if (x >= 1.0f)
821 x -= 1.0f;
822 float power_t = vital::futils::powerScale(0.5f, model_->getPower(index));
823 float y = vital::utils::interpolate(from.y, to.y, power_t);
824 return Point<float>(x, y);
825}
826
827bool LineEditor::powerActive(int index) {
828 VITAL_ASSERT(index >= 0 && index < model_->getNumPoints());
829 Point<float> delta;
830 if (index < model_->getNumPoints() - 1)
831 delta = pairToPoint(model_->getPoint(index + 1)) - pairToPoint(model_->getPoint(index));
832 else
833 delta = pairToPoint(model_->getPoint(0)) - pairToPoint(model_->lastPoint()) + Point<float>(1.0f, 0.0f);
834
835 return getWidth() * delta.x >= kMinPointDistanceForPower && delta.y;
836}
837
838void LineEditor::drawPosition(OpenGlWrapper& open_gl, Colour color, float fraction_x) {
839 static constexpr float kCenterFade = 0.2f;
840
841 if (fraction_x == 0.0f)
842 return;
843
844 float fraction_y = model_->valueAtPhase(fraction_x);
845 Point<float> point = valuesToOpenGlPosition(fraction_x, fraction_y);
846 float x = point.x;
847 float y = point.y;
848
849 glEnable(GL_BLEND);
850 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
851
852 int draw_width = getWidth();
853 int draw_height = getHeight();
854
855 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
856 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
857
858 Colour background = findColour(Skin::kWidgetBackground, true);
859
860 float position_height = 2.0f * size_ratio_ * kPositionWidth / draw_height;
861 float position_width = 2.0f * size_ratio_ * kPositionWidth / draw_width;
862 position_circle_.setQuad(0, x - position_width * 0.5f, y - position_height * 0.5f, position_width, position_height);
863 position_circle_.setColor(color);
864 position_circle_.setAltColor(color.interpolatedWith(background, kCenterFade));
865 position_circle_.setThickness(size_ratio_ * kPositionWidth * kRingThickness * 0.5f);
866 position_circle_.render(open_gl, true);
867}
868
870 Point<float> edit_position;
871 if (active_point_ >= 0)
872 edit_position = pairToPoint(model_->getPoint(active_point_));
873 else if (active_power_ >= 0)
874 edit_position = getPowerPosition(active_power_);
875 else {
876 drag_circle_.setActive(false);
877 hover_circle_.setActive(false);
878 return;
879 }
880
881 float width = getWidth();
882 float height = getHeight();
883 float x = padX(width * edit_position.x) * 2.0f / width - 1.0f;
884 float y = 1.0f - padY(height * edit_position.y) * 2.0f / height;
885 float hover_width = size_ratio_ * kGrabRadius * 4.0f / width;
886 float hover_height = size_ratio_ * kGrabRadius * 4.0f / height;
887 float drag_width = size_ratio_ * kDragRadius * 4.0f / width;
888 float drag_height = size_ratio_ * kDragRadius * 4.0f / height;
889
890 hover_circle_.setActive(!isPainting());
891 hover_circle_.setQuad(0, x - hover_width * 0.5f, y - hover_height * 0.5f, hover_width, hover_height);
892
893 drag_circle_.setActive(dragging_);
894 if (dragging_)
895 drag_circle_.setQuad(0, x - drag_width * 0.5f, y - drag_height * 0.5f, drag_width, drag_height);
896}
897
899 int grid_size_x = grid_size_x_;
900 int grid_size_y = grid_size_y_;
901
902 float width = 2.0f / getWidth();
903 int index = 0;
904 float x_scale = 1.0f - size_ratio_ * 2.0f * kPaddingX / getWidth();
905 for (int i = 1; i < grid_size_x; ++i) {
906 float x = i * 2.0f / grid_size_x - 1.0f;
907 x *= x_scale;
908 grid_lines_.setQuad(index, x - width * 0.5f, -1.0f, width, 2.0f);
909 index++;
910 }
911
912 float height = 2.0f / getHeight();
913 float y_scale = 1.0f - size_ratio_ * 2.0f * kPaddingY / getHeight();
914 for (int i = 1; i < grid_size_y; ++i) {
915 float y = i * 2.0f / grid_size_y - 1.0f;
916 y *= y_scale;
917 grid_lines_.setQuad(index, -1.0f, y - height * 0.5f, 2.0f, height);
918 index++;
919 }
920
921 if (grid_size_x && isPainting() && active_grid_section_ >= 0) {
922 int start_x = (active_grid_section_ * getWidth()) / grid_size_x + 1;
923 int end_x = ((active_grid_section_ + 1) * getWidth()) / grid_size_x;
924 grid_lines_.setQuad(index, start_x * width - 1.0f, -1.0f, (end_x - start_x) * width, 2.0f);
925 }
926 else
927 grid_lines_.setQuad(index, -2.0f, -2.0f, 0.0f, 0.0f);
928 grid_lines_.setNumQuads(grid_size_x + grid_size_y - 1);
929}
930
932 float width = getWidth();
933 float height = getHeight();
934
935 float position_width = size_ratio_ * kPositionWidth * 2.0f / width;
936 float position_height = size_ratio_ * kPositionWidth * 2.0f / height;
937 float power_width = size_ratio_ * kPowerWidth * 2.0f / width;
938 float power_height = size_ratio_ * kPowerWidth * 2.0f / height;
939
940 point_circles_.setThickness(size_ratio_ * kPositionWidth * kRingThickness * 0.5f);
941
942 int num_points = model_->getNumPoints();
943 point_circles_.setNumQuads(num_points);
944 power_circles_.setNumQuads(num_points);
945 for (int i = 0; i < num_points; ++i) {
946 Point<float> point = pairToPoint(model_->getPoint(i));
947 float x = padX(width * point.x) * 2.0f / width - 1.0f;
948 float y = 1.0f - padY(height * point.y) * 2.0f / height;
949
950 point_circles_.setQuad(i, x - position_width * 0.5f, y - position_height * 0.5f, position_width, position_height);
951
952 if (powerActive(i)) {
953 Point<float> power_position = getPowerPosition(i);
954 x = padX(getWidth() * power_position.x) * 2.0f / width - 1.0f;
955 y = 1.0f - padY(getHeight() * power_position.y) * 2.0f / height;
956 power_circles_.setQuad(i, x - power_width * 0.5f, y - power_height * 0.5f, power_width, power_height);
957 }
958 else
959 power_circles_.setQuad(i, -2.0f, -2.0f, power_width, power_width);
960 }
961}
962
964 if (!reset_positions_)
965 return;
966
968 reset_positions_ = false;
969
973}
974
976 drag_circle_.destroy(open_gl);
977 hover_circle_.destroy(open_gl);
978 grid_lines_.destroy(open_gl);
979 point_circles_.destroy(open_gl);
980 power_circles_.destroy(open_gl);
981 position_circle_.destroy(open_gl);
983}
984
985void LineEditor::setPaint(bool paint) {
986 paint_ = paint;
987 active_point_ = -1;
988 active_power_ = -1;
989}
990
992 value_entry_->setVisible(false);
993}
994
996 static constexpr float kTextEntryHeight = 30.0f;
997 static constexpr float kTextEntryWidth = 50.0f;
998
999#if !defined(NO_TEXT_ENTRY)
1000 Point<float> point = pairToPoint(model_->getPoint(entering_index_));
1001 int entry_height = kTextEntryHeight * size_ratio_;
1002 int entry_width = kTextEntryWidth * size_ratio_;
1003 int x = std::min<int>(point.x * getWidth(), getWidth() - entry_width);
1004 int y = std::min<int>(point.y * getHeight(), getHeight() - entry_height);
1005 value_entry_->setBounds(x, y, entry_width, entry_height);
1006 if (entering_phase_)
1007 value_entry_->setText(String(point.x));
1008 else
1009 value_entry_->setText(String(1.0 - point.y));
1010 value_entry_->setVisible(true);
1011 value_entry_->grabKeyboardFocus();
1012#endif
1013}
1014
1018
1019void LineEditor::textEditorFocusLost(TextEditor& editor) {
1021}
1022
1024 hideTextEntry();
1025}
1026
1028 if (value_entry_->getText().isEmpty() || entering_index_ < 0) {
1029 hideTextEntry();
1030 return;
1031 }
1032
1033 float value = value_entry_->getText().getFloatValue();
1034 if (entering_phase_) {
1035 value = std::max(std::min(value, getMaxX(entering_index_)), getMinX(entering_index_));
1036 Point<float> point = pairToPoint(model_->getPoint(entering_index_));
1037 point.x = value;
1038 model_->setPoint(entering_index_, pointToPair(point));
1039 }
1040 else {
1041 value = std::max(std::min(value, 1.0f), 0.0f);
1042 Point<float> point = pairToPoint(model_->getPoint(entering_index_));
1043 float start_y = point.y;
1044 point.y = 1.0f - value;
1045 model_->setPoint(entering_index_, pointToPair(point));
1046 if (entering_index_ == 0 && pairToPoint(model_->getPoint(model_->getNumPoints() - 1)).y == start_y) {
1047 point.x = 1.0f;
1048 model_->setPoint(model_->getNumPoints() - 1, pointToPair(point));
1049 }
1050 else if (entering_index_ == model_->getNumPoints() - 1 && pairToPoint(model_->getPoint(0)).y == start_y) {
1051 point.x = 0.0f;
1052 model_->setPoint(0, pointToPair(point));
1053 }
1054 }
1055
1056 model_->render();
1057 hideTextEntry();
1059}
1060
1062 vital::poly_float result;
1063 result.set(0, adjustBoostPhase(phase[0]));
1064 result.set(1, adjustBoostPhase(phase[1]));
1065 return result;
1066}
1067
1068float LineEditor::adjustBoostPhase(float phase) {
1069 int num_points = model_->getNumPoints();
1070 int points_to_left = 0;
1071
1072 for (; points_to_left < num_points; ++points_to_left) {
1073 if (model_->getPoint(points_to_left).first >= phase)
1074 break;
1075 }
1076
1077 return (phase * kDrawPoints + points_to_left) / (kDrawPoints + num_points);
1078}
1079
1081 if (temporary_paint_toggle_ == toggle)
1082 return;
1083
1084 temporary_paint_toggle_ = toggle;
1085
1086 for (Listener* listener : listeners_)
1087 listener->togglePaintMode(isPaintEnabled(), toggle);
1088
1090}
The main GUI container for the entire synthesizer interface.
Definition full_interface.h:61
void saveLfo(const json &data)
Opens a save dialog to save a given LFO shape.
Definition full_interface.cpp:848
Interface for classes that want to receive notifications about line editor changes.
Definition line_editor.h:86
bool isPainting()
Checks if painting mode is currently active.
Definition line_editor.h:461
static constexpr float kPaddingX
Horizontal padding in pixels.
Definition line_editor.h:56
void clearActiveMouseActions()
Definition line_editor.cpp:634
static constexpr int kDrawPoints
Number of points drawn: resolution plus max points from LineGenerator.
Definition line_editor.h:45
vital::poly_float adjustBoostPhase(vital::poly_float phase)
Adjusts a given phase value for boost calculations.
Definition line_editor.cpp:1061
bool active_
Definition line_editor.h:481
void renderGrid(OpenGlWrapper &open_gl, bool animate)
Renders the grid lines that show snapping lines or painting sections.
Definition line_editor.cpp:763
void setSliderPositionFromText()
Sets the position of the selected point/power from the text field.
Definition line_editor.cpp:1027
void showTextEntry()
Shows the text editor for entering a precise value or phase.
Definition line_editor.cpp:995
void setPointPositions()
Calculates and sets positions for point and power handle quads.
Definition line_editor.cpp:931
static constexpr float kMinPointDistanceForPower
Minimum horizontal distance (in pixels) between points to show power handles.
Definition line_editor.h:61
void render(OpenGlWrapper &open_gl, bool animate) override
Renders the line using OpenGL.
Definition line_editor.cpp:788
void init(OpenGlWrapper &open_gl) override
Initializes OpenGL resources for rendering the line.
Definition line_editor.cpp:753
bool isPaintEnabled()
Checks if paint mode is globally enabled.
Definition line_editor.h:466
virtual void mouseUp(const MouseEvent &e) override
Definition line_editor.cpp:603
void resetWavePath()
Resets the wave path, recalculating positions based on current points and powers.
Definition line_editor.cpp:643
void setEditingCircleBounds()
Sets bounds for the editing circles (hover and drag indicators).
Definition line_editor.cpp:869
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Definition line_editor.cpp:629
virtual void mouseDoubleClick(const MouseEvent &e) override
Definition line_editor.cpp:517
LineGenerator * getModel()
Gets the current LineGenerator model.
Definition line_editor.h:357
bool hasMatchingSystemClipboard()
Checks if the system clipboard contains a compatible line data JSON.
Definition line_editor.cpp:353
void destroy(OpenGlWrapper &open_gl) override
Destroys OpenGL resources allocated by this line renderer.
Definition line_editor.cpp:975
void drawDrag(const MouseEvent &e)
Handles mouse dragging to move points or adjust powers.
Definition line_editor.cpp:591
float padY(float y)
Pads a Y coordinate to fit the drawing area with vertical padding.
Definition line_editor.cpp:729
int getActivePower()
Gets the currently active power handle index.
Definition line_editor.h:450
static constexpr float kRingThickness
Fractional thickness for marker ring rendering.
Definition line_editor.h:34
void drawUp(const MouseEvent &e)
Handles mouse release to finalize point or power positions.
Definition line_editor.cpp:610
virtual void enableTemporaryPaintToggle(bool toggle)
Temporarily enables or disables paint mode using a toggle (e.g., via a modifier key).
Definition line_editor.cpp:1080
static constexpr float kPaddingY
Vertical padding in pixels.
Definition line_editor.h:54
@ kFlipHorizontal
Definition line_editor.h:77
@ kRemovePoint
Definition line_editor.h:75
@ kSave
Definition line_editor.h:71
@ kEnterValue
Definition line_editor.h:73
@ kInit
Definition line_editor.h:76
@ kResetPower
Definition line_editor.h:74
@ kEnterPhase
Definition line_editor.h:72
@ kCopy
Definition line_editor.h:69
@ kPaste
Definition line_editor.h:70
@ kFlipVertical
Definition line_editor.h:78
void paintLine(const MouseEvent &e)
Paints the line by adding points according to a pattern when in paint mode.
Definition line_editor.cpp:364
static constexpr int kNumWrapPoints
Number of wrap points for looping lines.
Definition line_editor.h:43
static constexpr float kDragRadius
Radius in pixels for dragging a point or power handle.
Definition line_editor.h:38
static constexpr float kPositionWidth
Width in pixels for main position markers.
Definition line_editor.h:30
void mouseExit(const MouseEvent &e) override
Definition line_editor.cpp:624
float unpadY(float y)
Removes padding from a padded Y coordinate.
Definition line_editor.cpp:734
void setGlPositions()
Updates OpenGL buffers with the latest positions if needed.
Definition line_editor.cpp:963
force_inline void resetPositions()
Marks positions as needing recalculation on next render.
Definition line_editor.h:399
void drawDown(const MouseEvent &e)
Handles the initial mouse press (not in paint mode) for dragging points or powers.
Definition line_editor.cpp:497
static constexpr float kPowerMouseMultiplier
Multiplier for mouse movements when adjusting power handles.
Definition line_editor.h:59
void setGridPositions()
Calculates and sets positions for grid lines.
Definition line_editor.cpp:898
static constexpr float kPowerWidth
Width in pixels for power markers (curve shaping handles).
Definition line_editor.h:32
virtual void mouseMove(const MouseEvent &e) override
Definition line_editor.cpp:557
virtual void respondToCallback(int point, int power, int option)
Responds to a callback triggered by a menu option or action.
Definition line_editor.cpp:287
void setPaint(bool paint)
Enables or disables paint mode.
Definition line_editor.cpp:985
void drawPosition(OpenGlWrapper &open_gl, Colour color, float fraction_x)
Draws a position marker at a specific fraction of the X-axis.
Definition line_editor.cpp:838
int getActivePoint()
Gets the currently active point index.
Definition line_editor.h:444
virtual void mouseDrag(const MouseEvent &e) override
Definition line_editor.cpp:582
void hideTextEntry()
Hides the text entry editor.
Definition line_editor.cpp:991
float padX(float x)
Pads an X coordinate to fit the drawing area with horizontal padding.
Definition line_editor.cpp:739
void textEditorEscapeKeyPressed(TextEditor &editor) override
Definition line_editor.cpp:1023
LineEditor(LineGenerator *line_source)
Constructs the LineEditor.
Definition line_editor.cpp:21
void renderPoints(OpenGlWrapper &open_gl, bool animate)
Renders the points and power handles on the curve.
Definition line_editor.cpp:768
virtual void mouseDown(const MouseEvent &e) override
Definition line_editor.cpp:455
std::vector< Listener * > listeners_
Definition line_editor.h:482
void textEditorFocusLost(TextEditor &editor) override
Definition line_editor.cpp:1019
virtual ~LineEditor()
Destructor.
Definition line_editor.cpp:87
void textEditorReturnKeyPressed(TextEditor &editor) override
Definition line_editor.cpp:1015
float unpadX(float x)
Removes padding from a padded X coordinate.
Definition line_editor.cpp:746
static constexpr float kGrabRadius
Radius in pixels for detecting grabbing a point or power handle.
Definition line_editor.h:36
A class for generating and storing a line shape, defined by a series of points and associated powers.
Definition line_generator.h:20
std::pair< float, float > lastPoint() const
Returns the last point in the line.
Definition line_generator.h:252
force_inline bool smooth() const
Indicates whether smoothing is enabled.
Definition line_generator.h:280
float valueAtPhase(float phase)
Gets the line value at a given normalized phase.
Definition line_generator.cpp:199
int getRenderCount() const
Gets the number of times the line has been rendered since initialization.
Definition line_generator.h:371
void render()
Renders the line into the internal buffer based on the current points and settings.
Definition line_generator.cpp:149
float lastPower() const
Returns the power (interpolation shape factor) of the last point.
Definition line_generator.h:259
force_inline int getNumPoints() const
Returns the current number of points defining the line.
Definition line_generator.h:327
force_inline void setPower(int index, float power)
Sets the power for a specific point.
Definition line_generator.h:349
force_inline void setPoint(int index, std::pair< float, float > point)
Sets the position of a specific point.
Definition line_generator.h:337
static bool isValidJson(json data)
Checks if a given JSON object contains valid line data.
Definition line_generator.cpp:116
void removePoint(int index)
Removes the point at a specified index.
Definition line_generator.cpp:259
void flipHorizontal()
Flips the line horizontally around the x=0.5 vertical axis.
Definition line_generator.cpp:268
static force_inline float smoothTransition(float t)
Smooth transition function for smoothing between points.
Definition line_generator.h:49
float getValueAtPhase(float phase)
Returns the value of the line at a given phase by searching through the points.
Definition line_generator.cpp:230
void jsonToState(json data)
Restores the line state from a given JSON object.
Definition line_generator.cpp:125
force_inline void setNumPoints(int num_points)
Sets the number of points currently in use.
Definition line_generator.h:360
static constexpr int kMaxPoints
Maximum number of points that can define the line.
Definition line_generator.h:25
json stateToJson()
Converts the current state of the line into a JSON object.
Definition line_generator.cpp:96
force_inline std::pair< float, float > getPoint(int index) const
Returns a point at the given index.
Definition line_generator.h:306
void initLinear()
Initializes the line to a simple linear shape (from 1.0 at x=0 to 0.0 at x=1).
Definition line_generator.cpp:11
force_inline float getPower(int index) const
Returns the power at the given index.
Definition line_generator.h:317
void addPoint(int index, std::pair< float, float > position)
Inserts a new point into the line at a specified index.
Definition line_generator.cpp:239
void flipVertical()
Flips the line vertically around y=0.5.
Definition line_generator.cpp:286
void renderCorners(OpenGlWrapper &open_gl, bool animate, Colour color, float rounding)
Renders the corner shapes using the given color and rounding amount.
Definition open_gl_component.cpp:153
A component for rendering lines with optional filling and boost effects using OpenGL.
Definition open_gl_line_renderer.h:16
virtual void init(OpenGlWrapper &open_gl) override
Initializes OpenGL resources for rendering the line.
Definition open_gl_line_renderer.cpp:78
virtual void destroy(OpenGlWrapper &open_gl) override
Destroys OpenGL resources allocated by this line renderer.
Definition open_gl_line_renderer.cpp:468
force_inline float xAt(int index) const
Gets the x-coordinate of a point at a given index.
Definition open_gl_line_renderer.h:81
force_inline void setFillCenter(float fill_center)
Sets the vertical center for the fill area.
Definition open_gl_line_renderer.h:138
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the line using OpenGL.
Definition open_gl_line_renderer.cpp:464
force_inline void setYAt(int index, float val)
Sets the y-coordinate of a point, marking data as dirty.
Definition open_gl_line_renderer.h:98
force_inline void setFill(bool fill)
Enables or disables filling below the line.
Definition open_gl_line_renderer.h:124
force_inline float boostLeftAt(int index) const
Gets the left-side boost at a given point index.
Definition open_gl_line_renderer.h:72
force_inline void setBoostRight(int index, float val)
Sets the right-side boost for a point, marking data as dirty.
Definition open_gl_line_renderer.h:91
force_inline void setXAt(int index, float val)
Sets the x-coordinate of a point, marking data as dirty.
Definition open_gl_line_renderer.h:105
force_inline float yAt(int index) const
Gets the y-coordinate of a point at a given index.
Definition open_gl_line_renderer.h:78
force_inline float boostRightAt(int index) const
Gets the right-side boost at a given point index.
Definition open_gl_line_renderer.h:75
force_inline int numPoints() const
Gets the number of points in the line.
Definition open_gl_line_renderer.h:186
force_inline void setBoostLeft(int index, float val)
Sets the left-side boost for a point, marking data as dirty.
Definition open_gl_line_renderer.h:84
force_inline Colour color() const
Gets the current line color.
Definition open_gl_line_renderer.h:189
void setThickness(float thickness, bool reset=false)
Sets the thickness used by some shaders and can reset to this thickness.
Definition open_gl_multi_quad.h:338
void setActive(bool active)
Activates or deactivates rendering of this component.
Definition open_gl_multi_quad.h:331
virtual void init(OpenGlWrapper &open_gl) override
Initializes OpenGL buffers and shader attributes.
Definition open_gl_multi_quad.cpp:37
void setQuad(int i, float x, float y, float w, float h)
Sets the position and size of a quad in normalized device space.
Definition open_gl_multi_quad.h:313
void setNumQuads(int num_quads)
Sets how many quads will actually be drawn (up to max_quads).
Definition open_gl_multi_quad.h:92
force_inline void setAltColor(Colour color)
Sets an alternate color, often used by custom shaders.
Definition open_gl_multi_quad.h:118
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the quads using OpenGL.
Definition open_gl_multi_quad.cpp:92
virtual void destroy(OpenGlWrapper &open_gl) override
Releases OpenGL resources when the component is destroyed.
Definition open_gl_multi_quad.cpp:69
force_inline void setColor(Colour color)
Sets the base color for the quads.
Definition open_gl_multi_quad.h:102
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kWidgetAccent1
Definition skin.h:171
@ kWidgetPrimaryDisabled
Definition skin.h:167
@ kWidgetBackground
Definition skin.h:173
@ kLightenScreen
Definition skin.h:141
@ kWidgetCenterLine
Definition skin.h:164
@ kWidgetAccent2
Definition skin.h:172
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
void showPopupSelector(Component *source, Point< int > position, const PopupItems &options, std::function< void(int)> callback, std::function< void()> cancel={ })
Shows a popup selector with options.
Definition synth_section.cpp:119
static constexpr mono_float kMaxPower
Definition synth_lfo.h:116
#define VITAL_ASSERT(x)
Definition common.h:11
nlohmann::json json
Definition line_generator.h:7
force_inline mono_float powerScale(mono_float value, mono_float power)
A power-scaling function to map a linear range to a curved response.
Definition futils.h:455
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174
A hierarchical structure of popup menu items for a selector component.
Definition synth_section.h:29
void addItem(int sub_id, const std::string &sub_name, bool sub_selected=false)
Adds a new item as a submenu entry.
Definition synth_section.h:51
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
force_inline void vector_call set(size_t index, float new_value) noexcept
Sets a specific element in the SIMD register.
Definition poly_values.h:1182
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...