Rev 2097 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* slit.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include "slit.h"
#include "rect.h"
#include "mondrian.h"
#include "utils.h"
#include "fader.h"
#include "console.h"
#include <cmath>
using namespace std;
slit::slit () {
boxes[0] = 0; edges[0] = -1;
boxes[1] = 0; edges[1] = -1;
start = end = mid = 0;
type = INVALID;
animt = INITIAL_OPEN_CLOSE_TIME;
fdr = 0;
select = 0;
++ref;
}
slit::slit (rect** bxs, float x, float y, float sz, fader* _fdr) {
// slit can be on 2 boxes only
boxes [0] = bxs [0]; // box 0
boxes [1] = bxs [1]; // box 1
rect* b0 = boxes [0];
int e0 = b0->extents.get_edge_hit (x, y, mondrian::gutter2); // edge 0
edges [0] = e0;
edges [1] = (e0 + 2) % 4; // edge 1 = opposite edge on 2nd box
int typs [] = {HORIZONTAL, VERTICAL, HORIZONTAL, VERTICAL};
type = typs [e0];
if (type == VERTICAL) mid = y; else mid = x;
start = mid - sz;
end = mid + sz;
animt = INITIAL_OPEN_CLOSE_TIME;
if (_fdr) {
fdr = new fader ();
fdr->copy (_fdr);
} else fdr = 0;
select = 0;
++ref;
}
slit::~slit () {
if (fdr) delete fdr;
--ref;
}
int slit::is_too_small () {
if (fdr) return 0;
float sz = end - start;
if (sz > MIN_SIZE) return 0; else return 1;
return 0;
}
void slit::toggle_anim () {
if (fdr) {
start = anim_start;
end = anim_end;
calc_mid ();
delete fdr;
fdr = 0;
} else {
anim_start = start;
anim_end = end;
fdr = new fader (animt);
fdr->restart ();
}
}
void slit::eval_anim () {
if (fdr) {
fdr->eval ();
start = (1 - fdr->amount) * anim_start + fdr->amount * anim_end;
calc_mid ();
if (fdr->reached) {
fdr->restart ();
fdr->flip = !fdr->flip;
}
}
}
rect* get_other_rect_of_slit (rect* ib, int e, float v, slit** os) {
list<slit*>& slits = ib->slits[e];
rect* or_ = 0;
for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) {
slit* si = *i;
if (v >= si->start && v <= si->end) {
if (si->boxes[0] == ib) or_ = si->boxes[1]; else or_ = si->boxes[0];
*os = si;
return or_;
}
}
return 0;
}
rect* get_other_rect_of_slit (slit* s, rect* t) {
if (s->boxes[0] == t) return s->boxes[1]; else return s->boxes[0];
}
int get_slit_lip (slit_lip_t& slit_lip, rect* R, int e, float v) {
list<slit*>& slits = R->slits[e];
static const int tol = 4;
for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) {
slit* si = *i;
if (abs (v - si->start) < tol) {
slit_lip.slitt = si;
slit_lip.lip = &si->start;
rect* R1 = get_other_rect_of_slit (si, R);
box<float>& RE = R->extents, RE1 = R1->extents;
float lows [rect::nedges] = {RE.left, RE.bottom, RE.left, RE.bottom};
float lows1 [rect::nedges] = {RE1.left, RE1.bottom, RE1.left, RE1.bottom};
float low = max (lows[e], lows1[e]);
slit_iterator i1 = i; --i1;
if (i1 != j) slit_lip.low = max ((*i1)->end, low); else slit_lip.low = low;
slit_lip.high = si->end;
return 1;
} else if (abs (si->end - v) < tol) {
slit_lip.slitt = si;
slit_lip.lip = &si->end;
slit_lip.low = si->start;
rect* R1 = get_other_rect_of_slit (si, R);
box<float>& RE = R->extents, RE1 = R1->extents;
float highs [rect::nedges] = {RE.right, RE.top, RE.right, RE.top};
float highs1 [rect::nedges] = {RE1.right, RE1.top, RE1.right, RE1.top};
float high = min (highs[e], highs1[e]);
slit_iterator i1 = i; ++i1;
if (i1 != j) slit_lip.high = min ((*i1)->start, high); else slit_lip.high = high;
return 1;
}
}
return 0;
}
slit* slit_hit (rect* R, int e, float v) {
list<slit*>& slits = R->slits[e];
for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) {
slit* si = *i;
if (v >= si->start && v <= si->end) return si;
}
return 0;
}
slit* slit_hit (rect** bxs, float x, float y) {
rect* b0 = bxs [0];
int e0 = b0->extents.get_edge_hit (x, y, mondrian::gutter2);
int e1 = (e0 + 2) % 4;
int e[2] = {e0, e1};
float v[4] = {x, y, x, y};
for (int i = 0; i < 2; ++i) {
rect* b = bxs[i];
int ei = e[i];
slit* sh = slit_hit (b, ei, v[ei]);
if (sh) return sh;
}
return 0;
}
void slit_lip_t::edit () {
float delta = *cur - *prev;
*lip += delta;
clamp (low, *lip, high);
slitt->calc_mid ();
}
void slit_lip_t::set_high (float h) {
high = h;
edit ();
}
void slit_lip_t::set_low (float l) {
low = l;
edit ();
}
void slit_lip_t::clear () {
slitt = 0;
lip = prev = cur = 0;
low = high = 0;
}
slit_info::slit_info () {
x = y = half_size = 0;
anim = 0;
}
void draw_slits (float start, float end, float level, int type, list<slit*>& slits, slit_drawer& slit_drawerr) {
float last_end = start;
if (type == slit::VERTICAL) {
for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) {
slit* si = *i;
slit_drawerr.add (level, last_end);
slit_drawerr.add (level, si->start);
last_end = si->end;
}
slit_drawerr.add (level, last_end);
slit_drawerr.add (level, end);
} else {
for (slit_iterator i = slits.begin (), j = slits.end (); i != j; ++i) {
slit* si = *i;
slit_drawerr.add (last_end, level);
slit_drawerr.add (si->start, level);
last_end = si->end;
}
slit_drawerr.add (last_end, level);
slit_drawerr.add (end, level);
}
}
slit_drawer::slit_drawer (int nlines) {
int nverts = 2 * nlines;
int nlocs = 2 * nverts;
verts = new float [nlocs];
last = nlocs - 2;
cur = 0;
}
slit_drawer::~slit_drawer () {
delete[] verts;
}
void slit_drawer::add (float x, float y) {
if (cur < last) {
verts[cur] = x;
verts[cur+1] = y;
cur += 2;
} else {
draw ();
}
}
void slit_drawer::draw () {
if (cur) {
glVertexPointer (2, GL_FLOAT, 0, verts);
glDrawArrays (GL_LINES, 0, cur / 2);
cur = 0;
}
}