1 /*
2 * curve_editor.cc
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * DIN Is Noise is released under GNU Public License 2.0
5 * For more information, please visit https://dinisnoise.org/
6 */
7
8 #include "input.h"
9 #include "curve_editor.h"
10 #include "curve_library.h"
11 #include "console.h"
12 #include "font.h"
13 #include "utils.h"
14 #include "random.h"
15 #include "sine_mixer.h"
16 #include "beat2value.h"
17 #include "vector2d.h"
18 #include "fft.h"
19 #include "main.h"
20 #include "ui_list.h"
21 #include "chrono.h"
22 #include "viewwin.h"
23 #include "spiraler.h"
24 #include "rose_milker.h"
25 #include "instrument.h"
26 #include "capturer.h"
27
28 using namespace std;
29
30 extern int lmb, rmb;
31 extern ofstream dlog;
32 extern string user_data_dir;
33 extern int SAMPLE_RATE;
34 extern int FPS;
35 extern double TIME_PER_FRAME;
36 extern const float TWO_PI;
37 extern char BUFFER [];
38 extern instrument* get_current_instrument ();
39
show_curve_picker()40 void show_curve_picker () {
41 curve_picker.show ();
42 }
43
curve_editor(const std::string & settingsf,const std::string & helpf)44 curve_editor::curve_editor (const std::string& settingsf, const std::string& helpf) : helptext (helpf) {
45
46 curcrv = 0;
47
48 do_nothing ();
49
50 is_waveform_editor = sine_enabled = fft_enabled = samples_enabled = draw_curve_only = 0;
51
52 load (settingsf);
53
54 lmb_move = 0;
55 lmb_clicked = 0;
56
57 angle = 0;
58 last_rpm = 0;
59
60 gl_pts = 0;
61 n_pts = 0;
62
63 hlabel_only = 0;
64
65 mark_segments = 0;
66
67 }
68
~curve_editor()69 curve_editor::~curve_editor () {
70 save ();
71 dlog << "-- destroyed curve editor: " << name << " ---" << endl;
72 }
73
load(const std::string & fname)74 void curve_editor::load (const std::string& fname) {
75
76 // load settings from file
77 std::string feditor = user_data_dir + fname;
78 ifstream file (feditor.c_str (), ios::in);
79 if (!file) {
80 dlog << "!!! cannot open curve editor settings from: " << fname << " !!!" << endl;
81 return;
82 } else dlog << "<<< loading curve editor settings from: " << feditor;
83
84 settings_filename = fname;
85
86 std::string ignore;
87
88 basic_editor::load (file);
89
90 int ct; file >> ignore >> ct;
91 carry_tangents = ct;
92
93 int mt; file >> ignore >> mt;
94 mirror_tangents = mt;
95
96 file >> ignore >> sine_enabled;
97
98 file >> ignore >> label_vertices;
99
100 tb.load (file);
101
102 file >> ignore >> fft_enabled;
103 file >> ignore >> samples_enabled;
104 file >> ignore >> hz >> ignore >> nperiods;
105 cs.set (hz, nperiods);
106 file >> ignore >> is_waveform_editor;
107 file >> ignore >> draw_curve_only;
108 file >> ignore >> kbkb_attack_editor;
109 file >> ignore >> overlay;
110 file >> ignore >> curcrv;
111 file >> ignore >> axis;
112 file >> ignore >> draw_plugin_output;
113
114 dlog << ", done >>>" << endl;
115
116 }
117
save()118 void curve_editor::save () {
119
120 // save settings to file
121 //
122 ofstream file ((user_data_dir + settings_filename).c_str(), ios::out);
123 if (!file) {
124 dlog << "cannot save " << settings_filename << endl;
125 return;
126 }
127
128 basic_editor::save (file);
129
130 file << "carry_tangents " << carry_tangents << endl;
131 file << "mirror_tangents " << mirror_tangents << endl;
132 file << "sine_enabled " << sine_enabled << endl;
133 file << "label_vertex " << label_vertices << endl;
134
135 tb.clear ();
136 tb.save (file);
137
138 file << "fft_enabled " << fft_enabled << endl;
139 file << "samples_enabled " << samples_enabled << endl;
140 file << "hz " << hz << endl;
141 file << "nperiods " << nperiods << endl;
142 file << "is_waveform_editor " << is_waveform_editor << endl;
143 file << "draw_curve_only " << draw_curve_only << endl;
144 file << "sustain_editing " << kbkb_attack_editor << endl;
145 file << "overlay " << overlay << endl;
146 file << "curcrv " << curcrv << endl;
147 file << "mirror_axis " << axis << endl;
148 file << "draw_plugin_output " << draw_plugin_output << endl;
149
150 }
151
prep_move()152 void curve_editor::prep_move () {
153 undos.push_back (undo_t (pik.crv_id, *pik.crv, win));
154 curveinfo[pik.crv_id].lisner->selected (pik.crv_id);
155 if (keydown (SDLK_SPACE)) {
156 cons << YELLOW << "Moving whole curve";
157 todo = MOVE_ALL;
158 } else {
159 todo = MOVE_PICKED;
160 cons << YELLOW << "Moving " << pik;
161 }
162 cons << eol;
163 lmb_move = PREP;
164 }
165
handle_input()166 int curve_editor::handle_input () {
167
168 basic_editor::handle_input (); // pan, zoom, snap etc
169
170 if (lmb) {
171
172 if (lmb_clicked == 0) { // first lmb
173
174 lmb_clicked = 1;
175
176 if (lmb_move == FINISH_ON_CLICK) {
177 cons << RED << "Finished moving " << pik << eol;
178 do_nothing ();
179 return 1;
180 }
181
182 if (todo == NOTHING) { // try to hit something to move
183 hittest ();
184 if (pik()) { // hit
185 if (pomo.hit (pik))
186 ;
187 else
188 prep_move ();
189 return 1;
190 }
191 } else {
192 switch (todo) {
193 case ADD_VERTEX:
194 add_vertex ();
195 return 1;
196 case INSERT_VERTEX:
197 if (!pik()) pik = pick_cur_curve ();
198 insert ();
199 return 1;
200 case REMOVE_VERTEX:
201 hittest ();
202 if (pik ()) remove ();
203 return 1;
204 case MODULATE_POINT:
205 hittest ();
206 modulate_point (1);
207 return 1;
208 case FOLD_VERTEX:
209 hittest ();
210 if (pik()) fold_tangents_of_vertex (pik);
211 return 1;
212 case UNFOLD_VERTEX:
213 hittest ();
214 if (pik()) unfold_tangents_of_vertex (pik);
215 return 1;
216 case MIRROR_VERTEX:
217 hittest ();
218 if (pik()) mirror ();
219 return 1;
220 case START_CAPTURE:
221 do_nothing ();
222 return 1;
223 case ASSIGN_CAPTURE:
224 hittest ();
225 assign_mouse_capture ();
226 return 1;
227 case PICK_CURVE:
228 hittest ();
229 if (pik()) curve_picked ();
230 return 1;
231 }
232 }
233 }
234 } else {
235 lmb_clicked = 0;
236 if (lmb_move && !MENU.show) {
237 if (todo == MOVE_PICKED) move (); else
238 if (todo == MOVE_ALL) move (1); // all
239 lmb_move = FINISH_ON_CLICK;
240 return 1;
241 }
242 }
243
244 if (library) {
245 if (library->num_curves () && !mouse_slider0.active) {
246 if (keypressedd (SDLK_9)) {
247 load_curve (-1);
248 return 1;
249 } else
250 if (keypressedd (SDLK_0)) {
251 load_curve (1);
252 return 1;
253 } else
254 if (keypressed (SDLK_MINUS)) { delete_curve (); return 1;}
255 }
256 if (keypressed (SDLK_EQUALS)) { add_curve (); return 1; }
257 }
258
259 if (keypressed (SDLK_i)) insert_using_menu ();
260 else if (keypressed (SDLK_v)) {
261 if (CTRL) { // ctrl + v ie paste
262 paste_using_menu ();
263 } else { // delete vertex or tanget
264 todo = REMOVE_VERTEX;
265 hittest ();
266 if (pik()) remove ();
267 todo = NOTHING;
268 }
269 }
270 else if (keypressedd (SDLK_z)) { // undo & redo
271 if (SHIFT) // l_shift + z - redo
272 do_redo ();
273 else
274 do_undo ();
275 }
276 else if (keypressedd (SDLK_r)) apply_plugin (uis.plugin__browser.get_cur ()); // apply current plugin
277 else if (keypressed (SDLK_m)) { // mirror tangents ie move one tangent and the other mirrors it
278 mirror_tangents = !mirror_tangents;
279 if (mirror_tangents) cons << YELLOW << "tangents are mirrored" << eol; else cons << YELLOW<< "tangents are not mirrored" << eol;
280 MENU.set_mirror_tangents (mirror_tangents);
281 } else if (keypressed (SDLK_COMMA)) {
282 if (!mouse_slider0.active) {
283 mark_segments = !mark_segments;
284 dont_call_listener (MENU.cb_mark_segments, mark_segments);
285 }
286 }
287 else if (keypressedd (SDLK_PERIOD)) {
288 if (!mouse_slider0.active) {
289 draw_curve_only = !draw_curve_only;
290 dont_call_listener (MENU.cb_draw_curve, draw_curve_only);
291 }
292 }
293 else if (keypressed (SDLK_c)) {
294 if (CTRL) { // l_ctrl + c - copy curve
295 if (num_curves == 1) {
296 pik = pick_cur_curve ();
297 copy_curve ();
298 } else {
299 hittest ();
300 if (pik()) copy_curve (); else if (hitlist.size()) copy_using_menu ();
301 }
302 } else { // carry tangents?
303 carry_tangents = !carry_tangents;
304 if (carry_tangents)
305 cons << YELLOW << "vertices carry their tangents" << eol;
306 else
307 cons << YELLOW << "vertices desert their tangents" << eol;
308 MENU.set_vertices_carry_tangents (carry_tangents);
309 }
310 }
311 else if (keypressed (SDLK_SLASH)) {
312 if (!mouse_slider0.active) toggle_waveform_samples_display ();
313 } else if (keypressed (SDLK_l)) {
314 label_vertices = !label_vertices;
315 dont_call_listener (MENU.cb_label_vertices, label_vertices);
316 }
317 else if (keypressed (SDLK_F8)) { // apply mouse capture
318 if (mocap0()) {
319 hittest ();
320 todo = ASSIGN_CAPTURE;
321 next_todo = NOTHING;
322 assign_mouse_capture ();
323 }
324 } else if (keypressed (SDLK_o)) { // toggle overlay of instrument/editor
325 overlay = !overlay;
326 if (overlay)
327 cons << GREEN << "Overlaid the " << uis.over->name << eol;
328 else
329 cons << GREEN << "Removed the " << uis.over->name << " from overlay" << eol;
330 MENU.cb_overlay.set_state (overlay, 0);
331 }
332 else if (keypressed (SDLK_F1)) helptext(); // show help
333
334 return 1;
335
336 }
337
apply_mocap()338 void curve_editor::apply_mocap () {
339 float x, y;
340 int vx, vy;
341 for (int i = 0, j = macros.size(); i < j; ++i) {
342 mouse_macro& m = macros[i];
343 if (m.paused == 0) {
344 hit_t& h = m.hit;
345 if (h(1)) {
346 m.mo.get (x, y);
347 move (h, x, y);
348 obj2view (x, y, vx, vy);
349 capturer.set (m, vx, vy);
350 }
351 }
352 }
353 }
354
pick(int i)355 void curve_editor::pick (int i) {
356 int ncurves = curveinfo.size ();
357 if (i > -1 && i < ncurves) {
358 curve_info& ci = curveinfo[i];
359 ci.lisner->selected (i);
360 }
361 }
362
calc_hit_params(hit_t & hit)363 void curve_editor::calc_hit_params (hit_t& hit) {
364 if (!hit()) return;
365 multi_curve* crv = get_curve (hit.crv_id);
366 float vx, vy, lx, ly, rx, ry;
367 int id = hit.id;
368 crv->get_vertex (id, vx, vy);
369 crv->get_left_tangent (id, lx, ly);
370 crv->get_right_tangent (id, rx, ry);
371 direction (hit.left_tangent.x, hit.left_tangent.y, vx, vy, lx, ly);
372 direction (hit.right_tangent.x, hit.right_tangent.y, vx, vy, rx, ry);
373 hit.left_tangent_magnitude = (float) magnitude (hit.left_tangent.x, hit.left_tangent.y);
374 hit.right_tangent_magnitude = (float) magnitude (hit.right_tangent.x, hit.right_tangent.y);
375 const point<float>& hp = hit.get (); obj2mouse (hp.x, hp.y);
376 curcrv = hit.crv_id;
377 }
378
hittest()379 void curve_editor::hittest () {
380
381 hitlist.clear ();
382 for (int i = 0, j = curveinfo.size (); i < j; ++i) {
383 curve_info& ci = curveinfo[i];
384 multi_curve* crv = ci.curve;
385 hittest (crv, i, crv->vertices, hit_t::VERTEX);
386 hittest (crv, i, crv->left_tangents, hit_t::LEFT_TANGENT);
387 hittest (crv, i, crv->right_tangents, hit_t::RIGHT_TANGENT);
388 }
389
390 int n = hitlist.size();
391 if (n) n = filter_hitlist ();
392 if (n == 1) {
393 pik = hitlist [0];
394 calc_hit_params (pik);
395 } else {
396 pik = hit_t ();
397 if (n > 1) show_curve_picker ();
398 }
399 }
400
hittest(multi_curve * crv,int crv_id,const points_array & points,unsigned int what)401 void curve_editor::hittest (multi_curve* crv, int crv_id, const points_array& points, unsigned int what) {
402 for (int i = 0, j = points.size (); i < j; ++i) {
403 const point<float>& v = points[i];
404 float vx, vy; obj2win (v, vx, vy);
405 float d2 = magnitude2<float> (vx, vy, win.mousex, win.mousey);
406 if (d2 <= win.handle_radius2) hitlist.push_back (hit_t (crv, crv_id, what, i));
407 }
408 }
409
filter_hitlist()410 int curve_editor::filter_hitlist () {
411
412 for (int i = 0, j = curveinfo.size (); i < j; ++i) curveinfo[i].picked = 0;
413 for (vector<hit_t>::iterator i = hitlist.begin (), j = hitlist.end (); i != j;) {
414 hit_t& hit = *i;
415 if (todo == PICK_CURVE) {
416 int& picked = curveinfo[hit.crv_id].picked;
417 if (picked) { // picked already, so remove
418 hitlist.erase (i);
419 j = hitlist.end ();
420 } else { // pick one item per curve
421 picked = 1;
422 ++i;
423 }
424 } else
425 if (todo == REMOVE_VERTEX && hit.what != hit_t::VERTEX) { // have to select vertex to delete
426 i = hitlist.erase (i);
427 j = hitlist.end ();
428 } else
429 if ( (hit.what == hit_t::LEFT_TANGENT && hit.id == 0) || (hit.what == hit_t::RIGHT_TANGENT && hit.id == (hit.crv->last_vertex)) ) {
430 // remove 1st vertex's left tangent and last vertex's right tangent
431 i = hitlist.erase (i);
432 j = hitlist.end ();
433 }
434 else {
435 ++i;
436 }
437 }
438
439 return hitlist.size ();
440 }
441
set_pick_from_hitlist(int i)442 void curve_editor::set_pick_from_hitlist (int i) {
443 pik = hitlist [i];
444 calc_hit_params (pik);
445 curveinfo [curcrv].lisner->selected (curcrv);
446 cons << GREEN << "Picked " << pik << eol;
447 }
448
move(hit_t & hit,float x,float y,int eval_now)449 int curve_editor::move (hit_t& hit, float x, float y, int eval_now) {
450
451 curve_info& ci = curveinfo [hit.crv_id];
452 multi_curve* crv = ci.curve;
453
454 int need_eval = 0;
455
456 switch (hit.what) {
457
458 case hit_t::VERTEX:
459 need_eval = crv->set_vertex (hit.id, x, y, carry_tangents);
460 break;
461
462 case hit_t::LEFT_TANGENT:
463 need_eval = crv->set_left_tangent (hit.id, x, y);
464 if (mirror_tangents && need_eval) {
465 float vx, vy, lvx, lvy;
466 crv->get_vertex (hit.id, vx, vy);
467 unit_vector (lvx, lvy, vx, vy, x, y);
468 crv->set_right_tangent (hit.id, vx - hit.right_tangent_magnitude * lvx, vy - hit.right_tangent_magnitude * lvy);
469 }
470 break;
471
472 case hit_t::RIGHT_TANGENT:
473 need_eval = crv->set_right_tangent (hit.id, x, y);
474 if (mirror_tangents && need_eval) {
475 float vx, vy, rvx, rvy;
476 crv->get_vertex (hit.id, vx, vy);
477 unit_vector (rvx, rvy, vx, vy, x, y);
478 crv->set_left_tangent (hit.id, vx - hit.left_tangent_magnitude * rvx, vy - hit.left_tangent_magnitude * rvy);
479 }
480 break;
481
482 }
483
484 if (need_eval && eval_now) {
485 crv->evaluate();
486 ci.lisner->edited (this, hit.crv_id);
487 }
488
489 return need_eval;
490
491 }
492
move()493 int curve_editor::move () {
494 float sx, sy; snap (sx, sy);
495 float cx, cy; win2obj (sx, sy, cx, cy);
496 return move (pik, cx, cy);
497 }
498
move(int)499 int curve_editor::move (int) {
500
501 float sx, sy; snap (sx, sy);
502
503 float cx, cy;
504 win2obj (sx, sy, cx, cy);
505
506 curve_info& ci = curveinfo [pik.crv_id];
507 multi_curve* crv = ci.curve;
508
509 float vx, vy;
510 float dx, dy;
511
512 switch (pik.what) {
513 case hit_t::VERTEX:
514 crv->get_vertex (pik.id, vx, vy);
515 break;
516 case hit_t::LEFT_TANGENT:
517 crv->get_left_tangent (pik.id, vx, vy);
518 break;
519 case hit_t::RIGHT_TANGENT:
520 crv->get_right_tangent (pik.id, vx, vy);
521 break;
522 }
523
524 dx = cx - vx;
525 dy = cy - vy;
526
527 int result = 0;
528 for (int i = 0, j = crv->num_vertices; i < j; ++i) {
529 crv->get_vertex (i, vx, vy);
530 result |= crv->set_vertex (i, vx + dx, vy + dy);
531 crv->get_left_tangent (i, vx, vy);
532 result |= crv->set_left_tangent (i, vx + dx, vy + dy);
533 crv->get_right_tangent (i, vx, vy);
534 result |= crv->set_right_tangent (i, vx + dx, vy + dy);
535 }
536
537 if (result) {
538 crv->evaluate();
539 ci.lisner->edited (this, pik.crv_id);
540 }
541
542 return result;
543
544 }
545
remove()546 void curve_editor::remove () {
547 curve_info& ci = curveinfo [pik.crv_id];
548 multi_curve* crv = ci.curve;
549 mix = *crv;
550 undos.push_back (undo_t (pik.crv_id, *crv, win));
551 if (crv->remove (pik.id)) {
552 pomo.remove (pik);
553 crv->evaluate();
554 ci.lisner->edited (this, pik.crv_id);
555 } else {
556 cons << RED << "cant delete curve: " << crv->name << eol;
557 undos.pop_back ();
558 }
559 clear_hit (pik);
560 }
561
swap()562 void curve_editor::swap () {
563 if (num_curves == 2) {
564
565 multi_curve& crv0 = *get_curve (0);
566 multi_curve& crv1 = *get_curve (1);
567
568 multi_curve swp (crv0);
569
570 undos.push_back (undo_t (0, crv0, win));
571 string name0 (crv0.name);
572 float r0 = crv0.r, g0 = crv0.g, b0 = crv0.b;
573 crv0 = crv1;
574 crv0.name = name0;
575 crv0.set_color (r0, g0, b0);
576
577 undos.push_back (undo_t (1, crv1, win));
578 string name1 (crv1.name);
579 float r1 = crv1.r, g1 = crv1.g, b1 = crv1.b;
580 crv1 = swp;
581 crv1.name = name1;
582 crv1.set_color (r1, g1, b1);
583
584 cons << "Swapped curve " << crv0.name << " with " << crv1.name << eol;
585 curve_info &ci0 = get_curve_info (0), &ci1 = get_curve_info (1);
586
587 pomo.validate ();
588 ci0.lisner->edited (this, 0);
589 ci1.lisner->edited (this, 1);
590
591
592 }
593 }
594
insert()595 void curve_editor::insert () {
596 curve_info& ci = curveinfo [pik.crv_id];
597 multi_curve* crv = ci.curve;
598 float sx, sy; snap (sx, sy);
599 float cx, cy; win2obj (sx, sy, cx, cy);
600 mix = *crv;
601 undos.push_back (undo_t (pik.crv_id, *crv, win));
602 const point<float>& obj = get_obj_chunk ();
603 if (crv->insert (cx, cy, obj.x, obj.y)) {
604 crv->evaluate();
605 ci.lisner->edited (this, pik.crv_id);
606 } else undos.pop_back ();
607 }
608
replace()609 void curve_editor::replace () {
610 if (curv_scratch_points.size () > 1) {
611 curve_info& ci = curveinfo [pik.crv_id];
612 multi_curve& crv = *ci.curve;
613 int shapeform = crv.shapeform;
614 mix = crv;
615 undos.push_back (undo_t (pik.crv_id, crv, win));
616 create_polyline (crv, curv_scratch_points);
617 if (shapeform) crv.set_shapeform (1);
618 pomo.validate ();
619 ci.lisner->edited (this, pik.crv_id);
620 cons << GREEN << "Replaced curve." << eol;
621 } else cons << RED << "Aborted drawn curve!" << eol;
622
623 clear_scratch_curve ();
624 }
625
mirror(int whole_curve)626 void curve_editor::mirror (int whole_curve) {
627
628 // mirrors vertex (or curve) about global x-axis, or local axes of bounding box
629 curve_info& ci = curveinfo [pik.crv_id];
630 multi_curve* crv = ci.curve;
631 undos.push_back (undo_t (pik.crv_id, *crv, win));
632
633 box<float> bbox;
634 if (axis > MIRROR_Y) crv->calc_bbox (bbox);
635
636 float xx, yy, dx, dy, _2mx = 2 * bbox.midx, _2my = 2 * bbox.midy;
637 if (whole_curve) {
638 if ((axis == MIRROR_Y) || (axis == MIRROR_BBY)) {
639 for (int i = 0; i < crv->num_vertices; ++i) {
640 crv->get_vertex (i, xx, yy); dx = _2mx - xx; crv->set_vertex (i, dx, yy);
641 crv->get_left_tangent (i, xx, yy); dx = _2mx - xx; crv->set_left_tangent (i, dx, yy);
642 crv->get_right_tangent (i, xx, yy); dx = _2mx - xx; crv->set_right_tangent (i, dx, yy);
643 }
644 } else {
645 for (int i = 0; i < crv->num_vertices; ++i) {
646 crv->get_vertex (i, xx, yy); dy = _2my - yy; crv->set_vertex (i, xx, dy);
647 crv->get_left_tangent (i, xx, yy); dy = _2my - yy; crv->set_left_tangent (i, xx, dy);
648 crv->get_right_tangent (i, xx, yy); dy = _2my - yy; crv->set_right_tangent (i, xx, dy);
649 }
650 }
651 mix = *crv;
652 crv->evaluate();
653 ci.lisner->edited (this, pik.crv_id);
654 } else {
655 switch (pik.what) {
656 case hit_t::VERTEX:
657 crv->get_vertex (pik.id, xx, yy);
658 break;
659 case hit_t::LEFT_TANGENT:
660 crv->get_left_tangent (pik.id, xx, yy);
661 break;
662 case hit_t::RIGHT_TANGENT:
663 crv->get_right_tangent (pik.id, xx, yy);
664 break;
665 }
666 mix = *crv;
667 if ((axis == MIRROR_Y) || (axis == MIRROR_BBY)) {
668 dx = _2mx - xx;
669 move (pik, dx, yy);
670 } else {
671 dy = _2my - yy;
672 move (pik, xx, dy);
673 }
674 }
675 }
676
draw()677 void curve_editor::draw () {
678 project ();
679 basic_editor::draw ();
680 draw_all ();
681 if (draw_plugin_output) uis.plugin__browser.draw (this);
682 if (show_scratch_curve) draw_scratch_curve ();
683 if (curve_picker.visible) hilite_item (curve_picker.id);
684 unproject ();
685 if (overlay) ui::over->drawerlay ();
686 }
687
draw_scratch_curve()688 void curve_editor::draw_scratch_curve () {
689 glColor3f (1, 1, 0.7f);
690 int n = win_scratch_points.size () + 1;
691 alloc_gl_pts (n);
692 int k = 0;
693 for (int i = 0, j = n - 1; i < j; ++i) {
694 const point<float>& p = win_scratch_points[i];
695 gl_pts[k++]=p.x;
696 gl_pts[k++]=p.y;
697 }
698 float sx, sy; snap (sx, sy);
699 gl_pts[k++]=sx;
700 gl_pts[k++]=sy;
701 glVertexPointer (2, GL_FLOAT, 0, gl_pts);
702 glDrawArrays (GL_LINE_STRIP, 0, n);
703 }
704
draw_all()705 void curve_editor::draw_all () {
706
707 // draw labels
708 tb.draw (hlabel_only);
709 tb.clear ();
710
711 if (mark_segments) mark_curve_segments ();
712
713 // draw curve profile, vertices, tangents and handles
714 int j = curveinfo.size ();
715 //int j1 = j > 1;
716 for (int i = 0; i < j; ++i) {
717 curve_info& ci = curveinfo[i];
718 multi_curve* crv = ci.curve;
719 //if (i == curcrv && j1) glLineWidth (2); // hilite current
720 if (draw_curve_only) {
721 glColor3f (crv->r, crv->g, crv->b);
722 draw_curve (crv);
723 } else {
724 glColor3f (crv->rt, crv->gt, crv->bt);
725 draw_tangents (crv);
726 glColor3f (crv->r, crv->g, crv->b);
727 draw_vertices (crv);
728 draw_curve (crv);
729 }
730 //glLineWidth (1);
731 }
732
733 // mark beat/value (gater, fm/am, octave shift)
734 //
735 int n = bv.size ();
736 if (n) {
737 float nowx, nowy;
738 float x, y;
739 static const int marker_size = 35;
740 for (int i = 0; i < n; ++i) {
741 beat2value* bvi = bv[i];
742 multi_curve& crv = *bvi->crv;
743 if (crv.shapeform) crv.get_xy (bvi->now, nowx, nowy);
744 else {
745 nowx = bvi->now;
746 nowy = bvi->sol (nowx);
747 }
748 obj2win (nowx, nowy, x, y);
749 glColor3f (crv.r, crv.g, crv.b);
750 glLineWidth (2);
751 mkr[0]=x-marker_size;mkr[1]=y;
752 mkr[2]=x;mkr[3]=y-marker_size;
753 mkr[4]=x+marker_size;mkr[5]=y;
754 mkr[6]=x;mkr[7]=y+marker_size;
755 glVertexPointer (2, GL_INT, 0, mkr);
756 glDrawArrays (GL_LINE_LOOP, 0, 4);
757 glLineWidth (1);
758
759 }
760 }
761
762 // label vertices
763 if (label_vertices) {
764 for (int i = 0, j = curveinfo.size (); i < j; ++i) {
765 curve_info& ci = curveinfo[i];
766 multi_curve* crv = ci.curve;
767 for (int m = 0, n = crv->num_vertices; m < n; ++m) {
768 point<float>& vm = crv->vertices[m];
769 sprintf (BUFFER, "%d", m);
770 tb.add (text (BUFFER, vm.x, vm.y, vtxlbl.r, vtxlbl.g, vtxlbl.b));
771 }
772 tb.refresh (this);
773 }
774 }
775
776 if (samples_enabled && curveinfo.size()) cs.draw (this, curveinfo[0].curve);
777
778 if (kbkb_attack_editor) {
779 mkr[0]=susx;mkr[1]=susbox.bottom;
780 mkr[2]=susx;mkr[3]=win.bottom;
781 glEnable (GL_LINE_STIPPLE);
782 glLineStipple (1, 0x00ff);
783 glColor3f (0, 0.5, 1);
784 glVertexPointer (2, GL_INT, 0, mkr);
785 glDrawArrays (GL_LINES, 0, 2);
786 glDisable (GL_LINE_STIPPLE);
787 mkr[0]=susbox.left;mkr[1]=susbox.top;
788 mkr[2]=susbox.midx;mkr[3]=susbox.bottom;
789 mkr[4]=susbox.right;mkr[5]=susbox.top;
790 glVertexPointer (2, GL_INT, 0, mkr);
791 glDrawArrays (GL_LINE_LOOP, 0, 3);
792 }
793
794 draw_cursor ();
795
796 }
797
798
mark_curve_segments()799 void curve_editor::mark_curve_segments () {
800
801 // drop vertical lines from current curve's profile points
802 glColor3f (0.2f, 0.2f, 0.2f);
803 curve_info& ci = curveinfo [curcrv];
804 multi_curve* crv = ci.curve;
805 vector<curve>& curv = crv->curv;
806 int m = 0;
807 for (int i = 0, j = curv.size(); i < j; ++i) m += curv[i].vpts.size ();
808 int e = 2 * m;
809 int n = 2 * e;
810 alloc_gl_pts (n);
811 for (int i = 0, j = curv.size(), k = 0; i < j; ++i) {
812 vector<crvpt>& vpts = curv[i].vpts;
813 for (int p = 0, q = vpts.size (); p < q; ++p) {
814 float dx, dy; obj2win (vpts[p].x, vpts[p].y, dx, dy);
815 gl_pts [k++]=dx;
816 gl_pts [k++]=dy;
817 gl_pts [k++]=dx;
818 gl_pts [k++]=0;
819 }
820 }
821 glVertexPointer (2, GL_FLOAT, 0, gl_pts);
822 glDrawArrays (GL_LINES, 0, e);
823 }
824
draw_handle(const point<float> & p)825 void curve_editor::draw_handle (const point<float>& p) {
826 float x, y; obj2win (p, x, y);
827 float handle [] = {x - win.handle_radius, y, x, y + win.handle_radius, x + win.handle_radius, y, x, y - win.handle_radius};
828 glVertexPointer (2, GL_FLOAT, 0, handle);
829 glDrawArrays (GL_LINE_LOOP, 0, 4);
830 }
831
draw_tangent(const point<float> & p,const point<float> & t)832 void curve_editor::draw_tangent (const point<float>& p, const point<float>& t) {
833 float x, y; obj2win (p, x, y);
834 float tx, ty; obj2win (t, tx, ty);
835 float pts [4] = {x, y, tx, ty};
836 glVertexPointer (2, GL_FLOAT, 0, pts);
837 glDrawArrays (GL_LINES, 0, 2);
838 }
839
draw_curve(multi_curve * crv)840 void curve_editor::draw_curve (multi_curve* crv) {
841
842 int r = 0, n = crv->get_total_points ();
843 alloc_gl_pts (n);
844
845 vector<curve>& curv = crv->curv;
846 int j = curv.size (), k = j - 1;
847 float dx, dy;
848 for (int i = 0; i < j; ++i) {
849 vector<crvpt>& vpts = curv[i].vpts;
850 for (int p = 0, q = vpts.size () - 1; p < q; ++p) {
851 obj2win (vpts[p].x, vpts[p].y, dx, dy);
852 gl_pts[r++] = dx;
853 gl_pts[r++] = dy;
854 }
855 }
856
857 // last point
858 int l = curv[k].vpts.size () - 1;
859 crvpt& pl = curv[k].vpts[l];
860 obj2win (pl.x, pl.y, dx, dy);
861 gl_pts[r++]=dx;
862 gl_pts[r++]=dy;
863
864 glVertexPointer (2, GL_FLOAT, 0, gl_pts);
865 glDrawArrays (GL_LINE_STRIP, 0, n);
866
867 }
868
draw_vertices(multi_curve * crv)869 void curve_editor::draw_vertices (multi_curve* crv) {
870 const points_array& vertices = crv->vertices;
871 for (int p = 0, q = vertices.size(); p < q; ++p) {
872 const point<float>& v = vertices[p];
873 draw_handle (v);
874 }
875 }
876
draw_tangents(multi_curve * crv)877 void curve_editor::draw_tangents (multi_curve* crv) {
878 // draw tangents of ith curve
879 const points_array& vertices = crv->vertices;
880 const points_array& left_tangents = crv->left_tangents;
881 const points_array& right_tangents = crv->right_tangents;
882 for (int p = 0, q = vertices.size(); p < q; ++p) {
883 const point<float>& v = vertices[p];
884 const point<float>& lt = left_tangents[p];
885 const point<float>& rt = right_tangents[p];
886 draw_tangent (v, lt);
887 draw_handle (lt);
888 draw_tangent (v, rt);
889 draw_handle (rt);
890 }
891 }
892
dodo(list<undo_t> & do1,list<undo_t> & do2,std::string mesg)893 void curve_editor::dodo (list<undo_t>& do1, list<undo_t>& do2, std::string mesg) {
894 if (do1.size() > 0) {
895 undo_t& last = do1.back ();
896 if (last.i < num_curves) {
897 curve_info& ci = curveinfo[last.i];
898 multi_curve* crv = ci.curve;
899 mix = *crv;
900 do2.push_back (undo_t (last.i, *crv, win));
901 float r, g, b;
902 crv->get_color (r, g, b);
903 *crv = last.curve;
904 crv->set_color (r, g, b);
905 pomo.validate ();
906 ci.lisner->edited (this, last.i);
907 win = last.win;
908 do1.pop_back ();
909 }
910 hitlist.clear ();
911 calc_visual_params ();
912 } else cons << RED << mesg << eol;
913 }
914
add(multi_curve * crv,curve_listener * lsnr)915 void curve_editor::add (multi_curve* crv, curve_listener* lsnr) {
916 curveinfo.push_back (curve_info (crv, lsnr));
917 if (++num_curves == 1) {
918 render_curve_samples ();
919 hlabel_only = crv->shapeform;
920 }
921 }
922
clear()923 void curve_editor::clear () {
924 curveinfo.clear ();
925 hitlist.clear ();
926 clear_hit (pik);
927 num_curves = 0;
928 }
929
get_curve(int i)930 multi_curve* curve_editor::get_curve (int i) {
931 if (i > -1 && i < (int) curveinfo.size()) {
932 curve_info& ci = curveinfo [i];
933 return ci.curve;
934 }
935 return 0;
936 }
937
get_curve_info(int i)938 curve_info& curve_editor::get_curve_info (int i) {
939 return curveinfo[i];
940 }
941
enter()942 void curve_editor::enter () {
943 calc_visual_params ();
944 if (is_waveform_editor) uis.dofft ();
945 setup_tools_menu ();
946 MENU.set_snap (snap_what);
947 MENU.set_vertices_carry_tangents (carry_tangents);
948 MENU.set_mirror_tangents (mirror_tangents);
949 MENU.sp_waveform_hz.set_value (hz);
950 MENU.sp_waveform_periods.set_value (nperiods);
951 MENU.sp_curve_rpm.set_value (last_rpm);
952 dont_call_listener (MENU.cb_show_waveform_samples, samples_enabled);
953 dont_call_listener (MENU.cb_label_vertices, label_vertices);
954 dont_call_listener (MENU.cb_draw_curve, draw_curve_only);
955 dont_call_listener (MENU.cb_overlay, overlay);
956 if (uis.is_widget_on_screen (&uis.plugin__browser, this)) {
957 uis.plugin__browser.set_ed (this);
958 uis.plugin__browser.set_fold (!draw_plugin_output);
959 }
960 }
961
calc_visual_params()962 void curve_editor::calc_visual_params () {
963 float var = view.height * 1.0 / view.width;
964 float wh = win.width * var, wh2 = wh / 2.0f;
965 win.set (win.left, win.midy - wh2, win.right, win.midy + wh2);
966 win.calc ();
967 basic_editor::calc_visual_params ();
968 }
969
clear_scratch_curve()970 void curve_editor::clear_scratch_curve () {
971 win_scratch_points.clear ();
972 curv_scratch_points.clear ();
973 scratch_curve.clear ();
974 show_scratch_curve = 0;
975 }
976
attach_library(curve_library * lib)977 void curve_editor::attach_library (curve_library* lib) {
978 library = lib;
979 }
980
bg()981 void curve_editor::bg () {
982 apply_mocap ();
983 rotate ();
984 }
985
curve_info(multi_curve * c,curve_listener * l,int p)986 curve_info::curve_info (multi_curve* c, curve_listener* l, int p) {
987 curve = c;
988 lisner = l;
989 picked = p;
990 }
991
curve_info()992 curve_info::curve_info () {
993 curve = 0;
994 lisner = 0;
995 picked = 0;
996 }
997
998
clear_hit(hit_t & h)999 void curve_editor::clear_hit (hit_t& h) {
1000 h.clear ();
1001 }
1002
load_curve(int dir)1003 void curve_editor::load_curve (int dir) {
1004 if (!pik()) pik = pick_cur_curve ();
1005 multi_curve& crv = *pik.crv;
1006 mix = crv;
1007 undos.push_back (undo_t (pik.crv_id, crv, win));
1008 if (dir == 1) crv = library->next (); else crv = library->prev();
1009 crv.set_color (mix.r, mix.g, mix.b);
1010 crv.name = mix.name;
1011 setup_tools_menu ();
1012 pomo.validate ();
1013 curveinfo[pik.crv_id].lisner->edited (this, pik.crv_id);
1014 cons.rollup (1);
1015 }
1016
add_curve()1017 void curve_editor::add_curve () {
1018 if (!library) return;
1019 if (!pik()) pik = pick_cur_curve ();
1020 curve_info& ci = curveinfo [pik.crv_id];
1021 library->add (*ci.curve);
1022 }
1023
replace_curve()1024 void curve_editor::replace_curve () {
1025 if (!library) return;
1026 if (!pik()) pik = pick_cur_curve ();
1027 library->replace (*get_curve (pik.crv_id));
1028 }
1029
insert_curve()1030 void curve_editor::insert_curve () {
1031 if (!library) return;
1032 if (!pik()) pik = pick_cur_curve ();
1033 library->insert (*get_curve (pik.crv_id));
1034 }
1035
paste(hit_t & hit)1036 void curve_editor::paste (hit_t& hit) {
1037 if (hit()) {
1038 curve_info& ci = curveinfo [hit.crv_id];
1039 multi_curve* crv = ci.curve;
1040 if (copy.num_vertices) {
1041 mix = *crv;
1042 undos.push_back (undo_t (hit.crv_id, *crv, win));
1043 std::string crv_name (crv->name);
1044 float cr, cg, cb;
1045 crv->get_color (cr, cg, cb);
1046 *crv = copy;
1047 crv->set_color (cr, cg, cb);
1048 crv->name = crv_name;
1049 pomo.validate ();
1050 ci.lisner->edited (this, hit.crv_id);
1051 cons << GREEN << "Pasted into " << crv->name << eol;
1052 } else cons << RED << "Nothing to paste!" << eol;
1053 do_nothing ();
1054 } else cons << RED << "Pick a curve to paste." << eol;
1055 }
1056
selection()1057 std::string curve_editor::selection () {
1058 std::stringstream ss;
1059 const char* what [] = {"invalid", "v", "lt", "rt"};
1060 for (int i = 0, j = hitlist.size (); i < j; ++i) {
1061 hit_t& h = hitlist[i];
1062 multi_curve* c = h.crv;
1063 float x, y;
1064 switch (h.what) {
1065 case hit_t::VERTEX:
1066 c->get_vertex (h.id, x, y);
1067 break;
1068 case hit_t::LEFT_TANGENT:
1069 c->get_left_tangent (h.id, x, y);
1070 break;
1071 case hit_t::RIGHT_TANGENT:
1072 c->get_right_tangent (h.id, x, y);
1073 break;
1074 }
1075 ss << '{' << c->name << ' ' << what[h.what] << ' ' << h.id << ' ' << x << ' ' << y << "} ";
1076 }
1077 return ss.str ();
1078 }
1079
1080
1081
picked_using_picker(int id)1082 void curve_editor::picked_using_picker (int id) {
1083 set_pick_from_hitlist (id);
1084 switch (todo) {
1085 case NOTHING:
1086 prep_move ();
1087 break;
1088 case PICK_CURVE:
1089 curve_picked ();
1090 break;
1091 case REMOVE_VERTEX:
1092 remove ();
1093 break;
1094 case FOLD_VERTEX:
1095 fold_tangents_of_vertex (pik);
1096 break;
1097 case UNFOLD_VERTEX:
1098 unfold_tangents_of_vertex (pik);
1099 break;
1100 case MIRROR_VERTEX:
1101 mirror ();
1102 break;
1103 case ASSIGN_CAPTURE:
1104 assign_mouse_capture ();
1105 break;
1106 case MODULATE_POINT:
1107 modulate_point (1);
1108 break;
1109 }
1110 }
1111
remove_using_menu()1112 void curve_editor::remove_using_menu () {
1113 todo = REMOVE_VERTEX;
1114 cursor_mesg = " Click on vertex to delete. ESC to stop.";
1115 }
1116
modulate_point()1117 void curve_editor::modulate_point () {
1118 todo = MODULATE_POINT;
1119 cursor_mesg = " Click on vertex or tangent to modulate. ESC to stop.";
1120 }
1121
modulate_point(int)1122 void curve_editor::modulate_point (int) {
1123 if (pik()) {
1124 undos.push_back (undo_t (pik.crv_id, *pik.crv, win));
1125 pomo.add (pik);
1126 }
1127 }
1128
insert_using_menu()1129 void curve_editor::insert_using_menu () {
1130 if (num_curves == 1) {
1131 todo = INSERT_VERTEX;
1132 cursor_mesg = " Click to insert vertex. ESC to stop.";
1133 } else {
1134 todo = PICK_CURVE;
1135 cursor_mesg = " Pick curve to insert vertex. ESC to abort!";
1136 next_todo = INSERT_VERTEX;
1137 next_cursor_mesg = " Click to insert vertex. ESC to stop.";
1138 }
1139 }
1140
fold_tangents_using_menu()1141 void curve_editor::fold_tangents_using_menu () {
1142 int fold_vertex = MENU.cb_selection_only.state;
1143 if (fold_vertex) {
1144 todo = FOLD_VERTEX;
1145 cursor_mesg = " Click on vertex to fold tangents. ESC to stop.";
1146 } else {
1147 if (num_curves == 1) {
1148 pik = pick_cur_curve ();
1149 fold_all_tangents (pik);
1150 do_nothing ();
1151 } else {
1152 todo = PICK_CURVE;
1153 next_todo = FOLD_ALL;
1154 next_cursor_mesg = "";
1155 cursor_mesg = " Pick curve to fold tangents. ESC to stop.";
1156 }
1157 }
1158 }
1159
unfold_tangents_using_menu()1160 void curve_editor::unfold_tangents_using_menu () {
1161 int unfold_vertex = MENU.cb_selection_only.state;
1162 if (unfold_vertex) {
1163 todo = UNFOLD_VERTEX;
1164 cursor_mesg = " Click on vertex to unfold tangents. ESC to stop.";
1165 } else {
1166 if (num_curves == 1) {
1167 pik = pick_cur_curve ();
1168 unfold_all_tangents (pik);
1169 do_nothing ();
1170 } else {
1171 todo = PICK_CURVE;
1172 cursor_mesg = " Pick curve to unfold tangents. ESC to stop.";
1173 next_todo = UNFOLD_ALL;
1174 next_cursor_mesg = "";
1175 }
1176 }
1177 }
1178
mirror_using_menu()1179 void curve_editor::mirror_using_menu () {
1180 int mirror_vertex = MENU.cb_selection_only.state;
1181 if (mirror_vertex) {
1182 todo = MIRROR_VERTEX;
1183 cursor_mesg = " Click on vertex or tangent to flip. ESC to stop.";
1184 } else {
1185 if (num_curves == 1) {
1186 pik = pick_cur_curve ();
1187 int whole_curve = 1;
1188 mirror (whole_curve);
1189 do_nothing ();
1190 } else {
1191 todo = PICK_CURVE;
1192 cursor_mesg = " Pick the curve to flip. ESC to stop.";
1193 next_todo = MIRROR_ALL;
1194 next_cursor_mesg = "";
1195 }
1196 }
1197 }
1198
copy_using_menu()1199 void curve_editor::copy_using_menu () {
1200 if (num_curves == 1) {
1201 copy = *curveinfo[0].curve;
1202 cons << GREEN << "Copied " << copy.name << eol;
1203 } else {
1204 todo = PICK_CURVE;
1205 cursor_mesg = " Pick the curve to copy. ESC to stop.";
1206 next_todo = COPY;
1207 next_cursor_mesg = "";
1208 }
1209 }
1210
paste_using_menu()1211 void curve_editor::paste_using_menu () {
1212 if (num_curves == 1) {
1213 pik = pick_cur_curve ();
1214 paste (pik);
1215 } else {
1216 todo = PICK_CURVE;
1217 cursor_mesg = " Pick the curve to paste. ESC to stop.";
1218 next_todo = PASTE;
1219 next_cursor_mesg = "";
1220 }
1221 }
1222
fold_all_tangents(hit_t & hit)1223 void curve_editor::fold_all_tangents (hit_t& hit) {
1224 curve_info& ci = curveinfo [hit.crv_id];
1225 multi_curve& crv = *ci.curve;
1226 mix = crv;
1227 undos.push_back (undo_t (hit.crv_id, crv, win));
1228 convert2_polyline (crv);
1229 ci.lisner->edited (this, hit.crv_id);
1230 }
1231
unfold_all_tangents(hit_t & hit)1232 void curve_editor::unfold_all_tangents (hit_t& hit) {
1233 curve_info& ci = curveinfo [hit.crv_id];
1234 multi_curve& crv = *ci.curve;
1235 mix = crv;
1236 undos.push_back (undo_t (hit.crv_id, crv, win));
1237 const point<float>& obj = get_obj_chunk ();
1238 convert2_catmull_rom (crv, max (obj.x, obj.y)); // turn bezier curve into 'catmull-rom' spline; still a bezier curve
1239 ci.lisner->edited (this, hit.crv_id);
1240 }
1241
fold_tangents_of_vertex(hit_t & hit)1242 void curve_editor::fold_tangents_of_vertex (hit_t& hit) {
1243 if (hit()) {
1244 curve_info& ci = curveinfo[hit.crv_id];
1245 multi_curve& crv = *ci.curve;
1246 mix = crv;
1247 undos.push_back (undo_t (hit.crv_id, crv, win));
1248 float vx, vy; crv.get_vertex (hit.id, vx, vy);
1249 crv.set_left_tangent (hit.id, vx, vy);
1250 crv.set_right_tangent (hit.id, vx, vy);
1251 crv.evaluate ();
1252 ci.lisner->edited (this, hit.crv_id);
1253 do_nothing ();
1254 }
1255 }
1256
unfold_tangents_of_vertex(hit_t & hit)1257 void curve_editor::unfold_tangents_of_vertex (hit_t& hit) {
1258 if (hit()) {
1259 curve_info& ci = curveinfo [hit.crv_id];
1260 multi_curve& crv = *ci.curve;
1261 mix = crv;
1262 undos.push_back (undo_t (hit.crv_id, crv, win));
1263 const point<float>& obj = get_obj_chunk ();
1264 float vx, vy; crv.get_vertex (hit.id, vx, vy);
1265 crv.set_left_tangent (hit.id, vx - obj.x, vy);
1266 crv.set_right_tangent (hit.id, vx + obj.x, vy);
1267 crv.evaluate ();
1268 ci.lisner->edited (this, hit.crv_id);
1269 do_nothing ();
1270 }
1271 }
1272
render_curve_samples()1273 void curve_editor::render_curve_samples () {
1274 if (samples_enabled) {
1275 if (!pik()) pik = pick_cur_curve ();
1276 cs.render (pik.crv);
1277 }
1278 }
1279
toggle_waveform_samples_display()1280 void curve_editor::toggle_waveform_samples_display () {
1281 if (is_waveform_editor) {
1282 samples_enabled = !samples_enabled;
1283 render_curve_samples ();
1284 dont_call_listener (MENU.cb_show_waveform_samples, samples_enabled);
1285 }
1286 }
1287
set_hz(float zh)1288 void curve_editor::set_hz (float zh) {
1289 hz = zh;
1290 if (hz < 0) hz = SAMPLE_RATE / 100;
1291 cs.set (hz, cs.nperiods);
1292 render_curve_samples ();
1293 }
1294
set_periods(int p)1295 void curve_editor::set_periods (int p) {
1296 cs.set (cs.hz, p);
1297 render_curve_samples ();
1298 }
1299
do_nothing()1300 void curve_editor::do_nothing () {
1301 stop_mouse_capture ();
1302 lmb_move = 0;
1303 if (todo == ADD_VERTEX) {
1304 if (MENU.show == 0)
1305 replace ();
1306 else
1307 clear_scratch_curve ();
1308 }
1309 todo = next_todo = NOTHING;
1310 cursor_mesg = next_cursor_mesg = "";
1311 }
1312
copy_curve()1313 void curve_editor::copy_curve () {
1314 if (pik()) {
1315 copy = *get_curve(pik.crv_id);
1316 cons << GREEN << "Copied "<< copy.name << "." << eol;
1317 do_nothing ();
1318 }
1319 }
1320
do_load_curve(int dir)1321 void curve_editor::do_load_curve (int dir) {
1322 if (library && library->num_curves()) load_curve (dir);
1323 }
1324
do_redo()1325 void curve_editor::do_redo () {
1326 dodo (redos, undos, "no more redos.");
1327 }
1328
do_undo()1329 void curve_editor::do_undo () {
1330 dodo (undos, redos, "no more undos.");
1331 }
1332
do_pick_curve()1333 void curve_editor::do_pick_curve () {
1334 clear_hit (pik);
1335 todo = PICK_CURVE;
1336 cursor_mesg = " Click to pick curve, ESC to abort!";
1337 next_todo = NOTHING;
1338 next_cursor_mesg = "";
1339 }
1340
pick_cur_curve()1341 hit_t curve_editor::pick_cur_curve () {
1342 multi_curve* crv = curveinfo[curcrv].curve;
1343 return hit_t (crv, 0);
1344 }
1345
get_picked_curve()1346 multi_curve* curve_editor::get_picked_curve () {
1347 if (!pik()) {
1348 pik = pick_cur_curve ();
1349 return pik.crv;
1350 } else
1351 return pik.crv;
1352 }
1353
set_picked_curve_name(const string & name)1354 void curve_editor::set_picked_curve_name (const string& name) {
1355 if (pik()) {
1356 cons << "Curve " << pik.crv->name << " changed to " << name << eol;
1357 pik.crv->set_name (name);
1358 } else
1359 cons << RED << "Please pick a curve" << eol;
1360 }
1361
delete_curve()1362 void curve_editor::delete_curve () {
1363 if (library) library->del ();
1364 }
1365
draw_replacement_curve_using_menu()1366 void curve_editor::draw_replacement_curve_using_menu () {
1367 if (num_curves == 1) {
1368 cons << YELLOW << "Replacing the viewed curve" << eol;
1369 pik = pick_cur_curve ();
1370 show_scratch_curve = 1;
1371 todo = ADD_VERTEX;
1372 cursor_mesg = " Click to add vertex. ESC to stop.";
1373 } else {
1374 todo = PICK_CURVE;
1375 cursor_mesg = " Pick curve to replace. ESC to abort!";
1376 next_todo = ADD_VERTEX;
1377 next_cursor_mesg = " Click to add vertex. ESC to abort!";
1378 }
1379 }
1380
add_vertex()1381 void curve_editor::add_vertex () {
1382 show_scratch_curve = 1;
1383 float sx, sy; snap (sx, sy);
1384 win_scratch_points.push_back (point<float> (sx, sy));
1385 float curvx, curvy; win2obj (sx, sy, curvx, curvy);
1386 curv_scratch_points.push_back (point<float>(curvx, curvy));
1387 if (curv_scratch_points.size () < 2) cursor_mesg = "Click to add vertex. ESC to abort!"; else cursor_mesg = "Click to add vertex. ESC to complete.";
1388 }
1389
assign_mouse_capture()1390 void curve_editor::assign_mouse_capture () {
1391 if (pik()) {
1392 undos.push_back (undo_t (pik.crv_id, *get_curve(pik.crv_id), win));
1393 macros.push_back (mouse_macro (mocap0, pik, capturer.add ()));
1394 cons << GREEN << "Assigned mouse capture to " << pik << eol;
1395 do_nothing ();
1396 }
1397 }
1398
assign_mouse_capture_from_menu()1399 void curve_editor::assign_mouse_capture_from_menu () {
1400 if (mocap0()) {
1401 todo = ASSIGN_CAPTURE;
1402 next_todo = NOTHING;
1403 cursor_mesg = " Pick vertex or tangent to assign mouse capture. ESC to abort!";
1404 } else cons << RED << "No mouse capture found!" << eol;
1405 }
1406
remove_mouse_capture(state_button * sb)1407 void curve_editor::remove_mouse_capture (state_button* sb) {
1408 for (vector<mouse_macro>::iterator i = macros.begin(), j = macros.end(); i != j;) {
1409 mouse_macro& m = *i;
1410 if (m.sb == sb) {
1411 cons << GREEN << "Removed mouse capture from " << m.hit << eol;
1412 i = macros.erase (i);
1413 j = macros.end ();
1414 if (macros.empty()) {
1415 do_nothing ();
1416 return;
1417 }
1418 } else ++i;
1419 }
1420 }
1421
toggle_mouse_capture(vector<state_button * > & caps)1422 void curve_editor::toggle_mouse_capture (vector<state_button*>& caps) {
1423 int p = 0, q = 0;
1424 for (vector<mouse_macro>::iterator i = macros.begin(), j = macros.end(); i != j; ++i) {
1425 mouse_macro& mm = *i;
1426 for (int i = 0, ncaps = caps.size (); i < ncaps; ++i) {
1427 state_button* sb = caps[i];
1428 if (sb->state && mm.sb == sb) {
1429 mm.paused = !mm.paused;
1430 if (mm.paused) ++p; else ++q;
1431 }
1432 }
1433 }
1434 cons << GREEN << "Played " << q << " and Paused " << p << " mouse captures" << eol;
1435 }
1436
start_mouse_capture_from_menu()1437 void curve_editor::start_mouse_capture_from_menu () {
1438 start_mouse_capture ();
1439 todo = START_CAPTURE;
1440 cursor_mesg = " Capturing mouse. Click or ESC to finish!";
1441 }
1442
set_limit(float f)1443 void curve_editor::set_limit (float f) {
1444 if (!pik()) pik = pick_cur_curve ();
1445 curve_info& ci = curveinfo [pik.crv_id];
1446 multi_curve* crv = ci.curve;
1447 crv->set_limit (f);
1448 crv->evaluate ();
1449 ci.lisner->edited (this, pik.crv_id);
1450 }
1451
setup_tools_menu()1452 void curve_editor::setup_tools_menu () {
1453 multi_curve* crv = get_curve (curcrv);
1454 MENU.lf_curve_name.set_text (crv->name);
1455 MENU.sp_curve_limit.set_value (crv->limit);
1456 MENU.picked (MENU.ol_mirror.option, 0);
1457 set_curve_style ();
1458 }
1459
curve_picked()1460 void curve_editor::curve_picked () {
1461 setup_tools_menu ();
1462 if (next_todo == FOLD_ALL) fold_all_tangents (pik);
1463 else if (next_todo == UNFOLD_ALL) unfold_all_tangents (pik);
1464 else if (next_todo == MIRROR_ALL) {int whole_curve = 1; mirror (whole_curve);}
1465 else if (next_todo == COPY) copy_curve ();
1466 else if (next_todo == PASTE) paste (pik);
1467 else {
1468 todo = next_todo;
1469 cursor_mesg = next_cursor_mesg;
1470 }
1471 }
1472
1473
set_curve_style()1474 void curve_editor::set_curve_style () {
1475 multi_curve* crv = get_curve (curcrv);
1476 string pre (" Curve is "); if (is_waveform_editor) pre = " Waveform is ";
1477 if (crv->shapeform) MENU.ol_curve_style.set_text(pre + "a shape"); else MENU.ol_curve_style.set_text (pre + "classical");
1478 }
1479
toggle_curve_style()1480 void curve_editor::toggle_curve_style () {
1481 multi_curve* crv = get_curve (curcrv);
1482 mix = *crv;
1483 crv->set_shapeform (!crv->shapeform);
1484 set_curve_style ();
1485 render_curve_samples ();
1486 if (crv->shapeform && is_waveform_editor && !samples_enabled) toggle_waveform_samples_display ();
1487 curveinfo[curcrv].lisner->edited (this, curcrv);
1488 }
1489
set_rpm(float _rpm)1490 void curve_editor::set_rpm (float _rpm) {
1491 if (_rpm == 0) {
1492 rpm = hit_t ();
1493 } else {
1494 if (!pik()) pik = pick_cur_curve ();
1495 rpm = pik;
1496 float rps = _rpm / 60.0;
1497 float rpf = rps / FPS;
1498 angle = rpf * TWO_PI;
1499 if (last_rpm == 0) {
1500 undos.push_back (undo_t (rpm.crv_id, *rpm.crv, win));
1501 rpm.crv->calc_centroid ();
1502 }
1503 startt = ui_clk() - TIME_PER_FRAME;
1504 }
1505 last_rpm = _rpm;
1506 }
1507
rotate()1508 void curve_editor::rotate () {
1509 if (rpm()) {
1510 float now = ui_clk();
1511 float elapsed = now - startt;
1512 if (elapsed >= TIME_PER_FRAME) {
1513 float mult = elapsed / TIME_PER_FRAME;
1514 rpm.crv->rotate (mult * angle);
1515 curveinfo[rpm.crv_id].lisner->edited (this, rpm.crv_id);
1516 startt = ui_clk();
1517 }
1518 }
1519 }
1520
scale(float sx,float sy)1521 void curve_editor::scale (float sx, float sy) {
1522 get_picked_curve ();
1523 undos.push_back (undo_t (pik.crv_id, *pik.crv, win));
1524 pik.crv->scale (sx, sy);
1525 }
1526
hilite_item(int id)1527 void curve_editor::hilite_item (int id) {
1528 hit_t& hit = hitlist[id];
1529 glLineWidth (2);
1530 point<float>& v = hit.crv->vertices [hit.id];
1531 point<float>& lt = hit.crv->left_tangents [hit.id];
1532 point<float>& rt = hit.crv->right_tangents [hit.id];
1533 glColor3f (1.0f, 0.6f, 1.0f);
1534 draw_handle (v);
1535 switch (hit.what) {
1536 case hit_t::LEFT_TANGENT:
1537 draw_tangent (v, lt);
1538 draw_handle (lt);
1539 break;
1540 case hit_t::RIGHT_TANGENT:
1541 draw_tangent (v, rt);
1542 draw_handle (rt);
1543 break;
1544 }
1545 glLineWidth (1);
1546 }
1547
apply_plugin(plugin * p)1548 void curve_editor::apply_plugin (plugin* p) {
1549 int r = 0;
1550 multi_curve* crv = curveinfo [curcrv].curve;
1551 if (p->mix) mix = *crv;
1552 if (p->undo) {
1553 undos.push_back (undo_t (curcrv, *crv, win));
1554 r = p->apply (*crv);
1555 if (r == 0) {
1556 undos.pop_back ();
1557 return;
1558 }
1559 } else {
1560 r = p->apply (*crv);
1561 }
1562
1563 if (r) {
1564 if (p == &spiraler_ || p == &rosemilker)
1565 crv->centroid_style = multi_curve::SET;
1566 else
1567 crv->centroid_style = multi_curve::CALC;
1568 pomo.validate ();
1569 curveinfo[curcrv].lisner->edited (this, curcrv);
1570 }
1571 }
1572
stop_todo()1573 int curve_editor::stop_todo () {
1574 if (todo != curve_editor::NOTHING) {
1575 do_nothing ();
1576 return 1;
1577 }
1578 return 0;
1579 }
1580
1581 #ifdef __SVG__
write_samples(ofstream & svg)1582 void curve_editor::write_samples (ofstream& svg) {
1583 float x = 0, y = 0;
1584 float ox, oy;
1585 obj2win (x, y, ox, oy);
1586 static float cx = cs.x[0];
1587 float dx, dy;
1588 for (int i = 0; i < cs.n; ++i) {
1589 obj2win (cs.x[i], cs.y[i], dx, dy);
1590 svg << "<polyline fill=\"none\" stroke=\"black\" points=\"";
1591 float cdx = cx + dx;
1592 svg << cdx << ',' << dy << ' ' << cdx << ',' << oy << endl;
1593 svg << "\"/>" << endl;
1594 }
1595 cx += dx;
1596 }
1597
write_curve(multi_curve * crv,ofstream & svg,float w,float h,float t,float left,float top,box<float> & bbox)1598 void curve_editor::write_curve (multi_curve* crv, ofstream& svg, float w, float h, float t, float left, float top, box<float>& bbox) {
1599 svg << "<polyline style=\"stroke-width:" << t << ";stroke-linecap:round;stroke-miterlimit:" << t << ";\" fill=\"none\" stroke=\"black\" points=\"";
1600 vector<crvpt> vpts; crv->get_profile_points (vpts);
1601 for (int p = 0, q = vpts.size (); p < q; ++p) {
1602 float dx = vpts[p].x, dy = vpts[p].y;
1603 svg << left + w * (dx - bbox.left) / bbox.width << "," << top + h * (dy - bbox.bottom) / bbox.height << spc;
1604 }
1605 svg << "\"/>" << endl;
1606 }
1607
write_svg(float h,float t,const string & fn,float left,float top)1608 void curve_editor::write_svg (float h, float t, const string& fn, float left, float top) {
1609 multi_curve* crv = get_picked_curve ();
1610 box<float> bbox; crv->calc_bbox (bbox);
1611 string fname = user_data_dir + fn;
1612 ofstream svg (fname.c_str(), ios::out);
1613 float w = bbox.width / bbox.height * h;
1614 cons << "w = " << w << " h = " << h << "bbox: " << bbox << eol;
1615 svg << "<?xml version=\"1.0\"?>" << endl;
1616 svg << "<svg xmlns=\"https://www.w3.org/2000/svg\" width=\"" << w << "\" height=\"" << h << "\" viewBox=\"" << left << spc << top << spc << w << spc << h << "\">" << endl;
1617 write_curve (crv, svg, w, h, t, left, top, bbox);
1618 svg << "</svg>" << endl;
1619 cons << GREEN << "written curve to: " << fname << eol;
1620 }
1621
1622 #endif
1623
1624 #ifdef __HPGL__
1625
write_curve(multi_curve * crv,ofstream & hpgl,float scale,float penmag)1626 void curve_editor::write_curve (multi_curve* crv, ofstream& hpgl, float scale, float penmag) {
1627 vector<crvpt> vpts; crv->get_profile_points (vpts);
1628 float minx = -1.0f, miny = -1.0f, maxx = 1.0f, maxy = 1.0f, width = maxx - minx, height = maxy - miny;
1629 for (int i = 0, j = vpts.size (); i < j; ++i) {
1630 float x = vpts[i].x, y = vpts[i].y;
1631 float ox = (x - minx) * scale / width;
1632 float oy = (y - miny) * scale / height;
1633 vpts[i].x = ox;
1634 vpts[i].y = oy;
1635 }
1636 float lx = vpts[0].x, ly = vpts[0].y;
1637 float m = 0;
1638 rnd<int> pen (1, 8);
1639 static const char semicolon = ';';
1640 for (int p = 1, q = vpts.size (); p < q; ++p) {
1641 float px = vpts[p].x, py = vpts[p].y;
1642 float dx = (px - lx), dy = (py - ly);
1643 m += magnitude (dx, dy);
1644 if (m >= penmag) { // switch pen for fun
1645 m -= penmag;
1646 hpgl << "SP" << pen () << semicolon << eol;
1647 }
1648 hpgl << "PR" << dx << ", " << dy << semicolon << eol;
1649 lx = px;
1650 ly = py;
1651 }
1652 }
1653
write_hpgl(float scale,float penmag)1654 void curve_editor::write_hpgl (float scale, float penmag) {
1655 multi_curve* crv = get_picked_curve ();
1656 string fname = user_data_dir + crv->name + ".hpgl";
1657 ofstream hpgl (fname.c_str(), ios::out);
1658 hpgl << "IN;" << eol;
1659 hpgl << "PD;" << eol;
1660 write_curve (crv, hpgl, scale, penmag);
1661 hpgl << "PU;" << eol;
1662 cons << GREEN << "written curve to: " << fname << eol;
1663 }
1664
1665 #endif
1666
esc()1667 int curve_editor::esc () {
1668 int ret = 0;
1669 if (stop_todo())
1670 ret = 1;
1671 else {
1672 if (!rmb) {
1673 load_instrument ();
1674 ret = 1;
1675 } else
1676 ret = 0;
1677 }
1678 if (sinemixer.harms.editing) {
1679 sinemixer.harms.stop_editing ();
1680 ret = 1;
1681 }
1682 return ret;
1683 }
1684
drawerlay()1685 void curve_editor::drawerlay () {
1686 // called from plugin sin/cos/radius editors
1687 project ();
1688 if (over) uis.plugin__browser.plugins[uis.plugin__browser.cur]->draw (dynamic_cast<curve_editor*>(over));
1689 unproject ();
1690 }
1691