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