1 /*
2 * mondrian.cc
3 * inspired by the works of Piet Mondrian
4 * DIN Is Noise is released under GNU Public License 2.0
5 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
6 * For more information, please visit https://dinisnoise.org/
7 */
8
9 #include <fstream>
10 #include <iostream>
11 #include <sstream>
12 #include "ui_list.h"
13 #include "main.h"
14 #include "font.h"
15 #include "console.h"
16 #include "mondrian.h"
17 #include "solver.h"
18 #include "random.h"
19 #include "utils.h"
20 #include "vector2d.h"
21 #include "font.h"
22 #include "audio.h"
23 #include "curve_library.h"
24 #include "container.h"
25 #include "rect.h"
26 #include "ball.h"
27 #include "slit.h"
28 #include "oscilloscope.h"
29
30 #include <algorithm>
31 #include <math.h>
32
33 using namespace std;
34
35 extern std::string user_data_dir;
36 extern viewport view;
37 extern font fnt;
38 extern mondrian mondrian0;
39 extern audio_out aout;
40 extern curve_library wav_lib, attack_lib, decay_lib;
41 extern gotog _gotomax;
42 extern int quit;
43 extern beat2value octave_shift;
44 extern float GOLDEN_RATIO;
45 extern const float PI_BY_180;
46 extern int IPS;
47 extern std::map <string, float> INTERVALS;
48 extern oscilloscope scope;
49 extern char BUFFER [];
50 extern float MIN_TIME;
51 extern int line_height;
52
mondrian()53 mondrian::mondrian () :
54 wave ("mondrian_waveform.crv"), waved ("mondrian_waveform.ed"), wavlis (wave_listener::MONDRIAN),
55 attack ("mondrian_attack.crv"), decay ("mondrian_decay.crv"), attacked ("mondrian_attack.ed"),
56 decayed ("mondrian_decay.ed"), fdr (slit::INITIAL_OPEN_CLOSE_TIME), _help ("mondrian.hlp") {
57
58 pan = zoom = 1;
59 root = 0;
60 hit = 0;
61 edge = edge::NONE;
62 num_balls = 0;
63 adding_balls = 0;
64 moving_balls = 0;
65 editing_edge = 0;
66 editing_slit = 0;
67 slitting = NOTHING;
68 started_making_ball = 0;
69 new_ball = 0;
70 n_pts = 0;
71 pts = 0;
72 pts_d = 0;
73 pts_clr = 0;
74 n_mrk = 0;
75 mrk = 0;
76 cursor = 0;
77 num_triggered_notes = 0;
78 note_volume = 0;
79 voices = 0;
80 min_voices = 0;
81 auto_adjust_voices = 0;
82 delta_attack_time = delta_decay_time = MIN_TIME;
83 lmb_clicked = 0;
84 num_boxes = 8;
85 label_notes = 1;
86 label_hz_vol = 0;
87 fill_boxes = 1;
88 draw__boxes = 1;
89 draw__notes = 1;
90 draw_slit_cutter = 0;
91 num_selected_slits = 0;
92 num_selected_balls = 0;
93 sel_tar = SELECT_BALLS;
94 nleaves = 0;
95
96 // box auto splitting
97 splitting_rects = 0;
98 auto_split_orient = split::BOTH;
99 auto_split_at = split::NOTES;
100
101 // both [auto]split, delete
102 split_leaf = rect::BIGGEST;
103 delete_leaf = rect::RANDOM;
104
105 delete_all_rects = 0;
106
107 inst = 1;
108
109 }
110
~mondrian()111 mondrian::~mondrian () {
112 wave.save ("mondrian_waveform.crv");
113 attack.save ("mondrian_attack.crv");
114 decay.save ("mondrian_decay.crv");
115 ofstream edf ((user_data_dir + "mondrian.ed").c_str (), ios::out); save_settings (edf);
116 ofstream dataf ((user_data_dir + "mondrian.data").c_str(), ios::out);
117 string R("R");
118 save_boxes (dataf, root, R);
119 save_balls (dataf);
120 dataf << "poly radius " << poly.radius << " points " << poly.points << endl;
121 save_slits (dataf);
122 if (pts) delete[] pts;
123 if (pts) delete[] pts_d;
124 if (pts_clr) delete[] pts_clr;
125 if (mrk) delete[] mrk;
126 for (balls_iterator p = balls.begin (), q = balls.end (); p != q; ++p) delete *p;
127 if (root) delete_children (root);
128 if (new_ball) delete new_ball;
129 dlog << "--- destroyed Mondrian --" << endl;
130 }
131
enter()132 void mondrian::enter () {}
133
leave()134 void mondrian::leave () {
135 stop_doing_stuff ();
136 ui::leave ();
137 }
138
139
launch_note(ball * _ball,float t,float t0,float dt,const pair<float,float> & invl)140 void mondrian::launch_note (ball* _ball, float t, float t0, float dt, const pair<float, float>& invl) {
141 if (quit != DONT || (lmb && _ball == new_ball)) return;
142 float mid = (invl.first + invl.second) / 2.0f;
143 if (t < mid) t = invl.first; else t = invl.second;
144 float interval = 1 + (t - t0) * dt;
145 float frequency = get_tonic (this) * interval * _ball->pitch_mult;
146 N.set_freq (frequency);
147 ++num_triggered_notes;
148 if (auto_adjust_voices)
149 voices = max (min_voices, min_voices + num_triggered_notes);
150 else
151 voices = min_voices;
152 note_volume = 1.0f / voices * _ball->vol_mult;
153
154 triggered_notes.push_back (triggered_note (N, note_volume, _ball->x, _ball->y, _ball->trig_what));
155 triggering_balls.push_back (_ball);
156 ++_ball->num_notes;
157 triggered_note& last_triggered_note = triggered_notes.back ();
158 last_triggered_note.setup (&wave, &attack, &decay);
159 last_triggered_note.r *= _ball->pitch_mult;
160 last_triggered_note.g *= _ball->pitch_mult;
161 last_triggered_note.b *= _ball->pitch_mult;
162 print_num_triggered_notes ();
163 }
164
print_num_triggered_notes()165 void mondrian::print_num_triggered_notes () {
166 stringstream ss; ss << "Voices: " << num_triggered_notes << "/" << voices;
167 uis.l_mondrian_voices.set_text (ss.str());
168 }
169
randomise_box_color()170 void mondrian::randomise_box_color () {
171 finding f; find (root, win.mousex, win.mousey, f);
172 rect* found = f.found;
173 if (found) found->make_random_color ();
174 }
175
get_box_balls()176 list<ball*>& mondrian::get_box_balls () { // get balls in box or all balls
177 finding f; find (root, win.mousex, win.mousey, f);
178 rect* found = f.found;
179 if (found) return found->balls; else return balls;
180 }
181
get_balls()182 list<ball*>& mondrian::get_balls () { // get selected or balls in box or all balls
183 if (num_selected_balls) return selected_balls; else return get_box_balls ();
184 }
185
get_balls(int)186 list<ball*>& mondrian::get_balls (int) { // get selected or all balls
187 if (num_selected_balls) return selected_balls; else return balls;
188 }
189
freeze_thaw_balls(list<ball * > & _balls)190 void mondrian::freeze_thaw_balls (list<ball*>& _balls) {
191 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
192 ball* b = *p;
193 b->frozen = !b->frozen;
194 if (b->frozen == 0 && b->V == 0) cons << YELLOW << "Defrosted ball [" << (uintptr_t) b << "] cant move [0 speed]" << eol;
195 }
196 }
197
freeze_balls(list<ball * > & _balls)198 void mondrian::freeze_balls (list<ball*>& _balls) {
199 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
200 ball* b = *p;
201 b->frozen = 1;
202 if (b->V == 0) cons << YELLOW << "Ball [" << (uintptr_t) b << "] cant move already [0 speed]" << eol;
203 }
204 }
205
thaw_balls(list<ball * > & _balls)206 void mondrian::thaw_balls (list<ball*>& _balls) {
207 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
208 ball* b = *p;
209 b->frozen = 0;
210 if (b->V == 0) cons << YELLOW << "Defrosted ball [" << (uintptr_t) b << "] cant move [0 speed]" << eol;
211 }
212 }
213
clear_modulations(list<ball * > & _balls)214 void mondrian::clear_modulations (list<ball*>& _balls) {
215 if (num_selected_balls == 0) {
216 cons << YELLOW << "Please select some balls!" << eol;
217 return;
218 }
219 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
220 ball* b = *p;
221 b->pitch_mult = 1;
222 b->mod = 0;
223 b->color_using_modulation ();
224 }
225 cons << GREEN << "Cleared modulation on " << num_selected_balls << " balls" << eol;
226 }
227
update_parent(rect * C)228 void mondrian::update_parent (rect* C) {
229 rect* P = C->parent;
230 if (P) {
231 rect* child1 = P->child1, *child2 = P->child2;
232 box<float>& el = child1->extents;
233 box<float>& er = child2->extents;
234 box<float>& e = P->extents;
235 box<float> e0 (e);
236 if (P->split == split::VERTICAL) {
237 if (C == child1) {
238 er.left = el.right;
239 er.bottom = el.bottom;
240 er.top = el.top;
241 er.calc ();
242 } else {
243 el.right = er.left;
244 el.bottom = er.bottom;
245 el.top = er.top;
246 el.calc ();
247 }
248 } else {
249 if (C == child1) {
250 er.left = el.left;
251 er.right = el.right;
252 er.bottom = el.top;
253 er.calc ();
254 } else {
255 el.left = er.left;
256 el.right = er.right;
257 el.top = er.bottom;
258 el.calc ();
259 }
260 }
261 e.left = el.left;
262 e.right = er.right;
263 e.bottom = el.bottom;
264 e.top = er.top;
265 e.calc ();
266 if (e == e0) {
267 update_children (P->child1);
268 update_children (P->child2);
269 } else update_parent (P);
270 } else {
271 update_children (C);
272 calc_visual_params ();
273 }
274 }
275
set_edge(rect * R,int e,float x,float y)276 void mondrian::set_edge (rect* R, int e, float x, float y) {
277 R->extents.set_edge (e, x, y);
278 update_parent (R);
279 }
280
obj2win(const point<float> & v,float & wx,float & wy)281 void mondrian::obj2win (const point<float>& v, float& wx, float& wy) {
282 wx = win_per_obj.x * v.x;
283 wy = win_per_obj.y * v.y;
284 }
285
obj2win(const float & ox,const float & oy,float & wx,float & wy)286 void mondrian::obj2win (const float& ox, const float& oy, float& wx, float& wy) {
287 wx = win_per_obj.x * ox;
288 wy = win_per_obj.y * oy;
289 }
290
win2obj(const float & wx,const float & wy,float & ox,float & oy)291 void mondrian::win2obj (const float& wx, const float& wy, float& ox, float& oy) {
292 ox = obj_per_win.x * wx;
293 oy = obj_per_win.y * wy;
294 }
295
load_settings()296 void mondrian::load_settings () {
297 ifstream file ((user_data_dir + "mondrian.ed").c_str (), ios::in);
298 if (!file) return;
299 load_settings (file);
300 }
301
302
save_settings(ofstream & file)303 void mondrian::save_settings (ofstream& file) {
304 file << "window " << win.left << spc << win.bottom << spc << win.right << spc << win.top << endl;
305 file << "win_chunk " << win_chunk.x << spc << win_chunk.y << endl;
306 file << "obj_chunk " << obj_chunk.x << spc << obj_chunk.y << endl;
307 file << "win_resolution " << win_resolution << endl;
308 file << "label_hz_vol " << label_hz_vol << endl;
309 file << "min_voices " << min_voices << endl;
310 file << "auto_delete_rect " << auto_del_rect.active << endl;
311 file << "auto_delete_rect_time " << auto_del_rect.triggert << endl;
312 file << "auto_split_rect " << auto_split_rect.active << endl;
313 file << "auto_split_time " << auto_split_rect.triggert << endl;
314 file << "auto_split_orient " << auto_split_orient << endl;
315 file << "auto_split_at " << auto_split_at << endl;
316 file << "pick_box_split " << split_leaf << endl;
317 file << "pick_box_delete " << delete_leaf << endl;
318 file << "min_split_size " << mondrian::min_split_size << endl;
319 file << "draw_boxes " << draw__boxes << endl;
320 file << "draw_ball_pos " << draw_ball.position << endl;
321 file << "draw_ball_heading " << draw_ball.heading << endl;
322 file << "draw_notes " << draw__notes << endl;
323 file << "label_notes " << label_notes << endl;
324 file << "fill_boxes " << fill_boxes << endl;
325 file << "num_boxes " << num_boxes << endl;
326 file << "added_ball_type " << added_ball_type << endl;
327 file << "cursor " << cursor << endl;
328 file << "auto_adjust_voices " << auto_adjust_voices << endl;
329 file << "half_slit_size " << slit::HALF_SIZE << endl;
330 file << "turn_sync " << MENU.cb_turn_sync.state << endl;
331 file << "speed_sync " << MENU.cb_speed_sync.state << endl;
332 }
333
calc_win_mouse()334 void mondrian::calc_win_mouse () {
335 if (MENU.show == 0) win.update_mouse ();
336 }
337
338
toggle_triggered_sound()339 void mondrian::toggle_triggered_sound () {
340 list<ball*>& _balls = get_balls ();
341 int n = 0;
342 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
343 ball* b = *p;
344 int& tw = b->trig_what;
345 tw = !tw;
346 cons << "Ball " << ++n;
347 if (tw) cons << " triggers noise"; else cons << " triggers note";
348 cons << eol;
349 }
350 }
351
clear_selected_targets()352 void mondrian::clear_selected_targets () {
353 if (sel_tar == SELECT_BALLS) {
354 browse.clear ();
355 clear_selected<ball> (selected_balls, num_selected_balls);
356 }
357 else
358 clear_selected<slit> (selected_slits, num_selected_slits);
359 }
360
select_all_targets()361 void mondrian::select_all_targets () {
362 if (sel_tar == SELECT_BALLS) {
363 browse.clear ();
364 select_all<ball> (balls, selected_balls, num_selected_balls);
365 }
366 else
367 select_all<slit> (slits, selected_slits, num_selected_slits);
368 }
369
invert_selected_targets()370 void mondrian::invert_selected_targets () {
371 if (sel_tar == SELECT_BALLS) {
372 browse.clear ();
373 invert_selection<ball> (balls, selected_balls, num_selected_balls);
374 }
375 else
376 invert_selection<slit> (slits, selected_slits, num_selected_slits);
377 }
378
select_box_targets()379 void mondrian::select_box_targets () {
380 if (sel_tar == SELECT_BALLS) {
381 select_box_balls ();
382 }
383 else
384 select_box_slits ();
385 }
386
browse_ball(int i)387 void mondrian::browse_ball (int i) {
388 if (browse.n) {
389 clear_selected<ball> (selected_balls, num_selected_balls, 0);
390 browse.which += i;
391 wrap (0, browse.which, browse.last);
392 ball* bb = browse.balls [browse.which];
393 bb->select = 1;
394 selected_balls.push_back (bb);
395 ++num_selected_balls;
396 after_selection ();
397 }
398 }
399
delete_selected_targets()400 void mondrian::delete_selected_targets () {
401 if (sel_tar == SELECT_BALLS)
402 delete_selected_balls ();
403 else
404 remove_selected_slits ();
405 }
406
delete_all_targets()407 void mondrian::delete_all_targets () {
408 if (sel_tar == SELECT_BALLS)
409 delete_all_balls ();
410 else
411 remove_all_slits ();
412 }
413
update_attack()414 void mondrian::update_attack () {
415 float x, y; attack.get_vertex (attack.last_vertex, x, y); _gotomax.set (x);
416 for (note_iterator i = triggered_notes.begin (), j = triggered_notes.end (); i != j; ++i) (*i).attack.update ();
417 }
418
update_decay()419 void mondrian::update_decay () {
420 for (note_iterator i = triggered_notes.begin (), j = triggered_notes.end (); i != j; ++i) {
421 triggered_note& ti = *i;
422 solver& sol = ti.decay;
423 sol.update ();
424 float y; sol.mcrv->get_vertex (sol.mcrv->last_vertex, ti.decay_lastx, y);
425 }
426 }
427
update_waveform(multi_curve & crv)428 void mondrian::update_waveform (multi_curve& crv) {
429 static const string nam ("mondrian-waveform");
430 for (note_iterator i = triggered_notes.begin (), j = triggered_notes.end (); i != j; ++i)
431 (*i).update_solver (crv, nam);
432 }
433
draw_rect(rect * what)434 void mondrian::draw_rect (rect* what) {
435 box<float>& extents = what->extents;
436
437 if (fill_boxes) {
438 glEnable (GL_BLEND);
439 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
440 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
441 glColor4f (what->r, what->g, what->b, 0.5);
442 glRectf (extents.left, extents.bottom, extents.right, extents.top);
443 glDisable (GL_BLEND);
444 }
445
446 // draw slits
447 glColor3f (1, 1, 1);
448 if (what->total_slits == 0) { // no slits
449 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
450 glRectf (extents.left, extents.bottom, extents.right, extents.top); // outline rect
451 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
452 } else {
453 float startt [] = {extents.left, extents.bottom, extents.left, extents.bottom};
454 float endd [] = {extents.right, extents.top, extents.right, extents.top};
455 float levell [] = {extents.bottom, extents.right, extents.top, extents.left};
456 int typp [] = {slit::HORIZONTAL, slit::VERTICAL, slit::HORIZONTAL, slit::VERTICAL};
457 for (int i = 0; i < rect::nedges; ++i) {
458 if (what->nslits[i]) {
459 draw_slits (startt[i], endd[i], levell[i], typp[i], what->slits[i], slit_drawerr);
460 } else {
461 float li = levell[i];
462 float si = startt[i], ei = endd[i];
463 if (typp[i] == slit::HORIZONTAL) {
464 slit_drawerr.add (si, li);
465 slit_drawerr.add (ei, li);
466 } else {
467 slit_drawerr.add (li, si);
468 slit_drawerr.add (li, ei);
469 }
470 }
471 }
472 slit_drawerr.draw ();
473 }
474 }
475
draw_leaves()476 void mondrian::draw_leaves () {
477 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) {
478 rect* bi = *i;
479 draw_rect (bi);
480 }
481 }
482
draw()483 void mondrian::draw () {
484
485 glMatrixMode (GL_PROJECTION);
486 glLoadIdentity ();
487 glOrtho (win.left, win.right, win.bottom, win.top, -1, 1);
488 glMatrixMode (GL_MODELVIEW);
489 glLoadIdentity ();
490
491 draw_notes ();
492
493 if (label_notes) {
494 tb.draw (); // note labels
495 glColor3f (0.9, 0.9, 1);
496 glVertexPointer (2, GL_FLOAT, 0, mrk);
497 glDrawArrays (GL_LINES, 0, n_mrk); // note markers
498 }
499
500 // draw cursor
501 box<float>& rex = root->extents;
502 if (inbox (rex, win.mousex, win.mousey)) {
503 static const float cc = 0.5f;
504 glColor3f (cc, cc, cc);
505 crsr[0]=rex.left; crsr[1]=win.mousey;
506 crsr[2]=rex.right; crsr[3]=win.mousey;
507 crsr[4]=win.mousex; crsr[5]=rex.bottom;
508 crsr[6]=win.mousex;crsr[7]=rex.top;
509 glVertexPointer (2, GL_FLOAT, 0, crsr);
510 glDrawArrays (GL_LINES, 0, 4);
511 }
512
513 if (draw_slit_cutter) {
514 glColor3f (1, 1, 0);
515 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
516 glRectf (win.mousex - slit::HALF_SIZE, win.mousey - slit::HALF_SIZE, win.mousex + slit::HALF_SIZE, win.mousey + slit::HALF_SIZE);
517 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
518 }
519
520 if (draw__boxes) draw_leaves ();
521 draw_balls ();
522
523 mon_selector.draw (rgn);
524
525 //selector.draw ();
526
527 mark_selected_slits ();
528
529 /*glPointSize (5);
530 glColor3f (0.0, 1.0, 1.0);
531 for (int i = 0, j = marks.size (); i < j; ++i) {
532 point<float>& pi = marks[i];
533 glBegin (GL_POINTS);
534 glVertex2f (pi.x, pi.y);
535 glEnd ();
536 }
537 glPointSize (1);*/
538
539 }
540
calc_visual_params()541 void mondrian::calc_visual_params () {
542 win.calc ();
543 make_notes ();
544 tb.refresh (this);
545 }
546
do_panx(int dir)547 void mondrian::do_panx (int dir) {
548 win.panx (dir);
549 calc_visual_params ();
550 }
551
do_pany(int dir)552 void mondrian::do_pany (int dir) {
553 win.pany (dir);
554 calc_visual_params ();
555 }
556
do_zoom(int dir)557 void mondrian::do_zoom (int dir) {
558 win.zoom (dir);
559 calc_visual_params ();
560 }
561
setup()562 void mondrian::setup () {
563
564 dlog << "*** setting up Mondrian ***" << endl;
565
566 load_settings ();
567 load_boxes_and_balls ();
568
569 if (root == 0) {
570 root = new rect;
571 const int xsize = 800;
572 root->extents (0, 0, xsize, xsize / GOLDEN_RATIO);
573 root->calc_intervals ();
574 poly.radius = root->extents.height / 4.0f;
575 set_note_poly_points (24); cons.clear ();
576 add_leaf (root);
577 }
578
579 poly.delta_radius = 1;
580
581 // setup waveform
582 waved.add (&wave, &wavlis);
583 waved.attach_library (&wav_lib);
584
585 // setup attack curve
586 attacked.add (&attack, &attacklis);
587 attacklis.inst = this;
588 attacked.attach_library (&attack_lib);
589
590 // setup decay curve
591 decayed.add (&decay, &decaylis);
592 decaylis.inst = this;
593 decayed.attach_library (&decay_lib);
594
595 scaleinfo.scl = this;
596
597 dlog << "+++ Mondrian setup complete +++" << endl;
598
599 }
600
get_sibling(rect * R)601 rect* mondrian::get_sibling (rect* R) {
602 rect* P = R->parent;
603 if (P != 0) {
604 if (P->child1 == R)
605 return P->child2;
606 else
607 return P->child1;
608 }
609 return 0;
610 }
611
612
find(rect * R,float x,float y,finding & fnd)613 void mondrian::find (rect* R, float x, float y, finding& fnd) {
614 if (inbox (R->extents, x, y)) {
615 if (R->child1 != 0) {
616 find (R->child1, x, y, fnd);
617 if (fnd.found == 0) find (R->child2, x, y, fnd);
618 } else {
619 fnd.found = R;
620 fnd.sibling = get_sibling (R);
621 }
622 }
623 }
624
make_finding(rect * R)625 finding mondrian::make_finding (rect* R) {
626 finding result;
627 result.found = R;
628 result.sibling = get_sibling (R);
629 return result;
630 }
631
box_under_cursor()632 rect* mondrian::box_under_cursor () {
633 finding result; find (root, win.mousex, win.mousey, result);
634 rect* F = result.found;
635 if (F == 0) {
636 cons << YELLOW << "Sorry cant split because you are outside all boxes!" << eol;
637 return 0;
638 } else return F;
639 }
640
641
find_hit_slit(float x,float y)642 int mondrian::find_hit_slit (float x, float y) {
643 rect* R = 0;
644 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) { // slit can only be on leaves
645 rect* li = *i;
646 box<float> exts = li->extents;
647 exts.resize (gutter, gutter);
648 if (inbox(exts, x, y)) { // finding 1 box is enough
649 R = li;
650 break;
651 }
652 }
653 if (R) {
654 int e = R->extents.get_edge_hit (x, y, gutter2);
655 if (e != edge::NONE) {
656 float v[] = {x, y, x, y};
657 slit* hs = slit_hit (R, e, v[e]); // hit slit
658 if (hs) {
659 push_back (selected_slits, hs);
660 ++num_selected_slits;
661 return 1;
662 }
663 }
664 }
665 return 0;
666 }
667
add_remove_slit(float x,float y,fader * fdr,float sz)668 int mondrian::add_remove_slit (float x, float y, fader* fdr, float sz) {
669
670
671 int result = 0;
672 int boxes_hit = 0;
673 int k = 0;
674
675 // slit can only be on boxes that are leaves
676 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) {
677 rect* li = *i;
678 box<float> lie = li->extents;
679 lie.resize (gutter, gutter);
680 if (inbox(lie, x, y)) {
681 if (++boxes_hit > 2) break; // too many!
682 bxs[k++] = li;
683 }
684 }
685
686 if (boxes_hit == 2) { // slit can only be on 2 leaves
687 slit* hs = slit_hit (bxs, x, y); // did we hit a slit?
688 if (hs == 0) { // no slit hit
689 slit* s = new slit (bxs, x, y, sz, fdr); // so make slit
690 rect** boxes = s->boxes;
691 int* edges = s->edges;
692 if (edge_on_root (root, boxes, edges) == 0) { // balls wont escape
693 // add slit to edges of the 2 leaves
694 int result0 = boxes[0]->add_slit (s, edges[0]);
695 int result1 = boxes[1]->add_slit (s, edges[1]);
696 if (result0 && result1) { // added successfully
697 ++num_slits;
698 slits.push_back (s); // add to global slits
699 } else {
700 // not added so discard
701 remove_slit (s);
702 }
703 } else {
704 // balls will escape playing area so discard
705 remove_slit (s);
706 }
707 } else {
708 remove_slit (hs);
709 }
710 result = 1;
711 }
712 return result;
713 }
714
split_rect(int type,float t,rect * B)715 rect* mondrian::split_rect (int type, float t, rect* B) {
716
717 if (B == 0) {
718 B = box_under_cursor ();
719 if (B == 0) return 0;
720 }
721
722 stop_editing_slit ();
723 stop_editing_edge ();
724
725 box<float>& extents = B->extents;
726 B->split = type;
727 rect* v1 = new rect;
728 rect* v2 = new rect;
729 box<float>& v1e = v1->extents;
730 box<float>& v2e = v2->extents;
731 if (type == split::VERTICAL) {
732 v1e (extents.left, extents.bottom, t, extents.top);
733 v2e (t, extents.bottom, extents.right, extents.top);
734 } else {
735 v1e (extents.left, extents.bottom, extents.right, t);
736 v2e (extents.left, t, extents.right, extents.top);
737 }
738 v1->parent = B;
739 v2->parent = B;
740 B->child1 = v1;
741 B->child2 = v2;
742 v1->calc_intervals ();
743 v2->calc_intervals ();
744 split_balls (B, v1, v2);
745 remove_leaf (B);
746 add_leaf (v1);
747 add_leaf (v2);
748 recreate_slits (B);
749 return B;
750 }
751
752
recreate_slits(rect * R)753 void mondrian::recreate_slits (rect* R) {
754 box<float>& e = R->extents;
755 float fixed_val [rect::nedges] = {e.bottom, e.right, e.top, e.left};
756 list<slit_info> reslits;
757 for (int i = 0; i < rect::nedges; ++i) {
758 list<slit*>& slits = R->slits[i];
759 int ns = R->nslits [i];
760 if (ns) {
761 slit_info sf;
762 float* moving [rect::nedges] = {&sf.x, &sf.y, &sf.x, &sf.y};
763 float* fixed [rect::nedges] = {&sf.y, &sf.x, &sf.y, &sf.x};
764 float* movingi = moving [i];
765 float* fixedi = fixed [i];
766 *fixedi = fixed_val [i];
767 for (slit_iterator si = slits.begin (), sj = slits.end (); si != sj;) {
768 slit* s = *si;
769 if (s->fdr) {
770 s->start = s->anim_start;
771 s->end = s->anim_end;
772 s->calc_mid ();
773 sf.anim = 1;
774 sf.fdr.copy (s->fdr);
775 } else sf.anim = 0;
776 *movingi = s->mid;
777 sf.half_size = s->mid - s->start;
778 reslits.push_back (sf);
779 remove_slit (s);
780 si = slits.begin ();
781 sj = slits.end ();
782 }
783 }
784 }
785
786 for (list<slit_info>::iterator i = reslits.begin (), j = reslits.end(); i != j; ++i) {
787 slit_info& si = *i;
788 if (si.anim)
789 add_remove_slit (si.x, si.y, &si.fdr, si.half_size);
790 else
791 add_remove_slit (si.x, si.y, 0, si.half_size);
792 }
793 }
794
795
add_leaf(rect * L)796 void mondrian::add_leaf (rect* L) {
797 leaves.push_back (L);
798 ++nleaves;
799 }
800
801
remove_leaf(rect * L)802 void mondrian::remove_leaf (rect* L) {
803 erase (leaves, L);
804 --nleaves;
805 }
806
earliest_leaf()807 rect* mondrian::earliest_leaf () {
808 return *(leaves.begin());
809 }
810
latest_leaf()811 rect* mondrian::latest_leaf () {
812 return *(--leaves.end());
813 }
814
balled_leaf()815 rect* mondrian::balled_leaf () {
816 list<ball*>& balls = get_balls (0);
817 int sz = balls.size ();
818 if (sz) {
819 rnd<float> rd (0, balls.size()-1);
820 int r = rd() + 0.5;
821 ball* b = get <list<ball*>, ball*> (balls, r);
822 return b->R;
823 } else return rnd_leaf();
824 }
825
rnd_leaf()826 rect* mondrian::rnd_leaf () {
827 rnd<float> rd (0, nleaves-1);
828 return get< list<rect*>, rect*> (leaves, int(rd()+0.5));
829 }
830
biggest_leaf()831 rect* mondrian::biggest_leaf () {
832 rect* mal = earliest_leaf ();
833 float max_area = mal->get_area ();
834 for (box_iterator i = ++leaves.begin (), j = leaves.end (); i != j; ++i) {
835 rect* li = *i;
836 float li_area = li->get_area ();
837 if (li_area > max_area) {
838 max_area = li_area;
839 mal = li;
840 }
841 }
842 return mal;
843 }
844
delete_rect(const finding & f)845 int mondrian::delete_rect (const finding& f) { // delete found box
846
847 rect* found = f.found;
848 rect* sibling = f.sibling;
849
850 // turn sibling into parent, kill parent
851 rect* parent = found->parent;
852 rect* grand_parent = parent->parent;
853 if (grand_parent) {
854 if (grand_parent->child1 == parent)
855 grand_parent->child1 = sibling;
856 else
857 grand_parent->child2 = sibling;
858 } else root = sibling;
859
860 sibling->extents = parent->extents;
861 sibling->parent = grand_parent;
862 update_children (sibling);
863
864 finding fnd;
865 for (balls_iterator p = found->balls.begin (), q = found->balls.end (); p != q; ++p) { // find new home for balls of found
866 ball* b = *p;
867 find (sibling, b->x, b->y, fnd);
868 b->R = fnd.found;
869 if (b->R == 0) b->R = sibling;
870 b->R->balls.push_back (b);
871 fnd.clear ();
872 }
873
874 delete parent;
875
876 remove_leaf (found);
877 recreate_slits (found);
878 delete found;
879
880 return 1;
881 }
882
delete_current_rect()883 void mondrian::delete_current_rect () { // delete box under cursor
884 finding f; find (root, win.mousex, win.mousey, f);
885 if (bad_rect (f.found)) return;
886 delete_rect (f);
887 }
888
delete_children(rect * _root)889 void mondrian::delete_children (rect* _root) {
890 rect* left = _root->child1;
891 rect* right = _root->child2;
892 if (left) {
893 delete_children (left);
894 delete_children (right);
895 }
896 delete _root;
897 }
898
update_children(rect * R)899 void mondrian::update_children (rect* R) {
900 box<float>& extents = R->extents;
901 R->calc_intervals ();
902 if (R->child1 && R->child2) {
903 box<float>& c1e = R->child1->extents;
904 if (R->split == split::HORIZONTAL) {
905 R->child1->extents (extents.left, extents.bottom, extents.right, c1e.top);
906 R->child2->extents (extents.left, c1e.top, extents.right, extents.top);
907 } else if (R->split == split::VERTICAL) {
908 R->child1->extents (extents.left, extents.bottom, c1e.right, extents.top);
909 R->child2->extents (c1e.right, extents.bottom, extents.right, extents.top);
910 }
911 update_children (R->child1);
912 update_children (R->child2);
913 } else {
914 if (edge != edge::NONE) {
915 if (edge == edge::LEFT || edge == edge::RIGHT) {
916 R->update_slits (edge::BOTTOM, R->extents.left, R->extents.right);
917 R->update_slits (edge::TOP, R->extents.left, R->extents.right);
918 } else {
919 R->update_slits (edge::LEFT, R->extents.bottom, R->extents.top);
920 R->update_slits (edge::RIGHT, R->extents.bottom, R->extents.top);
921 }
922 }
923 }
924 }
925
pick_leaf(int & what)926 rect* mondrian::pick_leaf (int& what) {
927 rect* asr = 0;
928 if (what == rect::RANDOM)
929 asr = rnd_leaf ();
930 else if (what == rect::BIGGEST)
931 asr = biggest_leaf ();
932 else if (what == rect::LATEST)
933 asr = latest_leaf ();
934 else if (what == rect::EARLIEST)
935 asr = earliest_leaf ();
936 else {
937 asr = balled_leaf ();
938 }
939 return asr;
940 }
941
942
bg()943 void mondrian::bg () {
944
945 remove_finished_notes ();
946
947 if (quit) return;
948
949 if (splitting_rects) {
950 for (split_iterator m = lsd.begin (), n = lsd.end (); m != n;) {
951 if (multi_split_rect (*m)) {
952 m = lsd.erase (m);
953 n = lsd.end ();
954 splitting_rects = !(m == n);
955 } else ++m;
956 }
957 } else {
958
959 if (delete_all_rects) {
960 if (nleaves > 1) {
961 rect* pl = pick_leaf (delete_leaf);
962 int good_rect = !bad_rect (pl);
963 if (good_rect) delete_rect ( make_finding (pl) );
964 } else {
965 delete_all_rects = 0;
966 }
967 } else {
968 if (auto_del_rect.active ) {
969 if (auto_del_rect (ui_clk())) {
970 if (!editing_edge && !editing_slit) {
971 rect* adr = pick_leaf (delete_leaf);
972 if (!bad_rect (adr)) delete_rect (make_finding (adr));
973 }
974 }
975 }
976 }
977
978 if (auto_split_rect.active) { // auto split box?
979
980 if (auto_split_rect (ui_clk())) { // reached time to auto split
981
982 // pick box to split
983 rect* asr = pick_leaf (split_leaf);
984
985 int split_orient;
986 if (auto_split_orient == split::BOTH) {
987 rnd<float> rd (split::HORIZONTAL, split::VERTICAL); // horizontal or vertical at random
988 split_orient = rd () + 0.5;
989 } else
990 split_orient = auto_split_orient;
991
992 if (auto_split_at == split::NOTES) { // split at notes of the scale
993 pair<int, int> note_ids;
994 if (get_note_ids (note_ids, asr, split_orient)) {
995 rnd<float> rd (note_ids.first, note_ids.second - 1);
996 int i = rd() + 0.5;
997 split_data sd (i, i + 1, auto_split_at, split_orient, asr);
998 lsd.push_back (sd); // split in bg!
999 splitting_rects = 1;
1000 }
1001 } else { // split at any microtone
1002 float delta;
1003 float low, high;
1004 if (split_orient == split::HORIZONTAL) {
1005 low = asr->extents.bottom;
1006 high = asr->extents.top;
1007 delta = asr->extents.height;
1008 } else {
1009 low = asr->extents.left;
1010 high = asr->extents.right;
1011 delta = asr->extents.width;
1012 }
1013 float _2_min_split_size = 2 * min_split_size;
1014 if (delta > _2_min_split_size) {
1015 rnd<float> rd (min_split_size, max (min_split_size, delta - min_split_size));
1016 float sz = rd ();
1017 int cl = 0;
1018 float pos = low + sz;
1019 cl = clamp (low, pos, high);
1020 if (!cl) {
1021 split_data sd (0, 1, auto_split_at, split_orient, asr);
1022 sd.sz = sz;
1023 lsd.push_back (sd); // split in bg!
1024 splitting_rects = 1;
1025 }
1026 }
1027 }
1028 }
1029 }
1030
1031 }
1032
1033 for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) (*i)->eval_anim ();
1034
1035 for (balls_iterator p = balls.begin (), q = balls.end (); p != q; ++p) {
1036 ball* b = *p;
1037 b->eval_ops ();
1038 b->update ();
1039 }
1040
1041 }
1042
render_audio(float * L,float * R)1043 int mondrian::render_audio (float* L, float* R) {
1044 int ret = 0;
1045 balls_iterator bter = triggering_balls.begin ();
1046 for (note_iterator i = triggered_notes.begin (), j = triggered_notes.end (); i != j; ++i, ++bter) {
1047 triggered_note& ti = *i;
1048 ball* bi = *bter;
1049 if (ti.state != triggered_note::FINISHED) {
1050 ti.eval (L, R, aout.result, aout.vol, aout.samples_per_channel, bi->attack_time, bi->decay_time, _gotomax);
1051 ti.eval (bi->attack_time);
1052 ret += ti.player.mixer.active;
1053 }
1054 }
1055 return ret;
1056 }
1057
remove_finished_notes()1058 void mondrian::remove_finished_notes () {
1059 balls_iterator bter = triggering_balls.begin ();
1060 for (note_iterator i = triggered_notes.begin (); i != triggered_notes.end();) {
1061 triggered_note& ti = *i;
1062 if (ti.state == triggered_note::FINISHED) {
1063 i = triggered_notes.erase (i);
1064 ball* b = *bter; if (--b->num_notes <= 0 && b->del) delete b;
1065 bter = triggering_balls.erase (bter);
1066 --num_triggered_notes;
1067 print_num_triggered_notes ();
1068 } else {
1069 ++i;
1070 ++bter;
1071 }
1072 }
1073 }
1074
get_one_selected_ball()1075 ball* mondrian::get_one_selected_ball () {
1076 if (num_selected_balls == 1) return *selected_balls.begin (); else return 0;
1077 }
1078
change_param(float & param,float value,float & recent)1079 int mondrian::change_param (float& param, float value, float& recent) {
1080 static const float minval = 0.0f;
1081 int atminval = (param == minval);
1082 param += value;
1083 int ret = 1;
1084 if (param < minval) {
1085 param = minval;
1086 if (atminval) ret = 0;
1087 }
1088 recent = param;
1089 return ret;
1090 }
1091
change_attack_time_kb(spinner<float> & s)1092 void mondrian::change_attack_time_kb (spinner<float>& s) {
1093 int n = 0;
1094 list<ball*>& _balls = get_balls ();
1095 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1096 ball* b = *p;
1097 change_param (b->attack_time, s(), ball::recent_attack_time);
1098 sprintf (BUFFER, "Ball %d, attack time = %0.3f secs", ++n, b->attack_time);
1099 cons << BUFFER << eol;
1100 }
1101
1102 }
1103
change_decay_time_kb(spinner<float> & s)1104 void mondrian::change_decay_time_kb (spinner<float>& s) {
1105 list<ball*>& _balls = get_balls ();
1106 int n = 0;
1107 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1108 ball* b = *p;
1109 change_param (b->decay_time, s(), ball::recent_decay_time);
1110 sprintf (BUFFER, "Ball %d, decay time = %0.3f secs", ++n, b->decay_time);
1111 cons << BUFFER << eol;
1112 }
1113 }
1114
draw_balls()1115 void mondrian::draw_balls () {
1116
1117 int num_balls_ = num_balls;
1118 if (new_ball) ++num_balls_;
1119 if (num_balls_ == 0) return;
1120 if (num_balls_ > n_pts) {
1121 if (pts) delete[] pts;
1122 if (pts_d) delete[] pts_d;
1123 if (pts_clr) delete[] pts_clr;
1124 pts = new float [2 * num_balls_];
1125 pts_d = new float [4 * num_balls_];
1126 pts_clr = new float [3 * num_balls_];
1127 n_pts = num_balls_;
1128 }
1129
1130 int i = 0, j = 0, k = 0;
1131 float r, g, cb;
1132
1133 static const int S = 25;
1134 for (balls_iterator p = balls.begin (), q = balls.end (); p != q; ++p) {
1135 ball* b = *p;
1136 if (b->select) {r = 0; g = 1; cb = 0;} else {r = b->r; g = b->g; cb = b->b;}
1137 if (draw_ball.trails) {
1138 glColor3f (r, g, cb);
1139 b->trail.draw ();
1140 }
1141
1142 // position
1143 pts[i++] = b->x;
1144 pts[i++] = b->y;
1145
1146 // color
1147 pts_clr[j++]=r;
1148 pts_clr[j++]=g;
1149 pts_clr[j++]=cb;
1150
1151 // direction
1152 pts_d[k++]=b->x+S*b->vx;
1153 pts_d[k++]=b->y+S*b->vy;
1154 pts_d[k++]=b->x;
1155 pts_d[k++]=b->y;
1156
1157 }
1158
1159 if (new_ball) {
1160 pts[i++]=new_ball->x;
1161 pts[i++]=new_ball->y;
1162 pts_clr[j++]=new_ball->r;
1163 pts_clr[j++]=new_ball->g;
1164 pts_clr[j++]=new_ball->b;
1165 }
1166
1167 if (draw_ball.heading) {
1168 glColor3f (1, 1, 1);
1169 glVertexPointer (2, GL_FLOAT, 0, pts_d);
1170 glDrawArrays (GL_LINES, 0, 2 * num_balls);
1171 }
1172
1173 if (draw_ball.position) {
1174 glPointSize (5);
1175 glEnableClientState (GL_COLOR_ARRAY);
1176 glColorPointer (3, GL_FLOAT, 0, pts_clr);
1177 glVertexPointer (2, GL_FLOAT, 0, pts);
1178 glDrawArrays (GL_POINTS, 0, num_balls_);
1179 glDisableClientState (GL_COLOR_ARRAY);
1180 glPointSize (1);
1181 }
1182
1183 }
1184
draw_notes()1185 void mondrian::draw_notes () {
1186
1187 int n = poly.points;
1188 float xy [2*n];
1189
1190 if (label_hz_vol) tb_hz_vol.clear ();
1191
1192 for (note_iterator i = triggered_notes.begin (), j = triggered_notes.end (); i != j; ++i) {
1193 triggered_note& ti = *i;
1194 float r = poly.radius * ti.volume.now / ti.volume.max;
1195 if (draw__notes) {
1196 for (int i = 0, j = 0; i < n; ++i) {
1197 xy[j++]=ti.x+r*poly.coss[i];
1198 xy[j++]=ti.y+r*poly.sinn[i];
1199 }
1200 if (scope.limit) glColor3f (1.0, 0.1, 0.1); else glColor3f (ti.r, ti.g, ti.b);
1201 glVertexPointer (2, GL_FLOAT, 0, xy);
1202 glDrawArrays (GL_LINE_LOOP, 0, n);
1203 }
1204
1205 if (label_hz_vol) {
1206 xy[0]=ti.x+r*poly.coss[0];
1207 xy[1]=ti.y+r*poly.sinn[0];
1208 float wtx = xy[0] + gutter, wty = xy[1] + gutter;
1209 float clr = ti.volume.now * 1.0 / ti.volume.max;
1210 sprintf (BUFFER, "%0.3f @ %03d%%", ti.start_hz, int(clr * 100.0 + 0.5));
1211 tb_hz_vol.add (text (BUFFER, wtx, wty, ti.r, ti.g, ti.b));
1212 }
1213
1214 }
1215
1216 if (label_hz_vol) {
1217 tb_hz_vol.refresh (this);
1218 tb_hz_vol.draw ();
1219 }
1220 }
1221
split_balls(rect * P,rect * C1,rect * C2)1222 void mondrian::split_balls (rect* P, rect* C1, rect* C2) {
1223 list<ball*>& P_balls = P->balls;
1224 for (balls_iterator p = P_balls.begin (); p != P_balls.end ();) {
1225 ball* b = *p;
1226 if (inbox (C1->extents, b->x, b->y)) {
1227 C1->balls.push_back (b);
1228 b->R = C1;
1229 } else {
1230 C2->balls.push_back (b);
1231 b->R = C2;
1232 }
1233 p = P_balls.erase (p);
1234 }
1235 }
1236
change_speed(spinner<float> & s,float d)1237 void mondrian::change_speed (spinner<float>& s, float d) {
1238 list<ball*>& _balls = get_balls ();
1239 int n = 0;
1240 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1241 ball* b = *p;
1242
1243 float& bv = b->V;
1244 bv += s(d);
1245
1246 if (bv <= 0) bv = 0.0f;
1247
1248 /*float& maxx = b->op_speed.max;
1249 float omaxx = maxx;
1250 maxx = max (maxx, bv);
1251 if ((num_selected_balls == 1) && (maxx != omaxx)) MENU.sp_max_speed.set_value (maxx);*/
1252
1253 sprintf (BUFFER, "Ball %d, speed = %0.3f", ++n, bv);
1254
1255 cons << YELLOW << BUFFER << eol;
1256
1257 }
1258 }
1259
toggle_slit_anim()1260 void mondrian::toggle_slit_anim () {
1261 int hs = 0;
1262 if (num_selected_slits == 0) hs = find_hit_slit (win.mousex, win.mousey);
1263 for (slit_iterator s = selected_slits.begin (), t = selected_slits.end (); s != t; ++s) {
1264 slit* si = *s;
1265 si->toggle_anim ();
1266 }
1267 if (hs) clear_selected<slit> (selected_slits, num_selected_slits, 0);
1268 }
1269
select_balls(const box<float> & rgn)1270 void mondrian::select_balls (const box<float>& rgn) {
1271 browse.clear ();
1272 if (SHIFT || CTRL) ; else clear_selected<ball> (selected_balls, num_selected_balls);
1273 for (balls_iterator p = balls.begin (), q = balls.end (); p != q; ++p) {
1274 ball* b = *p;
1275 if (inbox (rgn, b->x, b->y)) select_using_modifiers<ball> (b, CTRL, selected_balls, num_selected_balls);
1276 }
1277 after_selection ();
1278 }
1279
after_selection()1280 void mondrian::after_selection () {
1281 if (sel_tar == SELECT_BALLS) {
1282 if (num_selected_balls) {
1283 cons << GREEN << "Selected " << num_selected_balls << " balls" << eol;
1284 if (num_selected_balls == 1) {
1285 ball* bsel = *selected_balls.begin();
1286 bsel->print ();
1287 MENU.set_ball_ops (bsel);
1288 if (browse.n) {
1289 sprintf (BUFFER, " Ball %d of %d", browse.which+1, browse.n);
1290 MENU.ol_browse_balls.set_text (BUFFER);
1291 }
1292 } else {
1293 if (browse.n == 0) {
1294 browse.balls.resize (num_selected_balls);
1295 copy (selected_balls.begin (), selected_balls.end (), browse.balls.begin ());
1296 browse.n = browse.balls.size ();
1297 browse.last = browse.n - 1;
1298 browse.which = -1;
1299 }
1300 MENU.ol_browse_balls.set_text (" Click arrow to load ball");
1301 }
1302 } else {
1303 cons << RED << "No balls selected" << eol;
1304 MENU.clear_ball_ops ();
1305 }
1306 } else {
1307 if (num_selected_slits)
1308 cons << GREEN << "Selected " << num_selected_slits << " slits" << eol;
1309 else
1310 cons << RED << "No slits selected" << eol;
1311 }
1312 }
1313
1314
select_box_balls()1315 void mondrian::select_box_balls () {
1316 finding f; find (root, win.mousex, win.mousey, f);
1317 rect* R = f.found;
1318 if (R) {
1319 list<ball*>& b_balls = R->balls;
1320 browse.clear ();
1321 if (SHIFT || CTRL); else clear_selected<ball> (selected_balls, num_selected_balls);
1322 for (balls_iterator p = b_balls.begin (), q = b_balls.end (); p != q; ++p) select_using_modifiers<ball> (*p, CTRL, selected_balls, num_selected_balls);
1323 after_selection ();
1324 }
1325 }
1326
select_box_slits()1327 void mondrian::select_box_slits () {
1328 finding f; find (root, win.mousex, win.mousey, f);
1329 rect* R = f.found;
1330 if (R) {
1331 if (SHIFT || CTRL); else clear_selected<slit> (selected_slits, num_selected_slits);
1332 for (int i = 0; i < 4; ++i) {
1333 list<slit*>& slits = R->slits[i];
1334 for (slit_iterator s = slits.begin (), t = slits.end (); s != t; ++s) select_using_modifiers<slit> (*s, CTRL, selected_slits, num_selected_slits);
1335 }
1336 after_selection ();
1337 }
1338 }
1339
delete_ball(ball * b)1340 void mondrian::delete_ball (ball* b) {
1341 if (::erase (balls, b)) --num_balls;
1342 if (::erase (selected_balls, b)) --num_selected_balls;
1343 if (::erase (browse.balls, b)) {
1344 --browse.n;
1345 if (browse.n) {
1346 browse.last = browse.n - 1;
1347 MENU.ol_browse_balls.set_text (" Click arrow to load ball");
1348 } else {
1349 browse.last = 0;
1350 }
1351 }
1352
1353 b->R->erase (b);
1354 if (b->num_notes == 0) delete b; else b->del = 1;
1355 }
1356
delete_selected_balls()1357 void mondrian::delete_selected_balls () {
1358 int nb = num_balls;
1359 while (num_selected_balls) delete_ball (*selected_balls.begin());
1360 cons << YELLOW << "Deleted " << (nb - num_balls) << " balls" << eol;
1361 }
1362
1363
locate_ball(ball * b)1364 void mondrian::locate_ball (ball* b) {
1365 if (!inbox (b->R->extents, b->x, b->y)) {
1366 locator:
1367 finding fnd; find (root, b->x, b->y, fnd);
1368 rect* nbr = fnd.found;
1369 if (nbr) {
1370 b->R->erase (b);
1371 b->R = nbr;
1372 b->R->balls.push_back (b);
1373 } else {
1374 clamp<float>(root->extents.left, b->x, root->extents.right);
1375 clamp<float>(root->extents.bottom, b->y, root->extents.top);
1376 goto locator;
1377 }
1378 }
1379 }
1380
move_balls(float dx,float dy)1381 void mondrian::move_balls (float dx, float dy) {
1382 for (balls_iterator p = selected_balls.begin (), q = selected_balls.end (); p != q; ++p) {
1383 ball* b = *p;
1384 b->x += dx;
1385 b->y += dy;
1386 locate_ball (b);
1387 }
1388 }
1389
toggle_flag(int & flag,const string & poz,const string & neg)1390 void mondrian::toggle_flag (int& flag, const string& poz, const string& neg) {
1391 flag = !flag;
1392 if (flag)
1393 cons.set_cmd_line (poz, GREEN);
1394 else {
1395 cons.set_cmd_line ("");
1396 cons << YELLOW << neg << eol;
1397 }
1398 }
1399
do_add_balls(int type)1400 void mondrian::do_add_balls (int type) {
1401 adding_balls = 1;
1402 added_ball_type = type;
1403 if (new_ball) new_ball->set_type (added_ball_type);
1404 string bt (ball::types_str[added_ball_type]);
1405 stringstream ss; ss << "Click, drag and release to launch " << bt << ". ESC to stop.";
1406 cons.set_cmd_line (ss.str(), GREEN);
1407 MENU.ol_ball_types.set_text (bt);
1408 }
1409
do_move_balls()1410 void mondrian::do_move_balls () {
1411 if (stop_moving_balls()) return;
1412 if (num_selected_balls) {
1413 stop_adding_balls ();
1414 toggle_flag (moving_balls, "Just move your mouse to move the balls. ESC to stop.");
1415 }
1416 else
1417 cons << YELLOW << "Please select some balls!" << eol;
1418 }
1419
delete_all_balls()1420 void mondrian::delete_all_balls () {
1421 select_all<ball> (balls, selected_balls, num_selected_balls);
1422 delete_selected_balls ();
1423 }
1424
make_notes()1425 void mondrian::make_notes () {
1426 vector<string> notes;
1427 extern int NOTATION;
1428 extern int NUM_INTERVALS;
1429 extern const char* WESTERN_FLAT [];
1430 extern vector<string> INTERVAL_NAMES;
1431 extern vector<float> INTERVAL_VALUES;
1432 extern map<string,string> INT2IND;
1433 int western = scaleinfo.western;
1434 if (NOTATION == WESTERN) {
1435 for (int i = 0; i < NUM_INTERVALS; ++i) notes.push_back (WESTERN_FLAT[(western + i) % 12]);
1436 } else if (NOTATION == NUMERIC) {
1437 for (int i = 0; i < NUM_INTERVALS; ++i) notes.push_back (INTERVAL_NAMES[i]);
1438 } else {
1439 for (int i = 0; i < NUM_INTERVALS; ++i) notes.push_back (INT2IND[INTERVAL_NAMES[i]]);
1440 }
1441 int lh = line_height, lh1 = 2 * lh, mcw = fnt.charwidth.max;
1442 box<float>& br = root->extents;
1443 float x = br.left, y1 = br.bottom - lh1, y2 = br.top + lh;
1444 int ks = 10, ksx = ks + 7;
1445 float y = br.bottom, x1 = br.left - ksx - 2 * mcw, x2 = br.right + ks + mcw;
1446
1447 static const int nsides = 4, verts_per_mark = 2;
1448 int _n_mrk = NUM_INTERVALS * nsides * verts_per_mark;
1449 if (_n_mrk > n_mrk) {
1450 if (mrk) delete[] mrk;
1451 n_mrk = _n_mrk;
1452 mrk = new float [2 * n_mrk];
1453 }
1454 int k = 0;
1455 tb.clear ();
1456 for (int i = 0; i < NUM_INTERVALS; ++i) {
1457 float iv = INTERVAL_VALUES[i] - 1;
1458 float xn = x + iv * br.width;
1459 float yn = y + iv * br.height;
1460 const string& ni = notes[i];
1461 mrk[k++]=xn;
1462 mrk[k++]=br.bottom;
1463 mrk[k++]=xn;
1464 mrk[k++]=br.bottom-ks;
1465 mrk[k++]=br.right;
1466 mrk[k++]=yn;
1467 mrk[k++]=br.right+ks;
1468 mrk[k++]=yn;
1469 mrk[k++]=xn;
1470 mrk[k++]=br.top;
1471 mrk[k++]=xn;
1472 mrk[k++]=br.top+ks;
1473 mrk[k++]=br.left;
1474 mrk[k++]=yn;
1475 mrk[k++]=br.left-ks;
1476 mrk[k++]=yn;
1477 tb.add (text (ni, xn, y1));
1478 yn -= fnt.lift;
1479 tb.add (text (ni, x1, yn));
1480 tb.add (text (ni, x2, yn));
1481 tb.add (text (ni, xn, y1));
1482 tb.add (text (ni, xn, y2));
1483 }
1484 }
1485
1486
save_boxes(ofstream & f,rect * R,string & id)1487 void mondrian::save_boxes (ofstream& f, rect* R, string& id) {
1488 R->id = id;
1489 rect* child1 = R->child1;
1490 rect* child2 = R->child2;
1491 box<float>& e = R->extents;
1492 rect* P = R->parent;
1493 string c1 ("-"), c2 ("-");
1494 if (child1 != 0) {
1495 string L (id + 'L'), R(id + 'R');
1496 save_boxes (f, child1, L);
1497 save_boxes (f, child2, R);
1498 c1 = child1->id;
1499 c2 = child2->id;
1500 }
1501 f << "box ";
1502 if (P) f << P->id; else f << "0";
1503 f << spc << R->id << spc << e.left << spc << e.bottom << spc << e.right << spc << e.top << spc << R->split << spc << R->r << spc << R->g << spc << R->b << spc << c1 << spc << c2 << spc;
1504 int leaf = R->is_leaf ();
1505 f << " leaf " << leaf << spc;
1506 if (leaf) { // only leaf can have slits
1507 int total_slits = R->total_slits;
1508 f << "slits " << total_slits << spc;
1509 // box can be leaf and not have any slits
1510 if (total_slits) { // this leaf has slits
1511 for (int i = 0; i < rect::nedges; ++i) {
1512 int& nse = R->nslits[i];
1513 f << nse << spc;
1514 // not all of the leaf's edges need have slits
1515 if (nse) { // this edge has slits
1516 list<slit*>& si = R->slits[i];
1517 for (slit_iterator p = si.begin (), q = si.end (); p != q; ++p) {
1518 f << get_index_of_slit (*p) << spc;
1519 }
1520 }
1521 }
1522 }
1523 }
1524 f << endl;
1525 }
1526
1527
get_box_from_disk(list<box_from_disk_t> & boxes,const string & id)1528 box_from_disk_t mondrian::get_box_from_disk (list<box_from_disk_t>& boxes, const string& id) {
1529 for (box_from_disk_iterator p = boxes.begin (), q = boxes.end (); p != q; ++p) {
1530 box_from_disk_t& rp = *p;
1531 if (rp.R->id == id) {
1532 return rp;
1533 }
1534 }
1535 return box_from_disk_t ();
1536 }
1537
load_boxes_and_balls()1538 void mondrian::load_boxes_and_balls () {
1539 list<box_from_disk_t> boxes;
1540 box_from_disk_t box_from_disk;
1541 string fname ("mondrian.data");
1542 ifstream f ((user_data_dir + fname).c_str (), ios::in);
1543 if (!f) {
1544 dlog << "!!! Failed loading boxes & balls from file: " << fname << " !!!" << endl;
1545 return;
1546 }
1547 while (!f.eof()) {
1548 string what, ignore;
1549 f >> what;
1550 if (what == "box") { // load box
1551 rect *R = new rect;
1552 box_from_disk.R = R;
1553 f >> box_from_disk.parent;
1554 f >> R->id;
1555 float l, b, r, t;
1556 f >> l >> b >> r >> t;
1557 R->extents (l, b, r, t);
1558 f >> R->split;
1559 f >> R->r >> R->g >> R->b;
1560 f >> box_from_disk.child1 >> box_from_disk.child2;
1561 int is_leaf; f >> ignore >> is_leaf;
1562 if (is_leaf) {
1563 add_leaf (R);
1564 f >> ignore >> R->total_slits;
1565 if (R->total_slits) { // can have slits
1566 for (int i = 0; i < rect::nedges; ++i) {
1567 list<slit*>& ls = R->slits [i]; // slits on edge
1568 int& nse = R->nslits [i]; // number of slits on edge
1569 f >> nse;
1570 if (nse) {
1571 for (int p = 0; p < nse; ++p) {
1572 int ix; f >> ix; // get slit index
1573 ls.push_back ((slit *) ix); // will resolve to slit* after slits are loaded
1574 }
1575 }
1576 }
1577 }
1578 }
1579 boxes.push_back (box_from_disk);
1580 if (box_from_disk.parent == "0") root = R;
1581 } else if (what == "ball") {
1582
1583 ball* b = new ball;
1584 f >> b->x >> b->y >> b->V >> b->vx >> b->vy; b->set_velocity (b->V * b->vx, b->V * b->vy);
1585 string rid; f >> rid >> b->frozen >> b->pitch_mult >> b->mod >> b->r >> b->g >> b->b >> b->attack_time >> b->decay_time;
1586 int t; f >> t; b->trail.total = t; trail_t::alloc (t);
1587 f >> b->auto_rotate >> b->dtheta >> b->type >> b->vol_mult >> b->trig_what;
1588
1589 float minn, maxx;
1590 f >> b->op_turn.alarm.active >> b->op_turn.alarm.triggert;
1591 f >> minn >> maxx; b->op_turn.rd.set (minn, maxx);
1592
1593 f >> b->op_turn.vx >> b->op_turn.vy >> b->op_turn.angle;
1594 float turn_alpha; f >> turn_alpha;
1595
1596 f >> b->op_speed.alarm.active >> b->op_speed.alarm.triggert;
1597 f >> minn >> maxx; b->op_speed.rd.set (minn, maxx);
1598 f >> b->op_speed.max;
1599 f >> b->op_speed.start >> b->op_speed.delta;
1600 float speed_alpha; f >> speed_alpha;
1601
1602
1603 f >> b->op_teleport.alarm.active >> b->op_teleport.alarm.triggert;
1604 f >> b->op_teleport.radius;
1605
1606 f >> b->op_clone.alarm.active >> b->op_clone.alarm.triggert;
1607 f >> b->op_clone.n >> b->op_clone.max >> b->op_clone.offset >> b->op_clone.clone_can_clone;
1608
1609 f >> b->op_transform.alarm.active >> b->op_transform.alarm.triggert;
1610
1611 ball_op* bops [] = {&b->op_turn, &b->op_speed, &b->op_teleport, &b->op_clone, &b->op_transform};
1612 for (int i = 0; i < ball_op::NUM_OPS; ++i) {
1613 ball_op* bopi = bops[i];
1614 if (bopi->alarm.active) bopi->alarm.start ();
1615 }
1616
1617 b->op_turn.alarm.startt += (turn_alpha * b->op_turn.alarm.triggert);
1618 b->op_speed.alarm.startt += (speed_alpha * b->op_speed.alarm.triggert);
1619
1620 rect* R = get_box_from_disk (boxes, rid).R;
1621 b->R = R;
1622 R->balls.push_back (b);
1623 balls.push_back (b);
1624 ++num_balls;
1625 } else if (what == "rules") {
1626 for (int i = 0; i < 3; ++i) f >> Transform::rules[i];
1627 } else if (what == "poly") {
1628 f >> ignore >> poly.radius >> ignore >> poly.points;
1629 set_note_poly_points (poly.points); cons.clear ();
1630 } else if (what == "slits") {
1631 load_slits (f, boxes);
1632 } else if (what == "max_balls") {
1633 f >> Clone::max_balls;
1634 } else break;
1635 }
1636
1637 for (box_from_disk_iterator i = boxes.begin (), j = boxes.end (); i != j; ++i) {
1638 box_from_disk_t& ri = *i;
1639 rect* R = ri.R;
1640 rect* P = get_box_from_disk (boxes, ri.parent).R;
1641 rect* C1 = get_box_from_disk (boxes, ri.child1).R;
1642 rect* C2 = get_box_from_disk (boxes, ri.child2).R;
1643 R->parent = P;
1644 R->child1 = C1;
1645 R->child2 = C2;
1646 R->calc_intervals ();
1647 }
1648
1649 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) {
1650 rect* R = *i;
1651 if (R->total_slits) {
1652 for (int p = 0; p < rect::nedges; ++p) {
1653 list<slit*>& ls = R->slits[p];
1654 for (slit_iterator r = ls.begin (), s = ls.end (); r != s; ++r) {
1655 int ix = (uintptr_t) *r;
1656 *r = get_slit_from_index (ix);
1657 }
1658 }
1659 }
1660 }
1661
1662 }
1663
save_balls(ofstream & f)1664 void mondrian::save_balls (ofstream& f) {
1665 f << "max_balls " << Clone::max_balls << endl;
1666 for (balls_iterator i = balls.begin (), j = balls.end (); i != j; ++i) {
1667 ball* pb = *i;
1668 ball& b = *pb;
1669 f << "ball " << b.x << spc << b.y << spc << b.V << spc << b.vx << spc << b.vy << spc << b.R->id << spc << b.frozen << spc << b.pitch_mult << spc << b.mod << spc << b.r << spc << b.g << spc << b.b << spc << b.attack_time << spc << b.decay_time << spc << b.trail.total << spc << b.auto_rotate << spc << b.dtheta << spc << b.type << spc << b.vol_mult << spc << b.trig_what << spc << b.op_turn.alarm.active << spc << b.op_turn.alarm.triggert << spc << b.op_turn.rd.min << spc << b.op_turn.rd.max << spc << b.op_turn.vx << spc << b.op_turn.vy << spc << b.op_turn.angle << spc << b.op_turn.alarm () << spc << b.op_speed.alarm.active << spc << b.op_speed.alarm.triggert << spc << b.op_speed.rd.min << spc << b.op_speed.rd.max << spc << b.op_speed.max << spc << b.op_speed.start << spc << b.op_speed.delta << spc << b.op_speed.alarm () << spc << b.op_teleport.alarm.active << spc << b.op_teleport.alarm.triggert << spc << b.op_teleport.radius << spc << b.op_clone.alarm.active << spc << b.op_clone.alarm.triggert << spc << b.op_clone.n << spc << b.op_clone.max << spc << b.op_clone.offset << spc << b.op_clone.clone_can_clone << spc << b.op_transform.alarm.active << spc << b.op_transform.alarm.triggert << endl;
1670 }
1671
1672 f << "rules ";
1673 for (int i = 0; i < 3; ++i) f << Transform::rules[i] << spc;
1674 f << endl;
1675
1676 }
1677
save_slits(ofstream & f)1678 void mondrian::save_slits (ofstream& f) {
1679 f << "slits " << num_slits << endl;
1680 for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) {
1681 slit* si = *i;
1682 for (int i = 0; i < 2; ++i) {
1683 rect* ri = si->boxes[i];
1684 int ei = si->edges[i];
1685 f << ri->id << spc << ei << spc; // nb: call after save_boxes for proper rect id
1686 }
1687 int _fdr = 0;
1688 if (si->fdr) {
1689 si->start = si->anim_start;
1690 si->end = si->anim_end;
1691 _fdr = 1;
1692 }
1693 f << si->type << spc << si->start << spc << si->end << spc << si->mid << spc;
1694
1695 if (_fdr) {
1696 f << _fdr << spc;
1697 si->fdr->save (f);
1698 } else {
1699 f << _fdr;
1700 }
1701 f << endl;
1702 }
1703 for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) delete *i; // free mem of all slits
1704 }
1705
load_slits(ifstream & f,list<box_from_disk_t> & boxes)1706 void mondrian::load_slits (ifstream& f, list<box_from_disk_t>& boxes) {
1707 f >> num_slits;
1708 string r0, r1;
1709 for (int i = 0; i < num_slits; ++i) {
1710 slit* s = new slit;
1711 f >> r0 >> s->edges[0] >> r1 >> s->edges[1];
1712 s->boxes[0] = get_box_from_disk (boxes, r0).R;
1713 s->boxes[1] = get_box_from_disk (boxes, r1).R;
1714 f >> s->type >> s->start >> s->end >> s->mid;
1715 int fdr_exists; f >> fdr_exists;
1716 if (fdr_exists) {
1717 s->toggle_anim ();
1718 s->fdr->load (f);
1719 }
1720 slits.push_back (s);
1721 }
1722 }
1723
toggle_balls_type(int T)1724 void mondrian::toggle_balls_type (int T) {
1725 static const char* names [] = {" bouncers ", " wreckers ", " healers "};
1726 if (num_selected_balls) {
1727 list<ball*>& _balls = get_balls ();
1728 int t = 0, b = 0;
1729 int Tt;
1730 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1731 ball* pb = *p;
1732 if (pb->type == T) {
1733 Tt = ball::BOUNCER;
1734 ++b;
1735 }
1736 else {
1737 Tt = T;
1738 ++t;
1739 }
1740 pb->set_type (Tt);
1741 }
1742 cons << GREEN << "Made " << t << names[T] << "and " << b << names[0] << eol;
1743 } else cons << YELLOW << "Please select some balls!" << eol;
1744 }
1745
modulate_balls(int w)1746 int mondrian::modulate_balls (int w) {
1747 if (num_selected_balls) {
1748 list<ball*>& _balls = get_balls ();
1749 int b = 0;
1750 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1751 ball* pb = *p;
1752 pb->pitch_mult *= pow (octave_shift.sol.lasty, w);
1753 ball::recent_pitch_mult = pb->pitch_mult;
1754 sprintf (BUFFER, "Ball %d, pitch_multiplier = %0.3f", ++b, pb->pitch_mult);
1755 cons << BUFFER << eol;
1756 pb->mod += w;
1757 pb->color_using_modulation ();
1758 }
1759 }
1760 return num_selected_balls;
1761 }
1762
1763 /*void mondrian::rotate_velocity (spinner<int>& s) {
1764 list<ball*>& _balls = get_balls ();
1765 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1766 ball* pb = *p;
1767 pb->rotate_velocity (dir);
1768 }
1769 }*/
1770
rotate_velocity(int dir)1771 void mondrian::rotate_velocity (int dir) {
1772 list<ball*>& _balls = get_balls ();
1773 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1774 ball* pb = *p;
1775 pb->rotate_velocity (dir);
1776 }
1777 }
1778
change_ball_dtheta(int dir)1779 void mondrian::change_ball_dtheta (int dir) {
1780 int n = 0;
1781 list<ball*>& _balls = get_balls ();
1782 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1783 ball* pb = *p;
1784 pb->dtheta += (dir * PI_BY_180);
1785 if (pb->dtheta <= 0) pb->dtheta = 0;
1786 sprintf (BUFFER, "Ball %d, delta rotate velocity = %0.3f", ++n, pb->dtheta);
1787 cons << BUFFER << eol;
1788 }
1789 }
1790
change_trail_size(spinner<int> & s)1791 void mondrian::change_trail_size (spinner<int>& s) {
1792 int n = 0;
1793 list<ball*>& _balls = get_balls ();
1794 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1795 ball* pb = *p;
1796 pb->trail.change (s());
1797 cons << YELLOW << "Ball " << ++n << ", trail points = " << pb->trail.total << eol;
1798 }
1799 }
1800
set_note_poly_points(int p)1801 int mondrian::set_note_poly_points (int p) {
1802 int ret = 1;
1803 poly.points = p;
1804 if (poly.points < 2) {
1805 poly.points = 2;
1806 ret = 0;
1807 }
1808 poly.coss.resize (poly.points);
1809 poly.sinn.resize (poly.points);
1810 int n = poly.points;
1811 extern const float TWO_PI;
1812 float dtheta = TWO_PI / n;
1813 float theta = TWO_PI / 4.0f;
1814 for (int i = 0; i < n; ++i) {
1815 poly.coss[i] = cos(theta);
1816 poly.sinn[i] = sin(theta);
1817 theta += dtheta;
1818 }
1819 cons << YELLOW << "Note Polygon points = " << poly.points << eol;
1820 return ret;
1821 }
1822
set_note_poly_radius(float r)1823 int mondrian::set_note_poly_radius (float r) {
1824 int ret = 1;
1825 poly.radius = r;
1826 if (poly.radius < 0) {
1827 poly.radius = 0;
1828 ret = 0;
1829 }
1830 sprintf (BUFFER, "Note polygon radius = %0.3f", poly.radius);
1831 cons << YELLOW << BUFFER << eol;
1832 return ret;
1833 }
1834
flip_velocity()1835 void mondrian::flip_velocity () {
1836 list<ball*>& _balls = get_balls ();
1837 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1838 ball* pb = *p;
1839 pb->vx = -pb->vx;
1840 pb->vy = -pb->vy;
1841 pb->calc_velocity_slope ();
1842 if (pb->auto_rotate) {
1843 pb->auto_rotate = -pb->auto_rotate;
1844 rotate_velocity (pb->auto_rotate);
1845 }
1846 }
1847 }
1848
set_auto_rotate(int ar)1849 void mondrian::set_auto_rotate (int ar) {
1850 list<ball*>& _balls = get_balls ();
1851 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) (*p)->auto_rotate = ar;
1852 }
1853
toggle_auto_rotate(int ar)1854 void mondrian::toggle_auto_rotate (int ar) {
1855 list<ball*>& _balls = get_balls ();
1856 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
1857 ball* pb = *p;
1858 if (pb->auto_rotate) pb->auto_rotate = 0; else pb->auto_rotate = ar;
1859 }
1860 }
1861
tonic_changed()1862 void mondrian::tonic_changed () {calc_visual_params ();}
scale_loaded()1863 void mondrian::scale_loaded () {}
scale_changed()1864 void mondrian::scale_changed () {}
1865
remove_slit(slit * s)1866 void mondrian::remove_slit (slit* s) {
1867
1868 for (int i = 0; i < 2; ++i) { // slit is in 2 boxes
1869 rect* ri = s->boxes[i]; // box
1870 int ei = s->edges[i]; // edge
1871 int& nse = ri->nslits[ei]; // num slits on edge
1872 list<slit*>& si = ri->slits[ei]; // slits of edge
1873 if (erase (si, s)) { // erase slit
1874 --nse;
1875 --ri->total_slits;
1876 }
1877 }
1878
1879 if (s == slit_lip.slitt) {
1880 if (editing_slit) toggle_flag (editing_slit, "", "Stopped editing deleted slit");
1881 slit_lip.clear ();
1882 }
1883
1884 if (erase (slits, s)) --num_slits; // erase from global slits list
1885 if (erase (selected_slits, s)) --num_selected_slits; // erase from selected slits list
1886
1887 delete s; // free mem
1888 s = 0;
1889 }
1890
try_slitting()1891 int mondrian::try_slitting () {
1892 if (slitting == NOTHING) return 0;
1893 else {
1894 add_remove_slit (win.mousex, win.mousey);
1895 return mon_selector.abort ();
1896 }
1897 return 0;
1898 }
1899
stop_adding_balls()1900 int mondrian::stop_adding_balls () {
1901 if (adding_balls) {
1902 stringstream ss; ss << "Stopped adding " << ball::types_str [added_ball_type];
1903 toggle_flag (adding_balls, "", ss.str());
1904 started_making_ball = 0;
1905 if (new_ball) delete new_ball;
1906 new_ball = 0;
1907 return 1;
1908 }
1909 return 0;
1910 }
1911
stop_moving_balls()1912 int mondrian::stop_moving_balls () {
1913 if (moving_balls) {
1914 toggle_flag (moving_balls, "", "Stopped moving balls");
1915 mon_selector.abort ();
1916 return 1;
1917 }
1918 return 0;
1919 }
1920
1921
stop_slitting()1922 int mondrian::stop_slitting () {
1923 int ret = draw_slit_cutter;
1924 if (slitting) {
1925 toggle_flag (slitting, "", "Stopped slitting");
1926 ret = 1;
1927 }
1928 draw_slit_cutter = 0;
1929 return ret;
1930 }
1931
stop_editing_slit()1932 int mondrian::stop_editing_slit () {
1933 if (editing_slit) {
1934 toggle_flag (editing_slit, "", "Stopped editing slit.");
1935 if (slit_lip.slitt->is_too_small()) {
1936 cons << YELLOW << "Closed slit because it was too small" << eol;
1937 remove_slit (slit_lip.slitt);
1938 }
1939 mon_selector.abort();
1940 return 1;
1941 }
1942 return 0;
1943 }
1944
stop_editing_edge()1945 int mondrian::stop_editing_edge () {
1946 if (editing_edge) {
1947 hit = 0;
1948 edge = edge::NONE;
1949 toggle_flag (editing_edge, "", "Stopped editing edge.");
1950 mon_selector.abort();
1951 return 1;
1952 }
1953 return 0;
1954 }
1955
stop_doing_stuff()1956 int mondrian::stop_doing_stuff () {
1957 int result = 0;
1958 result |= stop_adding_balls ();
1959 result |= stop_moving_balls ();
1960 result |= stop_slitting ();
1961 result |= stop_editing_slit ();
1962 result |= stop_editing_edge ();
1963 return result;
1964 }
1965
select_type(int t)1966 void mondrian::select_type (int t) {
1967 browse.clear ();
1968 clear_selected<ball> (selected_balls, num_selected_balls);
1969 for (balls_iterator p = balls.begin (), q = balls.end(); p != q; ++p) {
1970 ball* b = *p;
1971 if (b->type == t) {
1972 b->select = 1;
1973 selected_balls.push_back (b);
1974 ++num_selected_balls;
1975 }
1976 }
1977 after_selection ();
1978 }
1979
switch_balls_type()1980 void mondrian::switch_balls_type () {
1981 // all balls: wreckers < > healers
1982 for (balls_iterator p = balls.begin (), q = balls.end(); p != q; ++p) {
1983 ball* b = *p;
1984 if (b->type != ball::BOUNCER) {
1985 if (b->type == ball::WRECKER)
1986 b->set_type (ball::HEALER);
1987 else
1988 b->set_type (ball::WRECKER);
1989 }
1990 }
1991 }
1992
start_slitting()1993 void mondrian::start_slitting () {
1994 if (slitting) {
1995 stop_slitting ();
1996 return;
1997 }
1998 cons.set_cmd_line ("Click on edge of a box to add or remove slit. ESC to stop.", GREEN);
1999 draw_slit_cutter = slitting = JUST_SLIT;
2000 }
2001
change_slit_size(spinner<float> & s)2002 void mondrian::change_slit_size (spinner<float>& s) {
2003 slit::HALF_SIZE += s();
2004 if (slit::HALF_SIZE < slit::MIN_HALF_SIZE) slit::HALF_SIZE = slit::MIN_HALF_SIZE;
2005 draw_slit_cutter = 1;
2006 cons << GREEN << "Default slit size = " << slit::HALF_SIZE << eol;
2007 }
2008
change_slit_anim_time(spinner<float> & sp)2009 void mondrian::change_slit_anim_time (spinner<float>& sp) {
2010 int hs = 0;
2011 if (num_selected_slits == 0) hs = find_hit_slit (win.mousex, win.mousey);
2012 int i = 0;
2013 for (slit_iterator s = selected_slits.begin (), t = selected_slits.end (); s != t; ++s) {
2014 slit* S = *s;
2015 if (S->fdr) {
2016 double& dt = S->fdr->delta_time;
2017 dt += sp();
2018 if (dt < 0) dt = 0;
2019 S->animt = dt;
2020 sprintf (BUFFER, "Slit %d, open|close time = %0.3f", ++i, dt);
2021 cons << GREEN << BUFFER << eol;
2022 } else S->toggle_anim ();
2023 }
2024 if (hs) clear_selected<slit> (selected_slits, num_selected_slits, 0);
2025 }
2026
remove_slits(rect * R)2027 void mondrian::remove_slits (rect* R) {
2028 if (R->total_slits) {
2029 for (int e = 0; e < rect::nedges; ++e) remove_slits_on_edge (R, e);
2030 }
2031 }
2032
remove_slits_on_edge(rect * R,int e)2033 void mondrian::remove_slits_on_edge (rect* R, int e) {
2034 int nse = R->nslits [e];
2035 if (nse) {
2036 list<slit*>& slits = R->slits[e];
2037 while (slits.begin () != slits.end ()) {
2038 slit* sf = slits.front ();
2039 remove_slit (sf);
2040 }
2041 }
2042 }
2043
remove_slits_on_current_edge()2044 void mondrian::remove_slits_on_current_edge () {
2045 rect* hit = 0;
2046 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) {
2047 rect* li = *i;
2048 if (li->total_slits && inbox (li->extents, win.mousex, win.mousey)) {
2049 hit = li;
2050 box<float>& bf = hit->extents;
2051 edge = bf.get_edge_hit (win.mousex, win.mousey, gutter2); // find edge hit
2052 if (edge != edge::NONE) {
2053 remove_slits_on_edge (hit, edge); // remove slits
2054 return;
2055 } else {
2056 cons << YELLOW << "Please get on an edge of this box to remove its slits" << eol;
2057 return;
2058 }
2059 }
2060 }
2061 cons << YELLOW << "Please get on an edge of a box that has slits" << eol;
2062 }
2063
remove_slits_on_current_box()2064 void mondrian::remove_slits_on_current_box () {
2065 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) {
2066 rect* li = *i;
2067 if (li->total_slits && inbox (li->extents, win.mousex, win.mousey)) {
2068 remove_slits (li);
2069 return;
2070 }
2071 }
2072 }
2073
remove_slits_on_boxes_with_balls()2074 void mondrian::remove_slits_on_boxes_with_balls () {
2075 list<ball*>& balls = get_balls (0);
2076 map<rect*, int> m;
2077 for (balls_iterator p = balls.begin (), q = balls.end (); p != q; ++p) {
2078 ball* b = *p;
2079 m[b->R] = 1;
2080 }
2081 for (map<rect*, int>::iterator i = m.begin (), j = m.end (); i != j; ++i) remove_slits ((*i).first);
2082 }
2083
remove_all_slits()2084 void mondrian::remove_all_slits () { // in all boxes
2085 for (box_iterator i = leaves.begin (), j = leaves.end (); i != j; ++i) {
2086 rect* li = *i;
2087 if (li->total_slits) remove_slits (li);
2088 }
2089 }
2090
remove_selected_slits()2091 void mondrian::remove_selected_slits () {
2092 while (1) {
2093 slit_iterator i = selected_slits.begin ();
2094 if (i != selected_slits.end ()) remove_slit (*i); else break;
2095 }
2096 }
2097
get_index_of_slit(slit * s)2098 int mondrian::get_index_of_slit (slit* s) {
2099 int k = 0;
2100 for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i, ++k) {
2101 if (*i == s) return k;
2102 }
2103 return -1;
2104 }
2105
get_slit_from_index(int q)2106 slit* mondrian::get_slit_from_index (int q) {
2107 int p = 0;
2108 for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i, ++p) {
2109 if (p == q) return *i;
2110 }
2111 return 0;
2112 }
2113
get_note_ids(pair<int,int> & nids,rect * R,int type)2114 int mondrian::get_note_ids (pair<int, int>& nids, rect* R, int type) {
2115
2116 pair<float, float> intervals;
2117
2118 if (type == split::VERTICAL)
2119 R->get_vertical_interval (intervals, root);
2120 else
2121 R->get_horizontal_interval (intervals, root);
2122
2123 get_note_ids_from_intervals (nids, intervals);
2124
2125 return ((nids.first != -1) && (nids.second != -1));
2126
2127 }
2128
get_note_ids_from_intervals(pair<int,int> & note_ids,const pair<float,float> & intervals)2129 void mondrian::get_note_ids_from_intervals (pair<int, int>& note_ids, const pair<float, float>& intervals) {
2130
2131 note_ids.first = note_ids.second = -1;
2132 int n = scaleinfo.num_notes;
2133
2134 static const float E = 0.0001;
2135
2136 for (int i = 0; i < n; ++i) {
2137 const string& name = scaleinfo.notes[i];
2138 float value = INTERVALS [name];
2139 float delta = value - intervals.first;
2140 if (delta > E) {
2141 note_ids.first = i;
2142 break;
2143 }
2144 }
2145
2146 if (note_ids.first != -1) {
2147 for (int j = note_ids.first; j < n; ++j) {
2148 const string& name = scaleinfo.notes [j];
2149 float value = INTERVALS [name];
2150 float delta = intervals.second - value;
2151 if (delta > E) {
2152 note_ids.second = j + 1;
2153 } else break;
2154 }
2155 }
2156
2157 }
2158
multi_split_rect(split_data & sd)2159 int mondrian::multi_split_rect (split_data& sd) {
2160 if (sd.start < sd.end) {
2161 float pos;
2162 if (sd.split_at == split::NOTES) {
2163 int i = sd.start;
2164 const string& name = scaleinfo.notes[i];
2165 float value = INTERVALS [name];
2166 float delta = value - 1.0f;
2167 if (sd.split_type == split::VERTICAL) pos = root->extents.left + delta * root->extents.width;
2168 else pos = root->extents.bottom + delta * root->extents.height;
2169 } else {
2170 if (sd.split_type == split::VERTICAL)
2171 pos = sd.R->extents.left + sd.sz;
2172 else
2173 pos = sd.R->extents.bottom + sd.sz;
2174 }
2175 split_rect (sd.split_type, pos, sd.R);
2176 if (sd.lr) sd.lr->push_back (sd.R->child1);
2177 sd.R = sd.R->child2;
2178 ++sd.start;
2179 ++sd.nsplits;
2180 return 0;
2181 } else {
2182 if (sd.lr && sd.R && sd.nsplits) sd.lr->push_back (sd.R);
2183 if (sd.lis) sd.lis->split_over (sd);
2184 return 1;
2185 }
2186 }
2187
multi_split_rect(int n,int type,rect * B,list<rect * > * lr,split_listener * sl)2188 void mondrian::multi_split_rect (int n, int type, rect* B, list<rect*> *lr, split_listener* sl) { // split into n boxes
2189 if (B == 0) {
2190 B = box_under_cursor ();
2191 if (B == 0) {
2192 cons << YELLOW << "Cant split as you are outside all boxes :(" << eol;
2193 return;
2194 }
2195 }
2196 float amt;
2197 if (type == split::VERTICAL) amt = B->extents.width; else amt = B->extents.height;
2198 float sz = amt / n;
2199 if (sz < min_split_size) {
2200 cons << YELLOW << "Cannot split as the boxes will be too small [" << " < " << min_split_size << " ] :(" << eol;
2201 return;
2202 }
2203
2204 // 1 split every frame
2205 split_data sd (0, n - 1, split::ANYWHERE, type, B, lr, sl, sz, n);
2206 lsd.push_back (sd);
2207 splitting_rects = 1;
2208 }
2209
multi_split_rect(int type,rect * B,list<rect * > * lr,split_listener * sl)2210 void mondrian::multi_split_rect (int type, rect* B, list<rect*> *lr, split_listener* sl) { // split at notes
2211 if (B == 0) B = box_under_cursor ();
2212 if (B) {
2213 pair<int, int> note_ids;
2214 if (get_note_ids (note_ids, B, type)) {
2215 // 1 split every frame
2216 split_data sd (note_ids.first, note_ids.second, split::NOTES, type, B, lr, sl);
2217 lsd.push_back (sd);
2218 splitting_rects = 1;
2219 }
2220 } else {
2221 cons << YELLOW << "Cant split as you are outside all boxes :(" << eol;
2222 }
2223 }
2224
make_note_grid()2225 void mondrian::make_note_grid () {
2226 if (root->child1 == 0 && root->child2 == 0) {
2227 rect* B = root;
2228 columns.clear ();
2229 multi_split_rect (split::VERTICAL, B, &columns, this); // split on notes along horizontal axis
2230 } else {
2231 cons << YELLOW << "Please delete all boxes, cannot create note grid :(" << eol;
2232 }
2233 }
2234
make_nxn_grid()2235 void mondrian::make_nxn_grid () {
2236 if (root->child1 == 0 && root->child2 == 0) {
2237 rect* B = root;
2238 columns.clear ();
2239 multi_split_rect (num_boxes, split::VERTICAL, B, &columns, this);
2240 } else {
2241 cons << YELLOW << "Please delete all boxes, cannot create box grid :(" << eol;
2242 }
2243 }
2244
split_over(split_data & sd)2245 void mondrian::split_over (split_data& sd) {
2246 if (sd.split_at == split::NOTES) {
2247 for (box_iterator s = sd.lr->begin (), t = sd.lr->end (); s != t; ++s) {
2248 multi_split_rect (split::HORIZONTAL, *s); // at notes
2249 }
2250 } else {
2251 for (box_iterator s = sd.lr->begin (), t = sd.lr->end (); s != t; ++s) {
2252 multi_split_rect (sd.n, split::HORIZONTAL, *s); // n x n
2253 }
2254 }
2255 }
2256
set_ball_param(int what,float v)2257 void mondrian::set_ball_param (int what, float v) {
2258 list<ball*>& _balls = get_balls ();
2259 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
2260 ball* b = *p;
2261 switch (what) {
2262 case ball::SET_DECAY_TIME:
2263 b->decay_time = v;
2264 break;
2265 case ball::SET_ATTACK_TIME:
2266 b->attack_time = v;
2267 break;
2268 case ball::SET_VOL_MULT:
2269 b->vol_mult = v;
2270 }
2271 }
2272 }
2273
2274
change_ball_vol_mult(spinner<float> & s)2275 void mondrian::change_ball_vol_mult (spinner<float>& s) {
2276 int n = 0;
2277 list<ball*>& _balls = get_balls ();
2278 for (balls_iterator p = _balls.begin (), q = _balls.end (); p != q; ++p) {
2279 ball* b = *p;
2280 b->vol_mult += s();
2281 // if (b->vol_mult < 0) b->vol_mult = 0.0f;
2282 sprintf (BUFFER, "Ball %d, volume multiplier = %0.3f", ++n, b->vol_mult);
2283 cons << GREEN << BUFFER << eol;
2284 }
2285 }
2286
change_min_voices(int d)2287 void mondrian::change_min_voices (int d) {
2288 min_voices += d;
2289 if (min_voices < 1) min_voices = 1;
2290 cons << YELLOW << "Min Voices = " << min_voices << eol;
2291 MENU.sp_mondrian_min_voices.set_value (min_voices);
2292 }
2293
edge_on_root(rect * root,rect ** boxes,int * edges)2294 int edge_on_root (rect* root, rect** boxes, int* edges) {
2295 float edge_vals_root [rect::nedges] = {root->extents.bottom, root->extents.right, root->extents.top, root->extents.left};
2296 for (int i = 0; i < 2; ++i) {
2297 rect* ri = boxes[i];
2298 int ei = edges[i];
2299 float edge_vals_ri [rect::nedges] = {ri->extents.bottom, ri->extents.right, ri->extents.top, ri->extents.left};
2300 if (edge_vals_ri [ei] == edge_vals_root [ei]) return 1;
2301 }
2302 return 0;
2303 }
2304
mark_selected_slits()2305 void mondrian::mark_selected_slits () {
2306 if (num_selected_slits) {
2307 glEnable (GL_LINE_STIPPLE);
2308 glLineStipple (1, 0xF0F0);
2309 glColor3f (0, 1, 0);
2310 for (slit_iterator si = selected_slits.begin (), sj = selected_slits.end (); si != sj; ++si) {
2311 slit* s = *si;
2312 rect* r = s->boxes[0];
2313 int e = s->edges[0];
2314 box<float>& x = r->extents;
2315 float l [] = {x.bottom, x.right, x.top, x.left};
2316 int t [] = {slit::HORIZONTAL, slit::VERTICAL, slit::HORIZONTAL, slit::VERTICAL};
2317 glBegin (GL_LINES);
2318 float le = l[e];
2319 if (t[e] == slit::HORIZONTAL) {
2320 glVertex2f (s->start, le);
2321 glVertex2f (s->end, le);
2322 } else {
2323 glVertex2f (le, s->start);
2324 glVertex2f (le, s->end);
2325 }
2326 glEnd ();
2327 }
2328 }
2329 glDisable (GL_LINE_STIPPLE);
2330 }
2331
region_begin()2332 void mondrian::region_begin () {
2333 rgn.left = rgn.right = win.mousex;
2334 rgn.bottom = rgn.top = win.mousey;
2335 }
2336
region_end()2337 void mondrian::region_end () {
2338 rgn.calc ();
2339 select_balls (rgn);
2340 }
2341
region_update()2342 const box<float>& mondrian::region_update () {
2343 rgn.right = win.mousex;
2344 rgn.top = win.mousey;
2345 return rgn;
2346 }
2347
draw_slit_cutter(int yesno)2348 void draw_slit_cutter (int yesno) {
2349 mondrian0.draw_slit_cutter = yesno;
2350 }
2351
2352
browse_t()2353 mondrian::browse_t::browse_t () {
2354 n = which = last = 0;
2355 }
2356
clear()2357 void mondrian::browse_t::clear () {
2358 n = which = last = 0;
2359 balls.clear ();
2360 MENU.ol_browse_balls.set_text ("");
2361 }
2362