Blob Blame Raw

#include <tools/replicator.h>

#include <tools/tool.h>

#include <toonz/tapplication.h>
#include <toonz/txsheet.h>
#include <toonz/txsheethandle.h>
#include <toonz/txshlevelhandle.h>
#include <toonz/tframehandle.h>
#include <toonz/tobjecthandle.h>
#include <toonz/dpiscale.h>

#include <tgl.h>



const int TReplicator::multiplierSoftLimit = 32;
const int TReplicator::multiplierLimit = 256;


//************************************************************************
//    TReplicator implementation
//************************************************************************

TReplicator::TReplicator(TMetaObject &object):
  TAssistantBase(object) { }

//---------------------------------------------------------------------------------------------------

int
TReplicator::getMultipler() const
  { return 1; }

//---------------------------------------------------------------------------------------------------

void
TReplicator::getModifiers(const TAffine&, TInputModifier::List&) const
  { }

//---------------------------------------------------------------------------------------------------

void
TReplicator::getPoints(const TAffine&, PointList&) const
  { }

//---------------------------------------------------------------------------------------------------

TIntProperty*
TReplicator::createCountProperty(const TStringId &id, int def, int min, int max) {
  if (min < 0) min = 0;
  if (def < min) def = min;
  if (max <= 0) max = multiplierSoftLimit;
  assert(min < max && def < max);
  TIntProperty *property = new TIntProperty(id.str(), min, max, def);
  property->setSpinner();
  return property;
}

//---------------------------------------------------------------------------------------------------

void
TReplicator::transformPoints(const TAffine &aff, PointList &points, int count) {
  points.reserve(points.size() + count);
  for(int i = 0; i < count; ++i)
    points.push_back(aff*points[i]);
}

//---------------------------------------------------------------------------------------------------

void
TReplicator::drawReplicatorPoints(const TPointD *points, int count) {
  double colorBlack[4] = { 0.0, 0.0, 0.0, 0.3 };
  double colorWhite[4] = { 1.0, 1.0, 1.0, 0.3 };
  
  glPushAttrib(GL_ALL_ATTRIB_BITS);
  tglEnableBlending();
  tglEnableLineSmooth(true, 1.0 * lineWidthScale);
  
  double pixelSize = sqrt(tglGetPixelSize2());
  TPointD a(5*pixelSize, 0), da(0, 0.5*pixelSize);
  TPointD b(0, 5*pixelSize), db(0.5*pixelSize, 0);
  
  for(int i = 0; i < count; ++i) {
    const TPointD &p = points[i];
    glColor4dv(colorWhite);
    tglDrawSegment(p - a - da, p + a - da);
    tglDrawSegment(p - b - db, p + b - db);
    glColor4dv(colorBlack);
    tglDrawSegment(p - a + da, p + a + da);
    tglDrawSegment(p - b + db, p + b + db);
  }

  glPopAttrib();
}

//---------------------------------------------------------------------------------------------------

int
TReplicator::scanReplicators(
  TTool *tool,
  PointList *inOutPoints,
  TInputModifier::List *outModifiers,
  bool draw,
  bool enabledOnly,
  bool markEnabled,
  bool drawPoints,
  TImage *skipImage )
{
  bool outOfLimit = false;
  long long multiplier = 0;
  int inputPoints = inOutPoints ? (int)inOutPoints->size() : 0;
  
  if (tool)
  if (TToolViewer *viewer = tool->getViewer())
  if (TApplication *application = tool->getApplication())
  if (TXshLevelHandle *levelHandle = application->getCurrentLevel())
  if (TXshLevel *level = levelHandle->getLevel())
  if (TXshSimpleLevel *simpleLevel = level->getSimpleLevel())
  if (TFrameHandle *frameHandle = application->getCurrentFrame())
  if (TXsheetHandle *XsheetHandle = application->getCurrentXsheet())
  if (TXsheet *Xsheet = XsheetHandle->getXsheet())
  {
    TPointD dpiScale = getCurrentDpiScale(simpleLevel, tool->getCurrentFid());
    int frame = frameHandle->getFrame();
    int count = Xsheet->getColumnCount();
    TAffine worldToTrack;
    if ( tool->getToolType() & TTool::LevelTool
      && !application->getCurrentObject()->isSpline() )
    {
      worldToTrack.a11 /= dpiScale.x;
      worldToTrack.a22 /= dpiScale.y;
    }

    for(int i = 0; i < count; ++i)
      if (TXshColumn *column = Xsheet->getColumn(i))
      if (column->isCamstandVisible())
      if (column->isPreviewVisible())
      if (TImageP image = Xsheet->getCell(frame, i).getImage(false))
      if (image != skipImage)
      if (image->getType() == TImage::META)
      if (TMetaImage *metaImage = dynamic_cast<TMetaImage*>(image.getPointer()))
      {
        TAffine imageToTrack = worldToTrack * tool->getColumnMatrix(i);
        if (draw) { glPushMatrix(); tglMultMatrix(imageToTrack); }

        TMetaImage::Reader reader(*metaImage);
        for(TMetaObjectListCW::iterator i = reader->begin(); i != reader->end(); ++i)
          if (*i)
          if (const TReplicator *replicator = (*i)->getHandler<TReplicator>())
          if (!enabledOnly || replicator->getEnabled())
          {
            if (!multiplier) multiplier = 1;
            bool enabled = replicator->getEnabled();
            
            if (enabled) {
              int m = replicator->getMultipler();
              if (m <= 0) m = 1;
              if (multiplier*m > multiplierLimit) {
                outOfLimit = true;
              } else {
                multiplier *= m;
                if (inOutPoints)
                  replicator->getPoints(imageToTrack, *inOutPoints);
                if (outModifiers)
                  replicator->getModifiers(imageToTrack, *outModifiers);
              }
            }
            
            if (draw) {
              unsigned int oldFlags = TReplicator::drawFlags;
              if (enabled && outOfLimit) TReplicator::drawFlags |= TReplicator::DRAW_ERROR;
              replicator->draw(viewer, enabled && markEnabled);
              TReplicator::drawFlags = oldFlags;
            }
          }

        if (draw) glPopMatrix();
      }
  }
  
  
  if (drawPoints && inOutPoints && (int)inOutPoints->size() > inputPoints)
    drawReplicatorPoints(
      inOutPoints->data() + inputPoints,
      (int)inOutPoints->size() - inputPoints );
  
  return (int)multiplier;
}