Rev 2097 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* mondrian.h
* inspired by the works of Piet Mondrian
* DIN Is Noise is released under GNU Public License 2.0
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/
#ifndef __mondrian__
#define __mondrian__
#include "point.h"
#include "viewwin.h"
#include "ui.h"
#include "box_selector.h"
#include "textboard.h"
#include "triggered_note.h"
#include "listeners.h"
#include "curve_editor.h"
#include "help.h"
#include "instrument.h"
#include "rect.h"
#include "ball.h"
#include "slit.h"
#include "alarm.h"
#include "spinner.h"
#include <string>
#include <vector>
typedef std::list<ball*>::iterator balls_iterator;
struct draw_ball_t {
int position;
int heading;
int trails;
draw_ball_t () { position = heading = trails = 1;}
};
struct field;
struct mondrian : instrument, scale_listener, region_listener, split_listener, typing_listener {
mondrian ();
~mondrian ();
void enter ();
void leave ();
void typing (field& f);
multi_curve wave; // waveform shared by all balls
curve_editor waved; // waveform editor
wave_listener wavlis;
void update_waveform (multi_curve& crv);
multi_curve attack, decay; // attack and decay curves shared by all balls
curve_editor attacked, decayed; // attack and decay curve editors
attack_listener attacklis;
decay_listener decaylis;
void update_attack ();
void update_decay ();
float delta_attack_time, delta_decay_time;
window win; // edit window
// object space <> window space mapping
//
point<int> win_chunk;
point<float> obj_chunk;
point<float> win_per_obj;
point<float> obj_per_win;
float win_resolution;
float obj_resolution;
void obj2win (const point<float>& p, float& wx, float& wy);
void obj2win (const float& ox, const float& oy, float& wx, float& wy);
void win2obj (const float& dx, const float& dy, float& cx, float& cy);
int pan, zoom;
void do_panx (int dir);
void do_pany (int dir);
void do_zoom (int dir);
void calc_win_mouse ();
int lmb_clicked;
//
// file
void load_settings ();
void load_settings (std::ifstream& file);
void save_settings (std::ofstream& file);
box_from_disk_t get_box_from_disk (std::list<box_from_disk_t>& boxes, const std::string& id);
void load_boxes_and_balls ();
void save_boxes (std::ofstream& f, rect* R, std::string& id);
void save_balls (std::ofstream& f);
void setup ();
int handle_input ();
// draw
//
int draw__boxes;
int fill_boxes;
int label_notes;
int label_hz_vol;
int draw__notes;
int draw_slit_cutter;
draw_ball_t draw_ball;
void draw_rect (rect* which);
void draw_leaves ();
void draw_balls ();
void draw_notes ();
void draw ();
// boxes
//
rect* root; // the main box
std::list <rect*> leaves; // boxes that dont have children and can bear slits
rect* get_sibling (rect* R); // return sibling of R
void find (rect* R, float x, float y, finding& f); // find box where x,y is found. starting with R and down
rect* box_under_cursor ();
finding make_finding (rect* R); // R and its sibling
int bad_rect (rect* R) { return R == 0 || R == root; }
// box splitting
//
rect* split_rect (int type, float where, rect* B = 0); // split box [type = horizontal or vertical]
int num_boxes;
int get_note_ids (std::pair<int, int>& nids, rect* R, int type);
void get_note_ids_from_intervals (std::pair<int, int>& idp, const std::pair<float, float>& ip);
int multi_split_rect (split_data& sd);
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
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
int splitting_rects;
std::list<split_data> lsd;
void split_over (split_data& sd);
std::list<rect*> columns;
void make_note_grid (); // split the root box both horizontally and vertically at the notes of the scale
void make_nxn_grid (); // split the root box into a N x N grid of boxes
int nleaves;
void add_leaf (rect* L); // splitting a box makes 2 leaves
void remove_leaf (rect* L);
rect* earliest_leaf ();
rect* latest_leaf ();
rect* rnd_leaf ();
rect* biggest_leaf ();
rect* balled_leaf ();
rect* pick_leaf (int& what);
int split_leaf, delete_leaf;
void recreate_slits (rect* b); // to recreate slits of a just deleted box in its two children ie leaves
int delete_rect (const finding& f); // delete found box
void delete_current_rect (); // delete box under cursor
void update_children (rect* R); // update extents of children of box R
void delete_children (rect* R); // delete children of box R
void update_parent (rect* C); // update parent (and ancestors) of box C
int delete_all_rects; // when active, once every frame
alarm_t auto_del_rect; // auto delete box?
alarm_t auto_split_rect; // auto split box?
int auto_split_orient;
int auto_split_at;
int auto_split_which;
rect* hit; // box hit when clicked
int edge; // edge hit
void set_edge (rect* R, int e, float x, float y); // set vertical (using x) or horizontal edge (using y) of box R
int sel_tar; // selection target
enum {SELECT_SLITS = 0, SELECT_BALLS};
// balls
//
std::list<ball*> balls;
int num_balls;
int adding_balls;
int added_ball_type;
int started_making_ball;
ball* new_ball;
void do_add_balls (int _type = ball::BOUNCER);
void split_balls (rect* P, rect* C1, rect* C2); // split balls among children C1 and C2 when parent P is deleted
void delete_ball (ball* b);
void delete_all_balls ();
void delete_selected_balls ();
float delta_speed;
void change_speed (spinner<float>& s, float d);
// ball selection
//
std::list<ball*> selected_balls;
int num_selected_balls;
void select_balls (const box<float>& rgn);
void select_box_balls ();
void after_selection ();
void select_type (int t);
struct browse_t {
int which, last, n;
std::vector<ball*> balls;
browse_t ();
void clear ();
} browse;
void browse_ball (int i);
std::list<ball*>& get_box_balls ();
std::list<ball*>& get_balls ();
std::list<ball*>& get_balls (int);
ball* get_one_selected_ball ();
void switch_balls_type ();
// freeze and thaw
void freeze_thaw_balls (std::list<ball*>& _balls);
void freeze_balls (std::list<ball*>& _balls);
void thaw_balls (std::list<ball*>& _balls);
void freeze_all_balls ();
void clear_modulations (std::list<ball*>& _balls);
// ball movement
int moving_balls;
void move_balls (float dx, float dy);
void do_move_balls ();
void locate_ball (ball* b);
// ball course
float delta_rotate_velocity;
void rotate_velocity (int dir);
void toggle_auto_rotate (int ar);
void set_auto_rotate (int ar);
void flip_velocity ();
void change_ball_dtheta (int dir);
// ball misc
void set_ball_param (int what, float value);
void change_ball_vol_mult (spinner<float>& s);
void clone_ball (ball* b);
void toggle_triggered_sound ();
// slits
//
enum {NOTHING, JUST_SLIT, ANIMATE_SLIT};
int slitting;
fader fdr; // for animating slit
int num_slits;
std::list<slit*> slits; // all slits
std::list<slit*> selected_slits;
int num_selected_slits;
void load_slits (std::ifstream& f, std::list<box_from_disk_t>& boxes);
void save_slits (std::ofstream& f);
int get_index_of_slit (slit* s);
slit* get_slit_from_index (int q);
rect* bxs[2]; // a slit can only be on 2 boxes
int find_hit_slit (float x, float y); // under cursor
slit_lip_t slit_lip;
int editing_slit;
int editing_edge;
void start_slitting ();
int try_slitting ();
int add_remove_slit (float x, float y, fader* fdr = 0, float sz = slit::HALF_SIZE);
void change_slit_size (spinner<float>& s);
void change_slit_anim_time (spinner<float>& s);
void remove_all_slits ();
void remove_selected_slits ();
void remove_slit (slit* s);
void remove_slits (rect* R);
void remove_slits_on_edge (rect* R, int e);
void remove_slits_on_current_edge ();
void remove_slits_on_current_box ();
void remove_slits_on_boxes_with_balls ();
void select_box_slits ();
void toggle_slit_anim ();
void remove_slit_anim ();
void start_slit_anim ();
void clear_selected_targets ();
void select_all_targets ();
void select_box_targets ();
void invert_selected_targets ();
void delete_selected_targets ();
void delete_all_targets ();
// visual
//
int n_pts;
float* pts; // balls are points
float* pts_d; // ball direction are lines
float* pts_clr; // ball colors
int n_mrk;
float* mrk;
float crsr [8];
int cursor;
textboard tb, tb_hz_vol;
void make_notes ();
void calc_visual_params ();
void randomise_box_color (); // of the box under cursor
void toggle_flag (int& flag, const std::string& poz, const std::string& neg = "");
// opengl polygon stipple box fill
//
static unsigned char patbuf [1024];
static std::string patstr;
static int patstep, patlen;
void fillpatbuf ();
slit_drawer slit_drawerr;
static const float gutter, gutter2; // for edge selection & slit making
static float min_split_size; // for auto box splitting
struct poly_t {
std::vector<float> coss, sinn;
int points;
float radius;
float delta_radius;
poly_t () {
radius = 0;
delta_radius = 0;
points = 0;
}
} poly;
int set_note_poly_points (int p);
int set_note_poly_radius (float r);
// notes
float note_volume;
int voices;
int min_voices;
int auto_adjust_voices;
note N;
int num_triggered_notes;
std::list<triggered_note> triggered_notes;
std::list<ball*> triggering_balls;
void launch_note (ball* _ball, float t, float t0, float dt, const std::pair<float, float>& invl);
void remove_finished_notes ();
void print_num_triggered_notes ();
int change_param (float& param, float value, float& recent);
void change_attack_time_kb (spinner<float>& s); // using kb shortcut
void change_decay_time_kb (spinner<float>& s);
void change_trail_size (spinner<int>& s);
void change_min_voices (int d);
// others
//
int stop_editing_slit ();
int stop_editing_edge ();
int stop_adding_balls ();
int stop_moving_balls ();
int stop_slitting ();
int stop_doing_stuff ();
int recting () {return editing_edge || editing_slit || splitting_rects; }
void scale_changed ();
void scale_loaded ();
void tonic_changed ();
int modulate_balls (int p);
void toggle_balls_type (int _type);
int render_audio (float* L, float* R);
void bg ();
void mark_selected_slits ();
box<float> rgn;
void region_begin ();
void region_end ();
const box<float>& region_update ();
help _help;
};
int edge_on_root (rect* root, rect** boxes, int* edges);
void draw_slit_cutter (int yesno);
extern mondrian mondrian0;
template<class T> void clear_selected (list<T*>& targets, int& num_targets, int aft_sel = 1) {
for (typename list<T*>::iterator p = targets.begin (), q = targets.end (); p != q; ++p) {
T* t = *p;
t->select = 0;
}
targets.clear ();
num_targets = 0;
if (aft_sel) mondrian0.after_selection ();
}
template <class T> void select_all (list<T*>& items, list<T*>& selection, int& num_selected) {
clear_selected<T> (selection, num_selected);
for (typename list<T*>::iterator p = items.begin (), q = items.end (); p != q; ++p) {
T* t = *p;
t->select = 1;
selection.push_back (t);
++num_selected;
}
mondrian0.after_selection ();
}
template <class T> void invert_selection (list<T*>& items, list<T*>& selection, int& num_selected) {
num_selected = 0;
selection.clear ();
for (typename list<T*>::iterator p = items.begin(), q = items.end(); p != q; ++p) {
T* b = *p;
b->select = !b->select;
if (b->select) {
selection.push_back (b);
++num_selected;
}
}
mondrian0.after_selection ();
}
template <class T> void select_using_modifiers (T* b, int ctrl, list<T*>& selection, int& num_selected) {
typename list<T*>::iterator se = selection.end (), f = ::find (selection.begin (), se, b);
if (f == se) {
sel:
b->select = 1;
push_back (selection, b);
++num_selected;
} else {
if (ctrl) {
if (b->select) {
b->select = 0;
selection.erase (f);
--num_selected;
} else
goto sel;
}
}
}
#endif