1 /*
2 * mondrian.h
3 * inspired by the works of Piet Mondrian
4 * DIN Is Noise is released under GNU Public License 2.0
5 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
6 * For more information, please visit https://dinisnoise.org/
7 */
8 
9 #ifndef __mondrian__
10 #define __mondrian__
11 
12 #include "point.h"
13 #include "viewwin.h"
14 #include "ui.h"
15 #include "box_selector.h"
16 #include "textboard.h"
17 #include "triggered_note.h"
18 #include "listeners.h"
19 #include "curve_editor.h"
20 #include "help.h"
21 #include "instrument.h"
22 #include "rect.h"
23 #include "ball.h"
24 #include "slit.h"
25 #include "alarm.h"
26 #include "spinner.h"
27 #include <string>
28 #include <vector>
29 
30 typedef std::list<ball*>::iterator balls_iterator;
31 
32 struct draw_ball_t {
33 	int position;
34 	int heading;
35 	int trails;
draw_ball_tdraw_ball_t36 	draw_ball_t () { position = heading = trails = 1;}
37 };
38 
39 struct mondrian : instrument, scale_listener, region_listener, split_listener {
40 
41   mondrian ();
42   ~mondrian ();
43 
44   void enter ();
45   void leave ();
46 
47   multi_curve wave; // waveform shared by all balls
48   curve_editor waved;  // waveform editor
49 	wave_listener wavlis;
50 	void update_waveform (multi_curve& crv);
51 
52 	multi_curve attack, decay; // attack and decay curves shared by all balls
53 	curve_editor attacked, decayed; // attack and decay curve editors
54 	attack_listener attacklis;
55 	decay_listener decaylis;
56 	void update_attack ();
57 	void update_decay ();
58 	float delta_attack_time, delta_decay_time;
59 
60   window win; // edit window
61 	// object space <> window space mapping
62 	//
63   point<int> win_chunk;
64   point<float> obj_chunk;
65   point<float> win_per_obj;
66   point<float> obj_per_win;
67   float win_resolution;
68   float obj_resolution;
69   void obj2win (const point<float>& p, float& wx, float& wy);
70   void obj2win (const float& ox, const float& oy, float& wx, float& wy);
71   void win2obj (const float& dx, const float& dy, float& cx, float& cy);
72 
73   int pan, zoom;
74   void do_panx (int dir);
75   void do_pany (int dir);
76   void do_zoom (int dir);
77 
78   void calc_win_mouse ();
79 	int lmb_clicked;
80 
81 	//
82 	// file
83   void load_settings ();
84   void load_settings (std::ifstream& file);
85   void save_settings (std::ofstream& file);
86 	box_from_disk_t get_box_from_disk (std::list<box_from_disk_t>& boxes, const std::string& id);
87 	void load_boxes_and_balls ();
88 	void save_boxes (std::ofstream& f, rect* R, std::string& id);
89 	void save_balls (std::ofstream& f);
90 
91   void setup ();
92 
93   int handle_input ();
94 
95 	// draw
96 	//
97 
98 	int draw__boxes;
99 	int fill_boxes;
100 	int label_notes;
101 	int label_hz_vol;
102 	int draw__notes;
103 	int draw_slit_cutter;
104 	draw_ball_t draw_ball;
105 
106 	void draw_rect (rect* which);
107 	void draw_leaves ();
108 	void draw_balls ();
109 	void draw_notes ();
110   void draw ();
111 
112 	// boxes
113 	//
114 
115   rect* root; // the main box
116 	std::list <rect*> leaves; // boxes that dont have children and can bear slits
117   rect* get_sibling (rect* R); // return sibling of R
118   void find (rect* R, float x, float y, finding& f); // find box where x,y is found. starting with R and down
119   rect* box_under_cursor ();
120   finding make_finding (rect* R); // R and its sibling
bad_rectmondrian121   int bad_rect (rect* R) { return R == 0 || R == root; }
122 
123   // box splitting
124   //
125 
126 	rect* split_rect (int type, float where, rect* B = 0); // split box [type = horizontal or vertical]
127 	int num_boxes;
128 	int get_note_ids (std::pair<int, int>& nids, rect* R, int type);
129   void get_note_ids_from_intervals (std::pair<int, int>& idp, const std::pair<float, float>& ip);
130 	int multi_split_rect (split_data& sd);
131 	void multi_split_rect (int n, int type, rect* B = 0, std::list<rect*> *pr = 0, split_listener* sl = 0); // split B [or current] into n boxes
132 	void multi_split_rect (int type, rect* B = 0, std::list<rect*> *lr = 0, split_listener* sl = 0); // split B [or current] at note intervals
133   int splitting_rects;
134   std::list<split_data> lsd;
135   void split_over (split_data& sd);
136   std::list<rect*> columns;
137 	void make_note_grid (); // split the root box both horizontally and vertically at the notes of the scale
138 	void make_nxn_grid (); // split the root box into a N x N grid of boxes
139 
140   int nleaves;
141 	void add_leaf (rect* L); // splitting a box makes 2 leaves
142 	void remove_leaf (rect* L);
143 
144   rect* earliest_leaf ();
145   rect* latest_leaf ();
146   rect* rnd_leaf ();
147   rect* biggest_leaf ();
148 	rect* balled_leaf ();
149   rect* pick_leaf (int& what);
150 	int split_leaf, delete_leaf;
151 
152 	void recreate_slits (rect* b); // to recreate slits of a just deleted box in its two children ie leaves
153 
154 	int delete_rect (const finding& f); // delete found box
155   void delete_current_rect (); // delete box under cursor
156 	void update_children (rect* R); // update extents of children of box R
157 	void delete_children (rect* R); // delete children of box R
158 	void update_parent (rect* C); // update parent (and ancestors) of box C
159   int delete_all_rects; // when active, once every frame
160 
161   alarm_t auto_del_rect; // auto delete box?
162   alarm_t auto_split_rect; // auto split box?
163 
164   int auto_split_orient;
165   int auto_split_at;
166   int auto_split_which;
167 
168 
169   rect* hit; // box hit when clicked
170   int edge; // edge hit
171   void set_edge (rect* R, int e, float x, float y); // set vertical (using x) or horizontal edge (using y) of box R
172 
173 	int sel_tar; // selection target
174 	enum {SELECT_SLITS = 0, SELECT_BALLS};
175 
176 	// balls
177   //
178   std::list<ball*> balls;
179 	int num_balls;
180 
181   int adding_balls;
182 	int added_ball_type;
183   int started_making_ball;
184   ball* new_ball;
185 	void do_add_balls (int _type = ball::BOUNCER);
186 
187   void split_balls (rect* P, rect* C1, rect* C2); // split balls among children C1 and C2 when parent P is deleted
188 
189 	void delete_ball (ball* b);
190 	void delete_all_balls ();
191 	void delete_selected_balls ();
192 
193   float delta_speed;
194 	void change_speed (spinner<float>& s, float d);
195 
196   // ball selection
197   //
198   std::list<ball*> selected_balls;
199   int num_selected_balls;
200   void select_balls (const box<float>& rgn);
201   void select_box_balls ();
202 	void after_selection ();
203 	void select_type (int t);
204 	struct browse_t {
205 		int which, last, n;
206 		std::vector<ball*> balls;
207 		browse_t ();
208 		void clear ();
209 	} browse;
210 	void browse_ball (int i);
211 
212 	std::list<ball*>& get_box_balls ();
213   std::list<ball*>& get_balls ();
214 	std::list<ball*>& get_balls (int);
215 	ball* get_one_selected_ball ();
216 	void switch_balls_type ();
217 
218 	// freeze and thaw
219   void freeze_thaw_balls (std::list<ball*>& _balls);
220   void freeze_balls (std::list<ball*>& _balls);
221   void thaw_balls (std::list<ball*>& _balls);
222   void freeze_all_balls ();
223 
224 	void clear_modulations (std::list<ball*>& _balls);
225 
226 	// ball movement
227   int moving_balls;
228   void move_balls (float dx, float dy);
229   void do_move_balls ();
230 	void locate_ball (ball* b);
231 
232 	// ball course
233 	float delta_rotate_velocity;
234 	void rotate_velocity (int dir);
235 	void toggle_auto_rotate (int ar);
236 	void set_auto_rotate (int ar);
237 	void flip_velocity ();
238 	void change_ball_dtheta (int dir);
239 
240 	// ball misc
241 	void set_ball_param (int what, float value);
242 	void change_ball_vol_mult (spinner<float>& s);
243 	void clone_ball (ball* b);
244 	void toggle_triggered_sound ();
245 
246 	// slits
247 	//
248 
249 	enum {NOTHING, JUST_SLIT, ANIMATE_SLIT};
250 	int slitting;
251 	fader fdr; // for animating slit
252 
253 	int num_slits;
254 	std::list<slit*> slits; // all slits
255 	std::list<slit*> selected_slits;
256 	int num_selected_slits;
257 
258 	void load_slits (std::ifstream& f, std::list<box_from_disk_t>& boxes);
259 	void save_slits (std::ofstream& f);
260 	int get_index_of_slit (slit* s);
261 	slit* get_slit_from_index (int q);
262 
263 	rect* bxs[2]; // a slit can only be on 2 boxes
264 
265 	int find_hit_slit (float x, float y); // under cursor
266 
267 	slit_lip_t slit_lip;
268 	int editing_slit;
269 	int editing_edge;
270 
271 	void start_slitting ();
272 	int try_slitting ();
273 	int add_remove_slit (float x, float y, fader* fdr = 0, float sz = slit::HALF_SIZE);
274 	void change_slit_size (spinner<float>& s);
275 	void change_slit_anim_time (spinner<float>& s);
276 	void remove_all_slits ();
277 	void remove_selected_slits ();
278 	void remove_slit (slit* s);
279 	void remove_slits (rect* R);
280 	void remove_slits_on_edge (rect* R, int e);
281 	void remove_slits_on_current_edge ();
282 	void remove_slits_on_current_box ();
283 	void remove_slits_on_boxes_with_balls ();
284 	void select_box_slits ();
285 	void toggle_slit_anim ();
286 	void remove_slit_anim ();
287 	void start_slit_anim ();
288 
289 	void clear_selected_targets ();
290 	void select_all_targets ();
291 	void select_box_targets ();
292 	void invert_selected_targets ();
293 	void delete_selected_targets ();
294 	void delete_all_targets ();
295 
296   // visual
297   //
298   int n_pts;
299   float* pts; // balls are points
300 	float* pts_d; // ball direction are lines
301   float* pts_clr; // ball colors
302   int n_mrk;
303   float* mrk;
304   float crsr [8];
305   int cursor;
306   textboard tb, tb_hz_vol;
307   void make_notes ();
308   void calc_visual_params ();
309   void randomise_box_color (); // of the box under cursor
310   void toggle_flag (int& flag, const std::string& poz, const std::string& neg = "");
311 
312 	slit_drawer slit_drawerr;
313 
314 	static const float gutter, gutter2; // for edge selection & slit making
315   static float min_split_size; // for auto box splitting
316 
317 	struct poly_t {
318 		std::vector<float> coss, sinn;
319 		int points;
320 		float radius;
321 		float delta_radius;
poly_tmondrian::poly_t322 		poly_t () {
323 			radius = 0;
324 			delta_radius = 0;
325 			points = 0;
326 		}
327 	} poly;
328 	int set_note_poly_points (int p);
329 	int set_note_poly_radius (float r);
330 
331   // notes
332   float note_volume;
333 	int voices;
334 	int min_voices;
335 	int auto_adjust_voices;
336   note N;
337 	int num_triggered_notes;
338   std::list<triggered_note> triggered_notes;
339 	std::list<ball*> triggering_balls;
340   void launch_note (ball* _ball, float t, float t0, float dt, const std::pair<float, float>& invl);
341 	void remove_finished_notes ();
342 	void print_num_triggered_notes ();
343 	int change_param (float& param, float value, float& recent);
344 	void change_attack_time_kb (spinner<float>& s); // using kb shortcut
345 	void change_decay_time_kb (spinner<float>& s);
346 	void change_trail_size (spinner<int>& s);
347 	void change_min_voices (int d);
348 
349 	// others
350 	//
351 
352 	int stop_editing_slit ();
353 	int stop_editing_edge ();
354 	int stop_adding_balls ();
355 	int stop_moving_balls ();
356 	int stop_slitting ();
357 	int stop_doing_stuff ();
rectingmondrian358   int recting () {return editing_edge || editing_slit || splitting_rects; }
359 
360 	void scale_changed ();
361 	void scale_loaded ();
362 	void tonic_changed ();
363 
364 	int modulate_balls (int p);
365 
366 	void toggle_balls_type (int _type);
367 
368   int render_audio (float* L, float* R);
369 
370 	void bg ();
371 
372 	void mark_selected_slits ();
373 
374 	box<float> rgn;
375 	void region_begin ();
376 	void region_end ();
377 	const box<float>& region_update ();
378 
379   help _help;
380 
381 };
382 
383 int edge_on_root (rect* root, rect** boxes, int* edges);
384 void draw_slit_cutter (int yesno);
385 
386 extern mondrian mondrian0;
387 
388 template<class T> void clear_selected (list<T*>& targets, int& num_targets, int aft_sel = 1) {
389   for (typename list<T*>::iterator p = targets.begin (), q = targets.end (); p != q; ++p) {
390     T* t = *p;
391     t->select = 0;
392   }
393 	targets.clear ();
394 	num_targets = 0;
395 	if (aft_sel) mondrian0.after_selection ();
396 }
397 
select_all(list<T * > & items,list<T * > & selection,int & num_selected)398 template <class T> void select_all (list<T*>& items, list<T*>& selection, int& num_selected) {
399 	clear_selected<T> (selection, num_selected);
400   for (typename list<T*>::iterator p = items.begin (), q = items.end (); p != q; ++p) {
401 		T* t = *p;
402 		t->select = 1;
403 		selection.push_back (t);
404 		++num_selected;
405 	}
406 	mondrian0.after_selection ();
407 }
408 
invert_selection(list<T * > & items,list<T * > & selection,int & num_selected)409 template <class T> void invert_selection (list<T*>& items, list<T*>& selection, int& num_selected) {
410 	num_selected = 0;
411 	selection.clear ();
412 	for (typename list<T*>::iterator p = items.begin(), q = items.end(); p != q; ++p) {
413     T* b = *p;
414     b->select = !b->select;
415 		if (b->select) {
416 			selection.push_back (b);
417 			++num_selected;
418 		}
419   }
420 	mondrian0.after_selection ();
421 }
422 
select_using_modifiers(T * b,int ctrl,list<T * > & selection,int & num_selected)423 template <class T> void select_using_modifiers (T* b, int ctrl, list<T*>& selection, int& num_selected) {
424 	typename list<T*>::iterator se = selection.end (), f = ::find (selection.begin (), se, b);
425 	if (f == se) {
426 		sel:
427 		b->select = 1;
428 		push_back (selection, b);
429 		++num_selected;
430 	} else {
431 		if (ctrl) {
432 			if (b->select) {
433 				b->select = 0;
434 				selection.erase (f);
435 				--num_selected;
436 			} else
437 				goto sel;
438 		}
439 	}
440 }
441 
442 
443 #endif
444