/*
* curve_samples.cc
* DIN Is Noise is copyright (c) 2006-2024 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"
#include "console.h"

extern void hz2step (float&, float&);

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

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

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

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

  towin (ed);

}

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


  extern double FPSNOW;
	dm = n * 1.0 / (nperiods * nsec * FPSNOW);

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

  int k = m + 1;
  for (int j = 0, i = 0; i < k; ++i) {
    xy[j++] = xw[i];
    xy[j++] = yw[i];
  }

  glColor3f (1.0f, 0.25f, 0.25f);

  if (k > 2) {
    glVertexPointer (2, GL_FLOAT, 0, xy);
    glDrawArrays (GL_LINE_STRIP, 0, k);
    if (crv->shapeform) { // mark position

      float dxp = 0.0f;
      int k1 = k - 1;
      ed->objx2winx (xp[k1], dxp);

      float ye = yw[k1];
      glBegin (GL_LINES);
        glVertex2i (dxp, ye);
        glVertex2i (xw[k1], ye);
      glEnd ();

      glPointSize (6);
        glBegin (GL_POINTS);
          glVertex2i (dxp, ye);
        glEnd ();
      glPointSize (1);

    }
  }

}

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.0f / step + 1;

  if (x) {
    if (n > oldn) {

      delete[] x; 
      delete[] xw;
      x = new float [n]; 
      xw = new float [n];

      delete[] xp; 
      xp = new float [n];

      delete[] y; 
      delete[] yw;
      y = new float [n]; 
      yw = new float [n];

      delete[] xy; 
      xy = new float [2 * n];

    }
  } else {

    x = new float [n];
    xw = new float [n];
    xp = new float [n];

    y = new float [n];
    yw = new float [n];
    xy = new float [2 * n];

  }
  int nsz = sizeof (float) * n;
  memset (x, 0, nsz);
  memset (xw, 0, nsz);
  memset (xp, 0, nsz);
  memset (y, 0, nsz);
  memset (yw, 0, nsz);
  memset (xy, 0, 2 * nsz);
}

void curve_samples::towin (curve_editor* ed) {
  ed->obj2win (x, y, xw, yw, n);
}
