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 | } |