Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "toonz/strokegenerator.h"
Toshihiro Shimizu 890ddd
//#include "tofflinegl.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Jeremy Bullock 7f2044
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace std;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeGenerator::clear() {
Shinya Kitaoka 120a6e
  m_points.clear();
shun-iwasawa 3c83df
  m_modifiedRegion = TRectD();
shun-iwasawa 3c83df
  m_lastPointRect.empty();
shun-iwasawa 3c83df
  m_lastModifiedRegion.empty();
Shinya Kitaoka 120a6e
  m_paintedPointCount = 0;
Shinya Kitaoka 120a6e
  m_p0 = m_p1 = TPointD();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool StrokeGenerator::isEmpty() const { return m_points.empty(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
fa009d
bool StrokeGenerator::add(const TThickPoint &point, double pixelSize2) {
Shinya Kitaoka 120a6e
  if (m_points.empty()) {
Shinya Kitaoka 120a6e
    double x = point.x, y = point.y, d = point.thick + 3;
Shinya Kitaoka 120a6e
    m_points.push_back(point);
Shinya Kitaoka 120a6e
    TRectD rect(x - d, y - d, x + d, y + d);
fa009d
    m_modifiedRegion     += rect;
fa009d
    m_lastPointRect      += rect;
fa009d
    m_lastModifiedRegion += rect;
Shinya Kitaoka 120a6e
    m_p0 = m_p1 = point;
fa009d
    return true;
fa009d
  }
fa009d
fa009d
  TThickPoint lastPoint = m_points.back();
fa009d
  if (tdistance2(lastPoint, point) >= 4 * pixelSize2) {
fa009d
    m_points.push_back(point);
fa009d
    double d = std::max(point.thick, lastPoint.thick) + 3;
fa009d
    TRectD rect(TRectD(lastPoint, point).enlarge(d));
fa009d
    m_modifiedRegion += rect;
fa009d
    m_lastModifiedRegion += rect;
fa009d
    m_lastPointRect = rect;
fa009d
    return true;
fa009d
  }
fa009d
  
fa009d
  m_points.back().thick = std::max(m_points.back().thick, point.thick);
fa009d
  return false;
fa009d
}
fa009d
fa009d
//-------------------------------------------------------------------
fa009d
fa009d
void StrokeGenerator::pop() {
fa009d
  if (!m_points.empty()) {
fa009d
    TRectD rect;
fa009d
    TThickPoint point = m_points.back();
fa009d
    m_points.pop_back();
fa009d
    if (!m_points.empty()) {
fa009d
      const TThickPoint &lastPoint = m_points.back();
Shinya Kitaoka 120a6e
      double d = std::max(point.thick, lastPoint.thick) + 3;
fa009d
      rect = TRectD(lastPoint, point).enlarge(d);
Shinya Kitaoka 120a6e
    } else {
fa009d
      double x = point.x, y = point.y, d = point.thick + 3;
fa009d
      rect = TRectD(x - d, y - d, x + d, y + d);
Shinya Kitaoka 120a6e
    }
fa009d
    m_modifiedRegion += rect;
fa009d
    m_lastModifiedRegion += rect;
fa009d
    m_lastPointRect = rect;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
fa009d
void StrokeGenerator::setLoop(bool loop)
fa009d
  { m_loop = loop; }
fa009d
fa009d
//-------------------------------------------------------------------
fa009d
Shinya Kitaoka 120a6e
void StrokeGenerator::filterPoints() {
Shinya Kitaoka 120a6e
  if (m_points.size() < 10) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  filtra m_points iniziali: generalmente elevate variazioni di thickness
Shinya Kitaoka 120a6e
  //  si hanno tra m_points[0] (al massimo m_points[1]) e i successivi)
Shinya Kitaoka 120a6e
  int size1 = m_points.size();
Shinya Kitaoka 120a6e
  int kMin  = 0;
Shinya Kitaoka 120a6e
  int kMax  = std::min(
Shinya Kitaoka 120a6e
      4,
Shinya Kitaoka 120a6e
      size1 -
Shinya Kitaoka 120a6e
          2);  //  confronta 5 m_points iniziali con i successivi corrispondenti
Shinya Kitaoka 120a6e
  int k = kMax;
Shinya Kitaoka 120a6e
  for (k = kMax; k >= kMin; --k) {
Shinya Kitaoka 120a6e
    TThickPoint currPoint = m_points[k];
Shinya Kitaoka 120a6e
    TThickPoint nextPoint = m_points[k + 1];
Shinya Kitaoka 120a6e
    double dist           = tdistance(currPoint, nextPoint);
Shinya Kitaoka 120a6e
    double deltaThick     = fabs(currPoint.thick - nextPoint.thick);
Shinya Kitaoka 120a6e
    if (deltaThick > 0.6 * dist)  //  deltaThick <= dist (condizione
Shinya Kitaoka 120a6e
                                  //  approssimata di non-autocontenimento per
Shinya Kitaoka 120a6e
                                  //  TTQ)
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      vector<tthickpoint>::iterator it1 = m_points.begin();</tthickpoint>
Shinya Kitaoka 120a6e
      vector<tthickpoint>::iterator it2 = it1 + k + 1;</tthickpoint>
Shinya Kitaoka 120a6e
      m_points.erase(it1, it2);  //  cancella da m_points[0] a m_points[k]
Shinya Kitaoka 120a6e
      assert((int)m_points.size() == size1 - k - 1);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  //  filtra m_points finali: generalmente elevate variazioni di thickness
Shinya Kitaoka 120a6e
  //  si hanno tra m_points[size - 1] (al massimo m_points[size - 2]) e i
Shinya Kitaoka 120a6e
  //  predecessori)
Shinya Kitaoka 120a6e
  int size2 = m_points.size();
Shinya Kitaoka 120a6e
  kMax      = size2 - 1;
Shinya Kitaoka 120a6e
  kMin      = std::max(
Shinya Kitaoka 120a6e
      kMax - 4,
Shinya Kitaoka 120a6e
      1);  //  confronta 5 m_points finali con i predecessori corrispondenti
Shinya Kitaoka 120a6e
  k = kMin;
Shinya Kitaoka 120a6e
  for (k = kMin; k <= kMax; ++k) {
Shinya Kitaoka 120a6e
    TThickPoint currPoint = m_points[k];
Shinya Kitaoka 120a6e
    TThickPoint prevPoint = m_points[k - 1];
Shinya Kitaoka 120a6e
    double dist           = tdistance(currPoint, prevPoint);
Shinya Kitaoka 120a6e
    double deltaThick     = fabs(currPoint.thick - prevPoint.thick);
Shinya Kitaoka 120a6e
    if (deltaThick > 0.6 * dist)  //  deltaThick <= dist (condizione
Shinya Kitaoka 120a6e
                                  //  approssimata di non-autocontenimento per
Shinya Kitaoka 120a6e
                                  //  TTQ)
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      int kTmp = k;
Shinya Kitaoka 120a6e
      while (k <= kMax)  //  cancella da m_points[k] a m_points[size2 - 1]
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        m_points.pop_back();
Shinya Kitaoka 120a6e
        ++k;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      assert((int)m_points.size() == size2 - (kMax - kTmp + 1));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeGenerator::drawFragments(int first, int last) {
Shinya Kitaoka 120a6e
  if (m_points.empty()) return;
Shinya Kitaoka 120a6e
  int i                                  = first;
Shinya Kitaoka 120a6e
  if (last >= (int)m_points.size()) last = m_points.size() - 1;
Shinya Kitaoka 120a6e
  TThickPoint a;
Shinya Kitaoka 120a6e
  TThickPoint b;
Shinya Kitaoka 120a6e
  TThickPoint c;
Shinya Kitaoka 120a6e
  TPointD v;
Shinya Kitaoka 120a6e
Jeremy Bullock 7f2044
  // If drawing a straight line, a stroke can have only two points
Jeremy Bullock 7f2044
  if (m_points.size() == 2) {
Jeremy Bullock 7f2044
    a = m_points[0];
Jeremy Bullock 7f2044
    b = m_points[1];
Jeremy Bullock 7f2044
    if (Preferences::instance()->getShow0ThickLines()) {
Jeremy Bullock 7f2044
      if (a.thick == 0) a.thick = 0.1;
Jeremy Bullock 7f2044
      if (b.thick == 0) b.thick = 0.1;
Jeremy Bullock 7f2044
    }
Jeremy Bullock 7f2044
    // m_p0 = m_p1 = b;
fa009d
    v          = a.thick * normalizeOrZero(rotate90(b - a));
Jeremy Bullock 7f2044
    m_p0       = a + v;
Jeremy Bullock 7f2044
    m_p1       = a - v;
fa009d
    v          = b.thick * normalizeOrZero(rotate90(b - a));
Jeremy Bullock 7f2044
    TPointD p0 = b + v;
Jeremy Bullock 7f2044
    TPointD p1 = b - v;
Jeremy Bullock 7f2044
    glBegin(GL_POLYGON);
Jeremy Bullock 7f2044
    tglVertex(m_p0);
Jeremy Bullock 7f2044
    tglVertex(m_p1);
Jeremy Bullock 7f2044
    tglVertex(p1);
Jeremy Bullock 7f2044
    tglVertex(p0);
Jeremy Bullock 7f2044
    glEnd();
Jeremy Bullock 7f2044
    m_p0 = p0;
Jeremy Bullock 7f2044
    m_p1 = p1;
Jeremy Bullock 7f2044
    glBegin(GL_LINE_STRIP);
Jeremy Bullock 7f2044
    tglVertex(a);
Jeremy Bullock 7f2044
    tglVertex(b);
Jeremy Bullock 7f2044
    glEnd();
Jeremy Bullock 7f2044
    return;
Jeremy Bullock 7f2044
  }
Jeremy Bullock 7f2044
Shinya Kitaoka 120a6e
  while (i < last) {
Shinya Kitaoka 120a6e
    a = m_points[i - 1];
Shinya Kitaoka 120a6e
    b = m_points[i];
Shinya Kitaoka 120a6e
    c = m_points[i + 1];
Jeremy Bullock 7f2044
    if (Preferences::instance()->getShow0ThickLines()) {
Jeremy Bullock 7f2044
      if (a.thick == 0) a.thick = 0.1;
Jeremy Bullock 7f2044
      if (b.thick == 0) b.thick = 0.1;
Jeremy Bullock 7f2044
      if (c.thick == 0) c.thick = 0.1;
Jeremy Bullock 7f2044
    }
shun-iwasawa 1fde39
    if (i - 1 == 0) {
fa009d
      v    = a.thick * normalizeOrZero(rotate90(b - a));
shun-iwasawa 1fde39
      m_p0 = a + v;
shun-iwasawa 1fde39
      m_p1 = a - v;
Shinya Kitaoka 120a6e
    }
fa009d
    v          = b.thick * normalizeOrZero(rotate90(c - a));
shun-iwasawa 1fde39
    TPointD p0 = b + v;
shun-iwasawa 1fde39
    TPointD p1 = b - v;
shun-iwasawa 1fde39
    glBegin(GL_POLYGON);
shun-iwasawa 1fde39
    tglVertex(m_p0);
shun-iwasawa 1fde39
    tglVertex(m_p1);
shun-iwasawa 1fde39
    tglVertex(p1);
shun-iwasawa 1fde39
    tglVertex(p0);
shun-iwasawa 1fde39
    glEnd();
shun-iwasawa 1fde39
    m_p0 = p0;
shun-iwasawa 1fde39
    m_p1 = p1;
shun-iwasawa 1fde39
Shinya Kitaoka 120a6e
    glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
    tglVertex(a);
Shinya Kitaoka 120a6e
    tglVertex(b);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
    i++;
Shinya Kitaoka 120a6e
  }
shun-iwasawa 1fde39
  if (last < 2) return;
shun-iwasawa 1fde39
  v = m_points[last].thick *
fa009d
      normalizeOrZero(rotate90(m_points[last] - m_points[last - 1]));
shun-iwasawa 1fde39
  TPointD p0 = m_points[last] + v;
shun-iwasawa 1fde39
  TPointD p1 = m_points[last] - v;
shun-iwasawa 1fde39
  glBegin(GL_POLYGON);
shun-iwasawa 1fde39
  tglVertex(m_p0);
shun-iwasawa 1fde39
  tglVertex(m_p1);
shun-iwasawa 1fde39
  tglVertex(p1);
shun-iwasawa 1fde39
  tglVertex(p0);
shun-iwasawa 1fde39
  glEnd();
shun-iwasawa 1fde39
  glBegin(GL_LINE_STRIP);
shun-iwasawa 1fde39
  tglVertex(m_points[last - 1]);
shun-iwasawa 1fde39
  tglVertex(m_points[last]);
shun-iwasawa 1fde39
  glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeGenerator::drawLastFragments() {
Shinya Kitaoka 120a6e
  if (m_points.empty()) return;
Shinya Kitaoka 120a6e
  int n          = m_points.size();
Shinya Kitaoka 120a6e
  int i          = m_paintedPointCount;
Shinya Kitaoka 120a6e
  const double h = 0.01;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (i == 0) {
Shinya Kitaoka 120a6e
    TThickPoint a = m_points[0];
Shinya Kitaoka 120a6e
    if (a.thick >= h) tglDrawDisk(a, a.thick);
Shinya Kitaoka 120a6e
    i++;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  drawFragments(i, n - 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_paintedPointCount = std::max(0, n - 2);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeGenerator::drawAllFragments() {
Shinya Kitaoka 120a6e
  if (m_points.empty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int n          = m_points.size();
Shinya Kitaoka 120a6e
  int i          = 0;
Shinya Kitaoka 120a6e
  const double h = 0.01;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickPoint a = m_points[0];
Shinya Kitaoka 120a6e
  if (a.thick >= h) tglDrawDisk(a, a.thick);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  drawFragments(1, n - 1);
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
//last fragment
Shinya Kitaoka 120a6e
TPointD p0 = c+v;
Shinya Kitaoka 120a6e
TPointD p1 = c-v;
Shinya Kitaoka 120a6e
glBegin(GL_POLYGON);
Shinya Kitaoka 120a6e
tglVertex(m_p0);
Shinya Kitaoka 120a6e
tglVertex(m_p1);
Shinya Kitaoka 120a6e
tglVertex(p1);
Shinya Kitaoka 120a6e
tglVertex(p0);
Shinya Kitaoka 120a6e
glEnd();
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
  a = m_points.back();
Shinya Kitaoka 120a6e
  if (a.thick >= h) tglDrawDisk(a, a.thick);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TRectD StrokeGenerator::getModifiedRegion() const { return m_modifiedRegion; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Jeremy Bullock 7f2044
void StrokeGenerator::removeMiddlePoints() {
Jeremy Bullock 7f2044
  int size = m_points.size();
Jeremy Bullock 7f2044
  if (size > 2) {
Jeremy Bullock 7f2044
    m_points.erase(m_points.begin() + 1, m_points.begin() + (size - 1));
Jeremy Bullock 7f2044
  }
Jeremy Bullock 7f2044
}
Jeremy Bullock 7f2044
Jeremy Bullock 7f2044
//-------------------------------------------------------------------
Jeremy Bullock 7f2044
shun-iwasawa 1fde39
TRectD StrokeGenerator::getLastModifiedRegion() {
shun-iwasawa 1fde39
  TRectD ret           = m_lastModifiedRegion;
shun-iwasawa 1fde39
  m_lastModifiedRegion = m_lastPointRect;
shun-iwasawa 1fde39
  return ret;
shun-iwasawa 1fde39
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Jeremy Bullock cd00fd
TPointD StrokeGenerator::getFirstPoint() { return m_points[0]; }
Jeremy Bullock cd00fd
Jeremy Bullock cd00fd
//-------------------------------------------------------------------
Jeremy Bullock cd00fd
fa009d
TStroke *StrokeGenerator::makeStroke(double error, UINT onlyLastPoints, bool useLoop) const {
Shinya Kitaoka 120a6e
  if (onlyLastPoints == 0 || onlyLastPoints > m_points.size())
Shinya Kitaoka 120a6e
    return TStroke::interpolate(m_points, error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vector<tthickpoint> lastPoints(onlyLastPoints);</tthickpoint>
Shinya Kitaoka 120a6e
  vector<tthickpoint>::const_iterator first =</tthickpoint>
Shinya Kitaoka 120a6e
      m_points.begin() + (m_points.size() - onlyLastPoints);
Shinya Kitaoka 120a6e
  copy(first, m_points.end(), lastPoints.begin());
Toshihiro Shimizu 890ddd
fa009d
  TStroke *stroke = TStroke::interpolate(lastPoints, error);
fa009d
  if (useLoop) stroke->setSelfLoop(m_loop);
fa009d
  return stroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------