/*
* curve_samples.cc
* DIN Is Noise is copyright (c) 2006-2022 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include "curve_editor.h"
#include "curve_samples.h"

extern void hz2step (float&, float&);

curve_samples::curve_samples () {
  m = 0;
  dm = 0;
  n = 0;
  n_reached = 0;
  x = xp = y = xy = 0;
  hz = step = 0;
  nperiods = 3;
}

curve_samples::~curve_samples () {
  if (x) delete[] x;
  if (xp) delete[] xp;
  if (y) delete[] y;
  if (xy) delete[] xy;
}

void curve_samples::render (multi_curve* crv) {

  solver ss (crv);	
  float dxx = step, xx = ss.firstx - dxx;
  ss (xx, dxx, n, y);

  float dx = 0.0f;
  box<float> bbox; crv->calc_bbox (bbox);
  for (int i = 0; i < n; ++i) {
    x[i] = bbox.right + dx; 
    dx += step;
  }

  if (crv->shapeform) {
    vector<curve>& curv = crv->curv;
		int ncrvs = curv.size ();
    int pid = 0, cid = 0;
    double dxp = 0;
    for (int i = 0; i < n;) {
      vector<crvpt>& vpts = curv[cid].vpts;
      vector<crvpt>& dpts = curv[cid].dpts;
			int pid1 = pid+1;
      crvpt& pp = dpts [pid];
      crvpt& pp1 = dpts [pid1];
			double left = pp.x, right = pp1.x;
      if (dxp > right) {
        int last2 = dpts.size () - 2;
        if (++pid > last2) {
					double lastx = curv[cid].dpts[pid].x;
          pid = 0;
          if (++cid >= ncrvs) {
						cid = 0;
						dxp -= lastx;
          }
        }
      } else {
				double delta = right - left; 
				double amt = (dxp - pp.x) * 1.0 / delta;
        crvpt& vp = vpts [pid];
        crvpt& vp1 = vpts [pid1];
        xp[i++] = float (vp.x + amt * (vp1.x - vp.x));
        dxp += step;
      }
    }
  }
}

void curve_samples::draw (curve_editor* ed, multi_curve* crv) {

  glColor3f (1.0f, 0.25f, 0.25f);
  float dx, dxp, dy;
  float ox, oy;
  ed->obj2win (0.0f, 0.0f, ox, oy);

  extern int FPS;
	dm = n * 1.0f / (nperiods * nsec * FPS);  // 1 period in n seconds

	m += dm;
	if (m >= n) {
		if (n_reached == 0) {
			m = n - 1; 
			n_reached = 1;
		} else {
			m = 0; 
			n_reached = 0;
		}
	}

	int j = 0, k = m;
  for (int i = 0; i <= k; ++i) {
    ed->obj2win (x[i], y[i], dx, dy);
    xy[j++] = dx;
    xy[j++] = dy;
  }
	glVertexPointer (2, GL_FLOAT, 0, xy);
  glDrawArrays (GL_LINE_STRIP, 0, k+1);

  if (crv->shapeform) { // mark position

		ed->obj2win (xp[k], y[k], dxp, dy);

    float sh[4];

    sh[0]=dxp;sh[1]=dy;
    glPointSize (6);
			glVertexPointer (2, GL_FLOAT, 0, sh);
    	glDrawArrays (GL_POINTS, 0, 1);
    glPointSize (1);
		sh[0]=dxp;sh[1]=dy;sh[2]=dx;sh[3]=dy;

		glVertexPointer (2, GL_FLOAT, 0, sh);
		glDrawArrays (GL_LINES, 0, 2);

  }

}

void curve_samples::set (float zh, int p) {

  if (zh <= 0) zh = 440;
  if (p <= 0) p = 1;

  nperiods = p;

  hz = zh;
  hz2step (hz, step);

  int oldn = n;
  n = p * (1 + 1.0f / step) + 0.5;

  if (x) {
    if (n > oldn) {
      delete[] x; x = new float [n];
      delete[] xp; xp = new float [n];
      delete[] y; y = new float [n];
      delete[] xy; xy = new float [2 * n];
    }
  } else {
    x = new float [n];
    xp = new float [n];
    y = new float [n];
    xy = new float [2 * n];
  }
  int nsz = sizeof (float) * n;
  memset (x, 0, nsz);
  memset (xp, 0, nsz);
  memset (y, 0, nsz);
  memset (xy, 0, 2 * nsz);
}
