Subversion Repositories DIN Is Noise

Rev

Rev 2285 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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