Subversion Repositories DIN Is Noise

Rev

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