Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tofflinegl.h"
Toshihiro Shimizu 890ddd
#include "tstencilcontrol.h"
Toshihiro Shimizu 890ddd
#include "tvectorgl.h"
Toshihiro Shimizu 890ddd
#include "tvectorrenderdata.h"
Toshihiro Shimizu 890ddd
#include "tcolorfunctions.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tmeshimage.h"
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "timage_io.h"
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzExt includes
Toshihiro Shimizu 890ddd
#include "ext/meshutils.h"
Toshihiro Shimizu 890ddd
#include "ext/plasticskeleton.h"
Toshihiro Shimizu 890ddd
#include "ext/plasticskeletondeformation.h"
Toshihiro Shimizu 890ddd
#include "ext/plasticdeformerstorage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/stageplayer.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage2.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheet.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshchildlevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/onionskinmask.h"
Toshihiro Shimizu 890ddd
#include "toonz/dpiscale.h"
Toshihiro Shimizu 890ddd
#include "toonz/imagemanager.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjecttree.h"
Toshihiro Shimizu 890ddd
#include "toonz/glrasterpainter.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
#include "toonz/fill.h"
Toshihiro Shimizu 890ddd
#include "toonz/levelproperties.h"
Toshihiro Shimizu 890ddd
#include "toonz/autoclose.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshleveltypes.h"
Toshihiro Shimizu 890ddd
#include "imagebuilders.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qimage></qimage>
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Toshihiro Shimizu 890ddd
#include <qpolygon></qpolygon>
Toshihiro Shimizu 890ddd
#include <qthreadstorage></qthreadstorage>
Toshihiro Shimizu 890ddd
#include <qmatrix></qmatrix>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/stagevisitor.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    Stage namespace
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \namespace Stage
Shinya Kitaoka 120a6e
    \brief The Stage namespace provides objects, classes and methods useful to
Shinya Kitaoka 120a6e
   view or display images.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace Stage;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \var Stage::inch
Shinya Kitaoka 120a6e
                For historical reasons camera stand is defined in a coordinate
Shinya Kitaoka 120a6e
   system in which
Shinya Kitaoka 120a6e
                an inch is equal to 'Stage::inch' unit.
Shinya Kitaoka 120a6e
                Pay attention: modify this value condition apparent line
Shinya Kitaoka 120a6e
   thickness of
Shinya Kitaoka 120a6e
                images .pli.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
// const double Stage::inch = 53.33333;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QImage rasterToQImage(const TRaster32P &ras) {
Shinya Kitaoka 120a6e
  QImage image(ras->getRawData(), ras->getLx(), ras->getLy(),
Shinya Kitaoka 120a6e
               QImage::Format_ARGB32_Premultiplied);
Shinya Kitaoka 120a6e
  return image;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QImage rasterToQImage(const TRasterGR8P &ras) {
Shinya Kitaoka 120a6e
  QImage image(ras->getLx(), ras->getLy(), QImage::Format_ARGB32_Premultiplied);
Shinya Kitaoka 120a6e
  int lx = ras->getLx(), ly = ras->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int y = 0; y < ly; y++) {
Shinya Kitaoka 120a6e
    TPixelGR8 *pix    = ras->pixels(y);
Shinya Kitaoka 120a6e
    TPixelGR8 *endPix = pix + lx;
Shinya Kitaoka 120a6e
    QRgb *outPix      = (QRgb *)image.scanLine(y);
Shinya Kitaoka 120a6e
    for (; pix < endPix; ++pix) {
Shinya Kitaoka 120a6e
      int value = pix->value;
Shinya Kitaoka 120a6e
      *outPix++ = qRgba(value, value, value, 255);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return image;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QImage rasterToQImage(const TRasterP &ras) {
Shinya Kitaoka 120a6e
  if (TRaster32P src32 = ras)
Shinya Kitaoka 120a6e
    return rasterToQImage(src32);
Shinya Kitaoka 120a6e
  else if (TRasterGR8P srcGr8 = ras)
Shinya Kitaoka 120a6e
    return rasterToQImage(srcGr8);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // assert(!"Cannot use drawImage with this image!");
Shinya Kitaoka 120a6e
  return QImage();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Draw orthogonal projection of \b bbox onto x-axis and y-axis.
Shinya Kitaoka 120a6e
void draw3DShadow(const TRectD &bbox, double z, double phi) {
Shinya Kitaoka 120a6e
  // bruttino assai, ammetto
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double a = bigBoxSize[0];
Shinya Kitaoka 120a6e
  double b = bigBoxSize[1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glColor3d(0.9, 0.9, 0.86);
Shinya Kitaoka 120a6e
  glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x0, bbox.y0, z);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x0, bbox.y1, z);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x1, bbox.y1, z);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x1, bbox.y0, z);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x0, bbox.y0, z);
Shinya Kitaoka 120a6e
  glEnd();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double y = -b;
Shinya Kitaoka 120a6e
  double x = phi >= 0 ? a : -a;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double xm = 0.5 * (bbox.x0 + bbox.x1);
Shinya Kitaoka 120a6e
  double ym = 0.5 * (bbox.y0 + bbox.y1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bbox.y0 > y) {
Shinya Kitaoka 120a6e
    glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
    glVertex3d(xm, y, z);
Shinya Kitaoka 120a6e
    glVertex3d(xm, bbox.y0, z);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
  } else if (bbox.y1 < y) {
Shinya Kitaoka 120a6e
    glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
    glVertex3d(xm, y, z);
Shinya Kitaoka 120a6e
    glVertex3d(xm, bbox.y1, z);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (bbox.x0 > x) {
Shinya Kitaoka 120a6e
    glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
    glVertex3d(x, ym, z);
Shinya Kitaoka 120a6e
    glVertex3d(bbox.x0, ym, z);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
  } else if (bbox.x1 < x) {
Shinya Kitaoka 120a6e
    glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
    glVertex3d(x, ym, z);
Shinya Kitaoka 120a6e
    glVertex3d(bbox.x1, ym, z);
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glColor3d(0.0, 0.0, 0.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x0, -b, z);
Shinya Kitaoka 120a6e
  glVertex3d(bbox.x1, -b, z);
Shinya Kitaoka 120a6e
  glEnd();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
  glVertex3d(x, bbox.y0, z);
Shinya Kitaoka 120a6e
  glVertex3d(x, bbox.y1, z);
Shinya Kitaoka 120a6e
  glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  Plastic function declarations
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  Returns from the specified player the stage object to be plastic
Toshihiro Shimizu 890ddd
  deformed - or 0 if current Toonz rules prevent it from being deformed.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TStageObject *plasticDeformedObj(const Stage::Player &player,
Shinya Kitaoka 120a6e
                                 const PlasticVisualSettings &pvs);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Draws the specified mesh image
Shinya Kitaoka 120a6e
void onMeshImage(TMeshImage *mi, const Stage::Player &player,
Shinya Kitaoka 120a6e
                 const ImagePainter::VisualSettings &vs,
Shinya Kitaoka 120a6e
                 const TAffine &viewAff);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Applies Plastic deformation of the specified player's stage object.
Shinya Kitaoka 120a6e
void onPlasticDeformedImage(TStageObject *playerObj,
Shinya Kitaoka 120a6e
                            const Stage::Player &player,
Shinya Kitaoka 120a6e
                            const ImagePainter::VisualSettings &vs,
Shinya Kitaoka 120a6e
                            const TAffine &viewAff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    Picker  implementation
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Picker::Picker(const TAffine &viewAff, const TPointD &point,
Shinya Kitaoka 120a6e
               const ImagePainter::VisualSettings &vs)
Shinya Kitaoka 120a6e
    : Visitor(vs)
Shinya Kitaoka 120a6e
    , m_viewAff(viewAff)
Shinya Kitaoka 120a6e
    , m_point(point)
Shinya Kitaoka 120a6e
    , m_columnIndexes()
Shinya Kitaoka 120a6e
    , m_minDist2(1.0e10) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::setDistance(double d) { m_minDist2 = d * d; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::onImage(const Stage::Player &player) {
Shinya Kitaoka 120a6e
  bool picked   = false;
Shinya Kitaoka 120a6e
  TAffine aff   = m_viewAff * player.m_placement;
Shinya Kitaoka 120a6e
  TPointD point = aff.inv() * m_point;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TImageP &img = player.image();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (TVectorImageP vi = img) {
Shinya Kitaoka 120a6e
    double w         = 0;
Shinya Kitaoka 120a6e
    UINT strokeIndex = 0;
Shinya Kitaoka 120a6e
    double dist2     = 0;
Shinya Kitaoka 120a6e
    TRegion *r       = vi->getRegion(point);
Shinya Kitaoka 120a6e
    int styleId      = 0;
Shinya Kitaoka 120a6e
    if (r) styleId   = r->getStyle();
Shinya Kitaoka 120a6e
    if (styleId != 0)
Shinya Kitaoka 120a6e
      picked = true;
Shinya Kitaoka 120a6e
    else if (vi->getNearestStroke(point, w, strokeIndex, dist2) &&
Shinya Kitaoka 120a6e
             dist2 < m_minDist2)
Shinya Kitaoka 120a6e
      picked = true;
Shinya Kitaoka 120a6e
  } else if (TRasterImageP ri = img) {
Shinya Kitaoka 120a6e
    TRaster32P ras = ri->getRaster();
Shinya Kitaoka 120a6e
    if (!ras) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ras->lock();
Shinya Kitaoka 120a6e
    TPointD pp = player.m_dpiAff.inv() * point + ras->getCenterD();
Shinya Kitaoka 120a6e
    TPoint p(tround(pp.x), tround(pp.y));
Shinya Kitaoka 120a6e
    if (!ras->getBounds().contains(p)) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPixel32 *pix               = ras->pixels(p.y);
Shinya Kitaoka 120a6e
    if (pix[p.x].m != 0) picked = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TAffine aff2 = (aff * player.m_dpiAff).inv();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD pa(p.x, p.y);
Shinya Kitaoka 120a6e
    TPointD dx = aff2 * (m_point + TPointD(3, 0)) - aff2 * m_point;
Shinya Kitaoka 120a6e
    TPointD dy = aff2 * (m_point + TPointD(0, 3)) - aff2 * m_point;
Shinya Kitaoka 120a6e
    double rx  = dx.x * dx.x + dx.y * dx.y;
Shinya Kitaoka 120a6e
    double ry  = dy.x * dy.x + dy.y * dy.y;
Shinya Kitaoka 120a6e
    int radius = tround(sqrt(rx > ry ? rx : ry));
Shinya Kitaoka 120a6e
    TRect rect = TRect(p.x - radius, p.y - radius, p.x + radius, p.y + radius) *
Shinya Kitaoka 120a6e
                 ras->getBounds();
Shinya Kitaoka 120a6e
    for (int y = rect.y0; !picked && y <= rect.y1; y++) {
Shinya Kitaoka 120a6e
      pix = ras->pixels(y);
Shinya Kitaoka 120a6e
      for (int x                  = rect.x0; !picked && x <= rect.x1; x++)
Shinya Kitaoka 120a6e
        if (pix[x].m != 0) picked = true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ras->unlock();
Shinya Kitaoka 120a6e
  } else if (TToonzImageP ti = img) {
Shinya Kitaoka 120a6e
    TRasterCM32P ras = ti->getRaster();
Shinya Kitaoka 120a6e
    if (!ras) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ras->lock();
Shinya Kitaoka 120a6e
    TPointD pp = player.m_dpiAff.inv() * point + ras->getCenterD();
Shinya Kitaoka 120a6e
    TPoint p(tround(pp.x), tround(pp.y));
Shinya Kitaoka 120a6e
    if (!ras->getBounds().contains(p)) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPixelCM32 *pix = ras->pixels(p.y) + p.x;
Shinya Kitaoka 120a6e
    if (!pix->isPurePaint() || pix->getPaint() != 0) picked = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ras->unlock();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (picked) {
Shinya Kitaoka 120a6e
    int columnIndex = player.m_ancestorColumnIndex;
Shinya Kitaoka 120a6e
    if (m_columnIndexes.empty() || m_columnIndexes.back() != columnIndex)
Shinya Kitaoka 120a6e
      m_columnIndexes.push_back(columnIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int row = player.m_frame;
Shinya Kitaoka 120a6e
    if (m_rows.empty() || m_rows.back() != row) m_rows.push_back(row);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::beginMask() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::endMask() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::enableMask() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::disableMask() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int Picker::getColumnIndex() const {
Shinya Kitaoka 120a6e
  if (m_columnIndexes.empty())
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return m_columnIndexes.back();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void Picker::getColumnIndexes(std::vector<int> &indexes) const {</int>
Shinya Kitaoka 120a6e
  indexes = m_columnIndexes;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int Picker::getRow() const {
Shinya Kitaoka 120a6e
  if (m_rows.empty())
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return m_rows.back();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    RasterPainter  implementation
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
RasterPainter::RasterPainter(const TDimension &dim, const TAffine &viewAff,
Shinya Kitaoka 120a6e
                             const TRect &rect,
Shinya Kitaoka 120a6e
                             const ImagePainter::VisualSettings &vs,
Shinya Kitaoka 120a6e
                             bool checkFlags)
Shinya Kitaoka 120a6e
    : Visitor(vs)
Shinya Kitaoka 120a6e
    , m_dim(dim)
Shinya Kitaoka 120a6e
    , m_viewAff(viewAff)
Shinya Kitaoka 120a6e
    , m_clipRect(rect)
Shinya Kitaoka 120a6e
    , m_maskLevel(0)
Shinya Kitaoka 120a6e
    , m_singleColumnEnabled(false)
Shinya Kitaoka 120a6e
    , m_checkFlags(checkFlags)
Shinya Kitaoka 120a6e
    , m_doRasterDarkenBlendedView(false) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Utilizzato solo per TAB Pro
Shinya Kitaoka 120a6e
void RasterPainter::beginMask() {
Shinya Kitaoka 120a6e
  flushRasterImages();  // per evitare che venga fatto dopo il beginMask
Shinya Kitaoka 120a6e
  ++m_maskLevel;
Shinya Kitaoka 120a6e
  TStencilControl::instance()->beginMask();
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
//! Utilizzato solo per TAB Pro
Shinya Kitaoka 120a6e
void RasterPainter::endMask() {
Shinya Kitaoka 120a6e
  flushRasterImages();  // se ci sono delle immagini raster nella maschera
Shinya Kitaoka 120a6e
                        // devono uscire ora
Shinya Kitaoka 120a6e
  --m_maskLevel;
Shinya Kitaoka 120a6e
  TStencilControl::instance()->endMask();
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
//! Utilizzato solo per TAB Pro
Shinya Kitaoka 120a6e
void RasterPainter::enableMask() {
Shinya Kitaoka 120a6e
  TStencilControl::instance()->enableMask(TStencilControl::SHOW_INSIDE);
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
//! Utilizzato solo per TAB Pro
Shinya Kitaoka 120a6e
void RasterPainter::disableMask() {
Shinya Kitaoka 120a6e
  flushRasterImages();  // se ci sono delle immagini raster mascherate devono
Shinya Kitaoka 120a6e
                        // uscire ora
Shinya Kitaoka 120a6e
  TStencilControl::instance()->disableMask();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::DoubleVar AutocloseDistance("InknpaintAutocloseDistance", 10.0);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar AutocloseAngle("InknpaintAutocloseAngle", 60.0);
Toshihiro Shimizu 890ddd
TEnv::IntVar AutocloseInk("InknpaintAutocloseInk", 1);
Toshihiro Shimizu 890ddd
TEnv::IntVar AutocloseOpacity("InknpaintAutocloseOpacity", 255);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int RasterPainter::getNodesCount() { return m_nodes.size(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterPainter::clearNodes() { m_nodes.clear(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRasterP RasterPainter::getRaster(int index, QMatrix &matrix) {
Shinya Kitaoka 120a6e
  if ((int)m_nodes.size() <= index) return TRasterP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_nodes[index].m_onionMode != Node::eOnionSkinNone) return TRasterP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_nodes.empty()) return TRasterP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double delta = sqrt(fabs(m_nodes[0].m_aff.det()));
Shinya Kitaoka 120a6e
  TRectD bbox  = m_nodes[0].m_bbox.enlarge(delta);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 1; i < (int)m_nodes.size(); i++) {
Shinya Kitaoka 120a6e
    delta = sqrt(fabs(m_nodes[i].m_aff.det()));
Shinya Kitaoka 120a6e
    bbox += m_nodes[i].m_bbox.enlarge(delta);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TRect rect(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1), tceil(bbox.y1));
Shinya Kitaoka 120a6e
  rect = rect * TRect(0, 0, m_dim.lx - 1, m_dim.ly - 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TAffine aff = TTranslation(-rect.x0, -rect.y0) * m_nodes[index].m_aff;
Shinya Kitaoka 120a6e
  matrix      = QMatrix(aff.a11, aff.a21, aff.a12, aff.a22, aff.a13, aff.a23);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return m_nodes[index].m_raster;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Make frame visualization.
Shinya Kitaoka 120a6e
\n	If onon-skin is active, create a new raster with dimension containing
Shinya Kitaoka 120a6e
all
Shinya Kitaoka 120a6e
                frame with onion-skin; recall \b TRop::quickPut with argument
Shinya Kitaoka 120a6e
each frame
Shinya Kitaoka 120a6e
                with onion-skin and new raster. If onion-skin is not active
Shinya Kitaoka 120a6e
recall
Shinya Kitaoka 120a6e
                \b TRop::quickPut with argument current frame and new raster.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
QThreadStorage<std::vector<char> *> threadBuffers;</std::vector<char>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterPainter::flushRasterImages() {
Shinya Kitaoka 120a6e
  if (m_nodes.empty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build nodes bbox union
Shinya Kitaoka 120a6e
  double delta = sqrt(fabs(m_nodes[0].m_aff.det()));
Shinya Kitaoka 120a6e
  TRectD bbox  = m_nodes[0].m_bbox.enlarge(delta);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i, nodesCount = m_nodes.size();
Shinya Kitaoka 120a6e
  for (i = 1; i < nodesCount; ++i) {
Shinya Kitaoka 120a6e
    delta = sqrt(fabs(m_nodes[i].m_aff.det()));
Shinya Kitaoka 120a6e
    bbox += m_nodes[i].m_bbox.enlarge(delta);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRect rect(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1), tceil(bbox.y1));
Shinya Kitaoka 120a6e
  rect = rect * TRect(0, 0, m_dim.lx - 1, m_dim.ly - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int lx = rect.getLx(), ly = rect.getLy();
Shinya Kitaoka 120a6e
  TDimension dim(lx, ly);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build a raster buffer of sufficient size to hold said union.
Shinya Kitaoka 120a6e
  // The buffer is per-thread cached in order to improve the rendering speed.
Shinya Kitaoka 120a6e
  if (!threadBuffers.hasLocalData())
Shinya Kitaoka 120a6e
    threadBuffers.setLocalData(new std::vector<char>());</char>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int size = dim.lx * dim.ly * sizeof(TPixel32);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<char> *vbuff = (std::vector<char> *)threadBuffers.localData();</char></char>
Shinya Kitaoka 120a6e
  if (size > (int)vbuff->size()) vbuff->resize(size);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRaster32P ras(dim.lx, dim.ly, dim.lx, (TPixel32 *)&(*vbuff)[0]);
Shinya Kitaoka 120a6e
  TRaster32P ras2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_vs.m_colorMask != 0) {
Shinya Kitaoka 120a6e
    ras2 = TRaster32P(ras->getSize());
Shinya Kitaoka 120a6e
    ras->clear();
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    ras2 = ras;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Clear the buffer - it will hold all the stacked nodes content to be overed
Shinya Kitaoka 120a6e
  // on top of the OpenGL buffer through a glDrawPixel()
Shinya Kitaoka 120a6e
  ras->lock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ras->clear();  // ras is typically reused - and we need it transparent first
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRect r                 = rect - rect.getP00();
Shinya Kitaoka 120a6e
  TRaster32P viewedRaster = ras->extract(r);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int current = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Retrieve preferences-related data
Shinya Kitaoka 120a6e
  int tc    = m_checkFlags ? ToonzCheck::instance()->getChecks() : 0;
Shinya Kitaoka 120a6e
  int index = ToonzCheck::instance()->getColorIndex();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPixel32 frontOnionColor, backOnionColor;
Shinya Kitaoka 120a6e
  bool onionInksOnly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Preferences::instance()->getOnionData(frontOnionColor, backOnionColor,
Shinya Kitaoka 120a6e
                                        onionInksOnly);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Stack every node on top of the raster buffer
Shinya Kitaoka 120a6e
  for (i = 0; i < nodesCount; ++i) {
Shinya Kitaoka 120a6e
    if (m_nodes[i].m_isCurrentColumn) current = i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TAffine aff         = TTranslation(-rect.x0, -rect.y0) * m_nodes[i].m_aff;
Shinya Kitaoka 120a6e
    TDimension imageDim = m_nodes[i].m_raster->getSize();
Shinya Kitaoka 120a6e
    TPointD offset(0.5, 0.5);
Shinya Kitaoka 120a6e
    aff *= TTranslation(offset);  // very quick and very dirty fix: in
Shinya Kitaoka 120a6e
                                  // camerastand the images seems shifted of an
Shinya Kitaoka 120a6e
                                  // half pixel...it's a quickput approximation?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPixel32 colorscale = TPixel32(0, 0, 0, m_nodes[i].m_alpha);
Shinya Kitaoka 120a6e
    int inksOnly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_nodes[i].m_onionMode != Node::eOnionSkinNone) {
Shinya Kitaoka 120a6e
      inksOnly = onionInksOnly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (m_nodes[i].m_onionMode == Node::eOnionSkinFront)
Shinya Kitaoka 120a6e
        colorscale = TPixel32(frontOnionColor.r, frontOnionColor.g,
Shinya Kitaoka 120a6e
                              frontOnionColor.b, m_nodes[i].m_alpha);
Shinya Kitaoka 120a6e
      else if (m_nodes[i].m_onionMode == Node::eOnionSkinBack)
Shinya Kitaoka 120a6e
        colorscale = TPixel32(backOnionColor.r, backOnionColor.g,
Shinya Kitaoka 120a6e
                              backOnionColor.b, m_nodes[i].m_alpha);
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      inksOnly = tc & ToonzCheck::eInksOnly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (TRaster32P src32 = m_nodes[i].m_raster)
Shinya Kitaoka 120a6e
      TRop::quickPut(viewedRaster, src32, aff, colorscale,
Shinya Kitaoka 120a6e
                     m_nodes[i].m_doPremultiply, m_nodes[i].m_whiteTransp,
Shinya Kitaoka 120a6e
                     m_nodes[i].m_isFirstColumn, m_doRasterDarkenBlendedView);
Shinya Kitaoka 120a6e
    else if (TRasterGR8P srcGr8 = m_nodes[i].m_raster)
Shinya Kitaoka 120a6e
      TRop::quickPut(viewedRaster, srcGr8, aff, colorscale);
Shinya Kitaoka 120a6e
    else if (TRasterCM32P srcCm = m_nodes[i].m_raster) {
Shinya Kitaoka 120a6e
      assert(m_nodes[i].m_palette);
Shinya Kitaoka 120a6e
      int oldframe = m_nodes[i].m_palette->getFrame();
Shinya Kitaoka 120a6e
      m_nodes[i].m_palette->setFrame(m_nodes[i].m_frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TPaletteP plt;
Shinya Kitaoka 120a6e
      if ((tc & ToonzCheck::eGap || tc & ToonzCheck::eAutoclose) &&
Shinya Kitaoka 120a6e
          m_nodes[i].m_isCurrentColumn) {
Shinya Kitaoka 120a6e
        srcCm          = srcCm->clone();
Shinya Kitaoka 120a6e
        plt            = m_nodes[i].m_palette->clone();
Shinya Kitaoka 120a6e
        int styleIndex = plt->addStyle(TPixel::Magenta);
Shinya Kitaoka 120a6e
        if (tc & ToonzCheck::eAutoclose)
Shinya Kitaoka 120a6e
          TAutocloser(srcCm, AutocloseDistance, AutocloseAngle, styleIndex,
Shinya Kitaoka 120a6e
                      AutocloseOpacity)
Shinya Kitaoka 120a6e
              .exec();
Shinya Kitaoka 120a6e
        if (tc & ToonzCheck::eGap)
Shinya Kitaoka 120a6e
          AreaFiller(srcCm).rectFill(m_nodes[i].m_savebox, 1, true, true,
Shinya Kitaoka 120a6e
                                     false);
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        plt = m_nodes[i].m_palette;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (tc == 0 || tc == ToonzCheck::eBlackBg ||
Shinya Kitaoka 120a6e
          !m_nodes[i].m_isCurrentColumn)
Shinya Kitaoka 120a6e
        TRop::quickPut(viewedRaster, srcCm, plt, aff, colorscale, inksOnly);
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        TRop::CmappedQuickputSettings settings;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        settings.m_globalColorScale = colorscale;
Shinya Kitaoka 120a6e
        settings.m_inksOnly         = inksOnly;
Shinya Kitaoka 120a6e
        settings.m_transparencyCheck =
Shinya Kitaoka 120a6e
            tc & (ToonzCheck::eTransparency | ToonzCheck::eGap);
Shinya Kitaoka 120a6e
        settings.m_blackBgCheck = tc & ToonzCheck::eBlackBg;
Shinya Kitaoka 120a6e
        /*-- InkCheck, Ink#1Check, PaintCheckはカレントカラムにのみ有効 --*/
Shinya Kitaoka 120a6e
        settings.m_inkIndex =
Shinya Kitaoka 120a6e
            m_nodes[i].m_isCurrentColumn
Shinya Kitaoka 120a6e
                ? (tc & ToonzCheck::eInk ? index
Shinya Kitaoka 120a6e
                                         : (tc & ToonzCheck::eInk1 ? 1 : -1))
Shinya Kitaoka 120a6e
                : -1;
Shinya Kitaoka 120a6e
        settings.m_paintIndex = m_nodes[i].m_isCurrentColumn
Shinya Kitaoka 120a6e
                                    ? (tc & ToonzCheck::ePaint ? index : -1)
Shinya Kitaoka 120a6e
                                    : -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        Preferences::instance()->getTranspCheckData(
Shinya Kitaoka 120a6e
            settings.m_transpCheckBg, settings.m_transpCheckInk,
Shinya Kitaoka 120a6e
            settings.m_transpCheckPaint);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TRop::quickPut(viewedRaster, srcCm, plt, aff, settings);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      srcCm = TRasterCM32P();
Shinya Kitaoka 120a6e
      plt   = TPaletteP();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_nodes[i].m_palette->setFrame(oldframe);
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      assert(!"Cannot use quickput with this raster combination!");
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_vs.m_colorMask != 0) {
Shinya Kitaoka 120a6e
    TRop::setChannel(ras, ras, m_vs.m_colorMask, false);
Shinya Kitaoka 120a6e
    TRop::quickPut(ras2, ras, TAffine());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, output the raster buffer on top of the OpenGL buffer
Shinya Kitaoka 120a6e
  glPushAttrib(GL_COLOR_BUFFER_BIT);  // Preserve blending and stuff
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
  glBlendFunc(GL_ONE,
Shinya Kitaoka 120a6e
              GL_ONE_MINUS_SRC_ALPHA);  // The raster buffer is intended in
Shinya Kitaoka 120a6e
  // premultiplied form - thus the GL_ONE on src
Shinya Kitaoka 120a6e
  glDisable(GL_DEPTH_TEST);
Shinya Kitaoka 120a6e
  glDisable(GL_DITHER);
Shinya Kitaoka 120a6e
  glDisable(GL_LOGIC_OP);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef GL_EXT_convolution
Shinya Kitaoka 120a6e
  glDisable(GL_CONVOLUTION_1D_EXT);
Shinya Kitaoka 120a6e
  glDisable(GL_CONVOLUTION_2D_EXT);
Shinya Kitaoka 120a6e
  glDisable(GL_SEPARABLE_2D_EXT);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef GL_EXT_histogram
Shinya Kitaoka 120a6e
  glDisable(GL_HISTOGRAM_EXT);
Shinya Kitaoka 120a6e
  glDisable(GL_MINMAX_EXT);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef GL_EXT_texture3D
Shinya Kitaoka 120a6e
  glDisable(GL_TEXTURE_3D_EXT);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
  glLoadIdentity();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glRasterPos2d(rect.x0, rect.y0);
Shinya Kitaoka 120a6e
  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
Shinya Kitaoka 120a6e
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glDrawPixels(ras2->getLx(), ras2->getLy(),            // Perform the over
Shinya Kitaoka 120a6e
               TGL_FMT, TGL_TYPE, ras2->getRawData());  //
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ras->unlock();
Shinya Kitaoka 120a6e
  glPopMatrix();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPopAttrib();  // Restore blending status
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_vs.m_showBBox && current > -1) {
Shinya Kitaoka 120a6e
    glPushMatrix();
Shinya Kitaoka 120a6e
    glLoadIdentity();
Shinya Kitaoka 120a6e
    tglColor(TPixel(200, 200, 200));
Shinya Kitaoka 120a6e
    tglMultMatrix(m_nodes[current].m_aff);
Shinya Kitaoka 120a6e
    tglDrawRect(m_nodes[current].m_raster->getBounds());
Shinya Kitaoka 120a6e
    glPopMatrix();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_nodes.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Make frame visualization in QPainter.
Toshihiro Shimizu 890ddd
\n	Draw in painter mode just raster image in m_nodes.
Toshihiro Shimizu 890ddd
\n  Onon-skin or channel mode are not considered.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void RasterPainter::drawRasterImages(QPainter &p, QPolygon cameraPol) {
Shinya Kitaoka 120a6e
  if (m_nodes.empty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double delta = sqrt(fabs(m_nodes[0].m_aff.det()));
Shinya Kitaoka 120a6e
  TRectD bbox  = m_nodes[0].m_bbox.enlarge(delta);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 1; i < (int)m_nodes.size(); i++) {
Shinya Kitaoka 120a6e
    delta = sqrt(fabs(m_nodes[i].m_aff.det()));
Shinya Kitaoka 120a6e
    bbox += m_nodes[i].m_bbox.enlarge(delta);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TRect rect(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1), tceil(bbox.y1));
Shinya Kitaoka 120a6e
  rect = rect * TRect(0, 0, m_dim.lx - 1, m_dim.ly - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRect r = rect - rect.getP00();
Shinya Kitaoka 120a6e
  TAffine flipY(1, 0, 0, 0, -1, m_dim.ly);
Shinya Kitaoka 120a6e
  p.setClipRegion(QRegion(cameraPol));
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_nodes.size(); i++) {
Shinya Kitaoka 120a6e
    if (m_nodes[i].m_onionMode != Node::eOnionSkinNone) continue;
Shinya Kitaoka 120a6e
    p.resetMatrix();
Shinya Kitaoka 120a6e
    TRasterP ras = m_nodes[i].m_raster;
Shinya Kitaoka 120a6e
    TAffine aff  = TTranslation(-rect.x0, -rect.y0) * flipY * m_nodes[i].m_aff;
Shinya Kitaoka 120a6e
    QMatrix matrix(aff.a11, aff.a21, aff.a12, aff.a22, aff.a13, aff.a23);
Shinya Kitaoka 120a6e
    QImage image = rasterToQImage(ras);
Shinya Kitaoka 120a6e
    if (image.isNull()) continue;
Shinya Kitaoka 120a6e
    p.setMatrix(matrix);
Shinya Kitaoka 120a6e
    p.drawImage(rect.getP00().x, rect.getP00().y, image);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p.resetMatrix();
Shinya Kitaoka 120a6e
  m_nodes.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void buildAutocloseImage(TVectorImage *vaux, TVectorImage *vi,
Shinya Kitaoka 120a6e
                         const std::vector<std::pair<int, double="">> &startPoints,</std::pair<int,>
Shinya Kitaoka 120a6e
                         const std::vector<std::pair<int, double="">> &endPoints) {</std::pair<int,>
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < startPoints.size(); i++) {
Shinya Kitaoka 120a6e
    TThickPoint p1 = vi->getStroke(startPoints[i].first)
Shinya Kitaoka 120a6e
                         ->getThickPoint(startPoints[i].second);
Shinya Kitaoka 120a6e
    TThickPoint p2 =
Shinya Kitaoka 120a6e
        vi->getStroke(endPoints[i].first)->getThickPoint(endPoints[i].second);
Shinya Kitaoka 120a6e
    std::vector<tthickpoint> points(3);</tthickpoint>
Shinya Kitaoka 120a6e
    points[0]       = p1;
Shinya Kitaoka 120a6e
    points[1]       = 0.5 * (p1 + p2);
Shinya Kitaoka 120a6e
    points[2]       = p2;
Shinya Kitaoka 120a6e
    points[0].thick = points[1].thick = points[2].thick = 0.0;
Shinya Kitaoka 120a6e
    TStroke *auxStroke                                  = new TStroke(points);
Shinya Kitaoka 120a6e
    auxStroke->setStyle(2);
Shinya Kitaoka 120a6e
    vaux->addStroke(auxStroke);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::DoubleVar AutocloseFactor("InknpaintAutocloseFactor", 4.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void drawAutocloses(TVectorImage *vi, TVectorRenderData &rd) {
Shinya Kitaoka 120a6e
  static TPalette *plt = 0;
Shinya Kitaoka 120a6e
  if (!plt) {
Shinya Kitaoka 120a6e
    plt = new TPalette();
Shinya Kitaoka 120a6e
    plt->addStyle(TPixel::Magenta);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, double="">> startPoints, endPoints;</std::pair<int,>
Shinya Kitaoka 120a6e
  getClosingPoints(vi->getBBox(), AutocloseFactor, vi, startPoints, endPoints);
Shinya Kitaoka 120a6e
  TVectorImage *vaux = new TVectorImage();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rd.m_palette = plt;
Shinya Kitaoka 120a6e
  buildAutocloseImage(vaux, vi, startPoints, endPoints);
Shinya Kitaoka 120a6e
  tglDraw(rd, vaux);
Shinya Kitaoka 120a6e
  delete vaux;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Take image from \b Stage::Player \b data and recall the right method for
Shinya Kitaoka 120a6e
                this kind of image, for vector image recall \b onVectorImage(),
Shinya Kitaoka 120a6e
   for raster
Shinya Kitaoka 120a6e
                image recall \b onRasterImage() for toonz image recall \b
Shinya Kitaoka 120a6e
   onToonzImage().
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void RasterPainter::onImage(const Stage::Player &player) {
Shinya Kitaoka 120a6e
  if (m_singleColumnEnabled && !player.m_isCurrentColumn) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Attempt Plastic-deformed drawing
Shinya Kitaoka 120a6e
  if (TStageObject *obj =
Shinya Kitaoka 120a6e
          ::plasticDeformedObj(player, m_vs.m_plasticVisualSettings)) {
Shinya Kitaoka 120a6e
    flushRasterImages();
Shinya Kitaoka 120a6e
    ::onPlasticDeformedImage(obj, player, m_vs, m_viewAff);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Common image draw
Shinya Kitaoka 120a6e
    const TImageP &img = player.image();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (TVectorImageP vi = img)
Shinya Kitaoka 120a6e
      onVectorImage(vi.getPointer(), player);
Shinya Kitaoka 120a6e
    else if (TRasterImageP ri = img)
Shinya Kitaoka 120a6e
      onRasterImage(ri.getPointer(), player);
Shinya Kitaoka 120a6e
    else if (TToonzImageP ti = img)
Shinya Kitaoka 120a6e
      onToonzImage(ti.getPointer(), player);
Shinya Kitaoka 120a6e
    else if (TMeshImageP mi = img) {
Shinya Kitaoka 120a6e
      flushRasterImages();
Shinya Kitaoka 120a6e
      ::onMeshImage(mi.getPointer(), player, m_vs, m_viewAff);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! View a vector cell images.
Toshihiro Shimizu 890ddd
\n	If onion-skin is active compute \b TOnionFader value.
Shinya Kitaoka 120a6e
                Create and boot a \b TVectorRenderData and recall \b tglDraw().
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void RasterPainter::onVectorImage(TVectorImage *vi,
Shinya Kitaoka 120a6e
                                  const Stage::Player &player) {
Shinya Kitaoka 120a6e
  flushRasterImages();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // When loaded, vectorimages needs to have regions recomputed, but doing that
Shinya Kitaoka 120a6e
  // while loading them
Shinya Kitaoka 120a6e
  // is quite slow (think about loading whole scenes!..). They are recomputed
Shinya Kitaoka 120a6e
  // the first time they
Shinya Kitaoka 120a6e
  // are selected and shown on screen...except when playing back, to avoid
Shinya Kitaoka 120a6e
  // slowness!
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // (Daniele) This function should *NOT* be responsible of that.
Shinya Kitaoka 120a6e
  //           It's the *image itself* that should recalculate or initialize
Shinya Kitaoka 120a6e
  //           said data
Shinya Kitaoka 120a6e
  //           if queried about it and turns out it's not available...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!player.m_isPlaying && player.m_isCurrentColumn)
Shinya Kitaoka 120a6e
    vi->recomputeRegionsIfNeeded();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const Preferences &prefs = *Preferences::instance();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TColorFunction *cf = 0;
Shinya Kitaoka 120a6e
  TPalette *vPalette = vi->getPalette();
Shinya Kitaoka 120a6e
  TPixel32 bgColor   = TPixel32::White;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int tc = (m_checkFlags && player.m_isCurrentColumn)
Shinya Kitaoka 120a6e
               ? ToonzCheck::instance()->getChecks()
Shinya Kitaoka 120a6e
               : 0;
Shinya Kitaoka 120a6e
  bool inksOnly = tc & ToonzCheck::eInksOnly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int oldFrame = vPalette->getFrame();
Shinya Kitaoka 120a6e
  vPalette->setFrame(player.m_frame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (player.m_onionSkinDistance != c_noOnionSkin) {
Shinya Kitaoka 120a6e
    TPixel32 frontOnionColor, backOnionColor;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (player.m_onionSkinDistance != 0) {
Shinya Kitaoka 120a6e
      prefs.getOnionData(frontOnionColor, backOnionColor, inksOnly);
Shinya Kitaoka 120a6e
      bgColor =
Shinya Kitaoka 120a6e
          (player.m_onionSkinDistance < 0) ? backOnionColor : frontOnionColor;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double m[4] = {1.0, 1.0, 1.0, 1.0}, c[4];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Weighted addition to RGB and matte multiplication
Shinya Kitaoka 120a6e
    m[3] = 1.0 -
Shinya Kitaoka 120a6e
           ((player.m_onionSkinDistance == 0)
Shinya Kitaoka 120a6e
                ? 0.1
Shinya Kitaoka 120a6e
                : OnionSkinMask::getOnionSkinFade(player.m_onionSkinDistance));
Shinya Kitaoka 120a6e
    c[0] = (1.0 - m[3]) * bgColor.r, c[1] = (1.0 - m[3]) * bgColor.g,
Shinya Kitaoka 120a6e
    c[2] = (1.0 - m[3]) * bgColor.b;
Shinya Kitaoka 120a6e
    c[3] = 0.0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    cf = new TGenericColorFunction(m, c);
Shinya Kitaoka 120a6e
  } else if (player.m_opacity < 255)
Shinya Kitaoka 120a6e
    cf = new TTranspFader(player.m_opacity / 255.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TVectorRenderData rd(m_viewAff * player.m_placement, TRect(), vPalette, cf,
Shinya Kitaoka 120a6e
                       true  // alpha enabled
Shinya Kitaoka 120a6e
                       );
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rd.m_drawRegions       = !inksOnly;
Shinya Kitaoka 120a6e
  rd.m_inkCheckEnabled   = tc & ToonzCheck::eInk;
Shinya Kitaoka 120a6e
  rd.m_paintCheckEnabled = tc & ToonzCheck::ePaint;
Shinya Kitaoka 120a6e
  rd.m_blackBgEnabled    = tc & ToonzCheck::eBlackBg;
Shinya Kitaoka 120a6e
  rd.m_colorCheckIndex   = ToonzCheck::instance()->getColorIndex();
Shinya Kitaoka 120a6e
  rd.m_show0ThickStrokes = prefs.getShow0ThickLines();
Shinya Kitaoka 120a6e
  rd.m_regionAntialias   = prefs.getRegionAntialias();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (tc & (ToonzCheck::eTransparency | ToonzCheck::eGap)) {
Shinya Kitaoka 120a6e
    TPixel dummy;
Shinya Kitaoka 120a6e
    rd.m_tcheckEnabled = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (rd.m_blackBgEnabled)
Shinya Kitaoka 120a6e
      prefs.getTranspCheckData(rd.m_tCheckInk, dummy, rd.m_tCheckPaint);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      prefs.getTranspCheckData(dummy, rd.m_tCheckInk, rd.m_tCheckPaint);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_vs.m_colorMask != 0) {
Shinya Kitaoka 120a6e
    glColorMask((m_vs.m_colorMask & TRop::RChan) ? GL_TRUE : GL_FALSE,
Shinya Kitaoka 120a6e
                (m_vs.m_colorMask & TRop::GChan) ? GL_TRUE : GL_FALSE,
Shinya Kitaoka 120a6e
                (m_vs.m_colorMask & TRop::BChan) ? GL_TRUE : GL_FALSE, GL_TRUE);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TVectorImageP viDelete;
Shinya Kitaoka 120a6e
  if (tc & ToonzCheck::eGap) {
Shinya Kitaoka 120a6e
    viDelete = vi->clone();
Shinya Kitaoka 120a6e
    vi       = viDelete.getPointer();
Shinya Kitaoka 120a6e
    vi->selectFill(vi->getBBox(), 0, 1, true, true, false);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_maskLevel > 0)
Shinya Kitaoka 120a6e
    tglDrawMask(rd, vi);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    tglDraw(rd, vi);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (tc & ToonzCheck::eAutoclose) drawAutocloses(vi, rd);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
Shinya Kitaoka 120a6e
  vPalette->setFrame(oldFrame);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  delete cf;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool isSubsheetChainOnColumn0(TXsheet *topXsheet, TXsheet *subsheet, int frame);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! Create a \b Node and put it in \b m_nodes.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void RasterPainter::onRasterImage(TRasterImage *ri,
Shinya Kitaoka 120a6e
                                  const Stage::Player &player) {
Shinya Kitaoka 120a6e
  TRasterP r = ri->getRaster();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine aff;
Shinya Kitaoka 120a6e
  aff = m_viewAff * player.m_placement * player.m_dpiAff;
Shinya Kitaoka 120a6e
  aff = TTranslation(m_dim.lx * 0.5, m_dim.ly * 0.5) * aff *
Shinya Kitaoka 120a6e
        TTranslation(-r->getCenterD() +
Shinya Kitaoka 120a6e
                     convert(ri->getOffset()));  // this offset is !=0 only if
Shinya Kitaoka 120a6e
                                                 // in cleanup camera test mode
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRectD bbox = TRectD(0, 0, m_dim.lx, m_dim.ly);
Shinya Kitaoka 120a6e
  bbox *= convert(m_clipRect);
Shinya Kitaoka 120a6e
  if (bbox.isEmpty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int alpha                 = 255;
Shinya Kitaoka 120a6e
  Node::OnionMode onionMode = Node::eOnionSkinNone;
Shinya Kitaoka 120a6e
  if (player.m_onionSkinDistance != c_noOnionSkin) {
Shinya Kitaoka 120a6e
    // GetOnionSkinFade va bene per il vettoriale mentre il raster funziona al
Shinya Kitaoka 120a6e
    // contrario
Shinya Kitaoka 120a6e
    // 1 opaco -> 0 completamente trasparente
Shinya Kitaoka 120a6e
    // inverto quindi il risultato della funzione stando attento al caso 0
Shinya Kitaoka 120a6e
    // (in cui era scolpito il valore 0.9)
Shinya Kitaoka 120a6e
    double onionSkiFade = player.m_onionSkinDistance == 0
Shinya Kitaoka 120a6e
                              ? 0.9
Shinya Kitaoka 120a6e
                              : (1.0 - OnionSkinMask::getOnionSkinFade(
Shinya Kitaoka 120a6e
                                           player.m_onionSkinDistance));
Shinya Kitaoka 120a6e
    alpha     = tcrop(tround(onionSkiFade * 255.0), 0, 255);
Shinya Kitaoka 120a6e
    onionMode = (player.m_onionSkinDistance > 0)
Shinya Kitaoka 120a6e
                    ? Node::eOnionSkinFront
Shinya Kitaoka 120a6e
                    : ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack
Shinya Kitaoka 120a6e
                                                        : Node::eOnionSkinNone);
Shinya Kitaoka 120a6e
  } else if (player.m_opacity < 255)
Shinya Kitaoka 120a6e
    alpha             = player.m_opacity;
Shinya Kitaoka 120a6e
  TXshSimpleLevel *sl = player.m_sl;
Shinya Kitaoka 120a6e
  bool doPremultiply  = false;
Shinya Kitaoka 120a6e
  bool whiteTransp    = false;
Shinya Kitaoka 120a6e
  if (sl) {
Shinya Kitaoka 120a6e
    LevelProperties *levelProp = sl->getProperties();
Shinya Kitaoka 120a6e
    if (levelProp->doPremultiply())
Shinya Kitaoka 120a6e
      doPremultiply = true;
Shinya Kitaoka 120a6e
    else if (levelProp->whiteTransp())
Shinya Kitaoka 120a6e
      whiteTransp = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool ignoreAlpha =
Shinya Kitaoka 120a6e
      (Preferences::instance()->isIgnoreAlphaonColumn1Enabled() &&
Shinya Kitaoka 120a6e
       player.m_column == 0 &&
Shinya Kitaoka 120a6e
       isSubsheetChainOnColumn0(sl->getScene()->getTopXsheet(), player.m_xsh,
Shinya Kitaoka 120a6e
                                player.m_frame));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_nodes.push_back(Node(r, 0, alpha, aff, ri->getSavebox(), bbox,
Shinya Kitaoka 120a6e
                         player.m_frame, player.m_isCurrentColumn, onionMode,
Shinya Kitaoka 120a6e
                         doPremultiply, whiteTransp, ignoreAlpha));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Create a \b Node and put it in \b m_nodes.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void RasterPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) {
Shinya Kitaoka 120a6e
  TRasterCM32P r = ti->getRaster();
Shinya Kitaoka 120a6e
  if (!ti->getPalette()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine aff = m_viewAff * player.m_placement * player.m_dpiAff;
Shinya Kitaoka 120a6e
  aff         = TTranslation(m_dim.lx / 2.0, m_dim.ly / 2.0) * aff *
Shinya Kitaoka 120a6e
        TTranslation(-r->getCenterD());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRectD bbox = TRectD(0, 0, m_dim.lx, m_dim.ly);
Shinya Kitaoka 120a6e
  bbox *= convert(m_clipRect);
Shinya Kitaoka 120a6e
  if (bbox.isEmpty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int alpha                 = 255;
Shinya Kitaoka 120a6e
  Node::OnionMode onionMode = Node::eOnionSkinNone;
Shinya Kitaoka 120a6e
  if (player.m_onionSkinDistance != c_noOnionSkin) {
Shinya Kitaoka 120a6e
    // GetOnionSkinFade va bene per il vettoriale mentre il raster funziona al
Shinya Kitaoka 120a6e
    // contrario
Shinya Kitaoka 120a6e
    // 1 opaco -> 0 completamente trasparente
Shinya Kitaoka 120a6e
    // inverto quindi il risultato della funzione stando attento al caso 0
Shinya Kitaoka 120a6e
    // (in cui era scolpito il valore 0.9)
Shinya Kitaoka 120a6e
    double onionSkiFade = player.m_onionSkinDistance == 0
Shinya Kitaoka 120a6e
                              ? 0.9
Shinya Kitaoka 120a6e
                              : (1.0 - OnionSkinMask::getOnionSkinFade(
Shinya Kitaoka 120a6e
                                           player.m_onionSkinDistance));
Shinya Kitaoka 120a6e
    alpha     = tcrop(tround(onionSkiFade * 255.0), 0, 255);
Shinya Kitaoka 120a6e
    onionMode = (player.m_onionSkinDistance > 0)
Shinya Kitaoka 120a6e
                    ? Node::eOnionSkinFront
Shinya Kitaoka 120a6e
                    : ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack
Shinya Kitaoka 120a6e
                                                        : Node::eOnionSkinNone);
Shinya Kitaoka 120a6e
  } else if (player.m_opacity < 255)
Shinya Kitaoka 120a6e
    alpha = player.m_opacity;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_nodes.push_back(Node(r, ti->getPalette(), alpha, aff, ti->getSavebox(),
Shinya Kitaoka 120a6e
                         bbox, player.m_frame, player.m_isCurrentColumn,
Shinya Kitaoka 120a6e
                         onionMode, false, false, false));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    OpenGLPainter  implementation
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
OpenGlPainter::OpenGlPainter(const TAffine &viewAff, const TRect &rect,
Shinya Kitaoka 120a6e
                             const ImagePainter::VisualSettings &vs,
Shinya Kitaoka 120a6e
                             bool isViewer, bool alphaEnabled)
Shinya Kitaoka 120a6e
    : Visitor(vs)
Shinya Kitaoka 120a6e
    , m_viewAff(viewAff)
Shinya Kitaoka 120a6e
    , m_clipRect(rect)
Shinya Kitaoka 120a6e
    , m_camera3d(false)
Shinya Kitaoka 120a6e
    , m_phi(0)
Shinya Kitaoka 120a6e
    , m_maskLevel(0)
Shinya Kitaoka 120a6e
    , m_isViewer(isViewer)
Shinya Kitaoka 120a6e
    , m_alphaEnabled(alphaEnabled)
Shinya Kitaoka 120a6e
    , m_paletteHasChanged(false)
Shinya Kitaoka 120a6e
    , m_minZ(0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OpenGlPainter::onImage(const Stage::Player &player) {
Shinya Kitaoka 120a6e
  if (player.m_z < m_minZ) m_minZ = player.m_z;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glPushAttrib(GL_ALL_ATTRIB_BITS);
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_camera3d)
Shinya Kitaoka 120a6e
    glTranslated(
Shinya Kitaoka 120a6e
        0, 0,
Shinya Kitaoka 120a6e
        player.m_z);  // Ok, move object along z as specified in the player
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Attempt Plastic-deformed drawing
Shinya Kitaoka 120a6e
  if (TStageObject *obj =
Shinya Kitaoka 120a6e
          ::plasticDeformedObj(player, m_vs.m_plasticVisualSettings))
Shinya Kitaoka 120a6e
    ::onPlasticDeformedImage(obj, player, m_vs, m_viewAff);
Shinya Kitaoka 120a6e
  else if (const TImageP &image = player.image()) {
Shinya Kitaoka 120a6e
    if (TVectorImageP vi = image)
Shinya Kitaoka 120a6e
      onVectorImage(vi.getPointer(), player);
Shinya Kitaoka 120a6e
    else if (TRasterImageP ri = image)
Shinya Kitaoka 120a6e
      onRasterImage(ri.getPointer(), player);
Shinya Kitaoka 120a6e
    else if (TToonzImageP ti = image)
Shinya Kitaoka 120a6e
      onToonzImage(ti.getPointer(), player);
Shinya Kitaoka 120a6e
    else if (TMeshImageP mi = image)
Shinya Kitaoka 120a6e
      onMeshImage(mi.getPointer(), player, m_vs, m_viewAff);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glPopMatrix();
Shinya Kitaoka 120a6e
  glPopAttrib();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OpenGlPainter::onVectorImage(TVectorImage *vi,
Shinya Kitaoka 120a6e
                                  const Stage::Player &player) {
Shinya Kitaoka 120a6e
  if (m_camera3d && (player.m_onionSkinDistance == c_noOnionSkin ||
Shinya Kitaoka 120a6e
                     player.m_onionSkinDistance == 0)) {
Shinya Kitaoka 120a6e
    const TRectD &bbox = player.m_placement * player.m_dpiAff * vi->getBBox();
Shinya Kitaoka 120a6e
    draw3DShadow(bbox, player.m_z, m_phi);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TColorFunction *cf = 0;
Shinya Kitaoka 120a6e
  TOnionFader fader;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPalette *vPalette = vi->getPalette();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int oldFrame = vPalette->getFrame();
Shinya Kitaoka 120a6e
  vPalette->setFrame(player.m_frame);  // Hehe. Should be locking
Shinya Kitaoka 120a6e
                                       // vPalette's mutex here...
Shinya Kitaoka 120a6e
  if (player.m_onionSkinDistance != c_noOnionSkin) {
Shinya Kitaoka 120a6e
    TPixel32 bgColor = TPixel32::White;
Shinya Kitaoka 120a6e
    fader            = TOnionFader(
Shinya Kitaoka 120a6e
        bgColor, OnionSkinMask::getOnionSkinFade(player.m_onionSkinDistance));
Shinya Kitaoka 120a6e
    cf = &fader;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TVectorRenderData rd =
Shinya Kitaoka 120a6e
      isViewer() ? TVectorRenderData(TVectorRenderData::ViewerSettings(),
Shinya Kitaoka 120a6e
                                     m_viewAff * player.m_placement, m_clipRect,
Shinya Kitaoka 120a6e
                                     vPalette)
Shinya Kitaoka 120a6e
                 : TVectorRenderData(TVectorRenderData::ProductionSettings(),
Shinya Kitaoka 120a6e
                                     m_viewAff * player.m_placement, m_clipRect,
Shinya Kitaoka 120a6e
                                     vPalette);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rd.m_alphaChannel = m_alphaEnabled;
Shinya Kitaoka 120a6e
  rd.m_is3dView     = m_camera3d;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_maskLevel > 0)
Shinya Kitaoka 120a6e
    tglDrawMask(rd, vi);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    tglDraw(rd, vi);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  vPalette->setFrame(oldFrame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OpenGlPainter::onRasterImage(TRasterImage *ri,
Shinya Kitaoka 120a6e
                                  const Stage::Player &player) {
Shinya Kitaoka 120a6e
  if (m_camera3d && (player.m_onionSkinDistance == c_noOnionSkin ||
Shinya Kitaoka 120a6e
                     player.m_onionSkinDistance == 0)) {
Shinya Kitaoka 120a6e
    TRectD bbox(ri->getBBox());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Since bbox is in image coordinates, adjust to level coordinates first
Shinya Kitaoka 120a6e
    bbox -= ri->getRaster()->getCenterD() - convert(ri->getOffset());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Then, to world coordinates
Shinya Kitaoka 120a6e
    bbox = player.m_placement * player.m_dpiAff * bbox;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    draw3DShadow(bbox, player.m_z, m_phi);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool tlvFlag = player.m_sl && player.m_sl->getType() == TZP_XSHLEVEL;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (tlvFlag &&
Shinya Kitaoka 120a6e
      m_paletteHasChanged)  // o.o! Raster images here - should never be
Shinya Kitaoka 120a6e
    assert(false);          // dealing with tlv stuff!
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool premultiplied = tlvFlag;  // xD
Shinya Kitaoka 120a6e
  static std::vector<char></char>
Shinya Kitaoka 120a6e
      matteChan;  // Wtf this is criminal. Altough probably this
Shinya Kitaoka 120a6e
                  // stuff is used only in the main thread... hmmm....
Shinya Kitaoka 120a6e
  TRaster32P r = (TRaster32P)ri->getRaster();
Shinya Kitaoka 120a6e
  r->lock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (c_noOnionSkin != player.m_onionSkinDistance) {
Shinya Kitaoka 120a6e
    double fade =
Shinya Kitaoka 120a6e
        0.5 - 0.45 * (1 - 1 / (1 + 0.15 * abs(player.m_onionSkinDistance)));
Shinya Kitaoka 120a6e
    if ((int)matteChan.size() < r->getLx() * r->getLy())
Shinya Kitaoka 120a6e
      matteChan.resize(r->getLx() * r->getLy());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int k = 0;
Shinya Kitaoka 120a6e
    for (int y = 0; y < r->getLy(); ++y) {
Shinya Kitaoka 120a6e
      TPixel32 *pix    = r->pixels(y);
Shinya Kitaoka 120a6e
      TPixel32 *endPix = pix + r->getLx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      while (pix < endPix) {
Shinya Kitaoka 120a6e
        matteChan[k++] = pix->m;
Shinya Kitaoka 120a6e
        pix->m         = (int)(pix->m * fade);
Shinya Kitaoka 120a6e
        pix++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    premultiplied = false;  // pfff
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TAffine aff = player.m_dpiAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPushAttrib(GL_ALL_ATTRIB_BITS);
Shinya Kitaoka 120a6e
  tglEnableBlending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  GLRasterPainter::drawRaster(m_viewAff * player.m_placement * aff *
Shinya Kitaoka 120a6e
                                  TTranslation(convert(ri->getOffset())),
Shinya Kitaoka 120a6e
                              ri, premultiplied);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPopAttrib();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (c_noOnionSkin != player.m_onionSkinDistance) {
Shinya Kitaoka 120a6e
    int k = 0;
Shinya Kitaoka 120a6e
    for (int y = 0; y < r->getLy(); ++y) {
Shinya Kitaoka 120a6e
      TPixel32 *pix    = r->pixels(y);
Shinya Kitaoka 120a6e
      TPixel32 *endPix = pix + r->getLx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      while (pix < endPix) pix++->m = matteChan[k++];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  r->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OpenGlPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) {
Shinya Kitaoka 120a6e
  if (m_camera3d && (player.m_onionSkinDistance == c_noOnionSkin ||
Shinya Kitaoka 120a6e
                     player.m_onionSkinDistance == 0)) {
Shinya Kitaoka 120a6e
    TRectD bbox(ti->getBBox());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bbox -= ti->getRaster()->getCenterD();
Shinya Kitaoka 120a6e
    bbox = player.m_placement * player.m_dpiAff * bbox;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    draw3DShadow(bbox, player.m_z, m_phi);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterCM32P ras = ti->getRaster();
Shinya Kitaoka 120a6e
  TRaster32P ras32(ras->getSize());
Shinya Kitaoka 120a6e
  ras32->fill(TPixel32(0, 0, 0, 0));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // onionSkin
Shinya Kitaoka 120a6e
  TRop::quickPut(ras32, ras, ti->getPalette(), TAffine());
Shinya Kitaoka 120a6e
  TAffine aff = player.m_dpiAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterImageP ri(ras32);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  GLRasterPainter::drawRaster(m_viewAff * player.m_placement * aff, ri, true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OpenGlPainter::beginMask() {
Shinya Kitaoka 120a6e
  ++m_maskLevel;
Shinya Kitaoka 120a6e
  TStencilControl::instance()->beginMask();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
void OpenGlPainter::endMask() {
Shinya Kitaoka 120a6e
  --m_maskLevel;
Shinya Kitaoka 120a6e
  TStencilControl::instance()->endMask();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
void OpenGlPainter::enableMask() {
Shinya Kitaoka 120a6e
  TStencilControl::instance()->enableMask(TStencilControl::SHOW_INSIDE);
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
void OpenGlPainter::disableMask() {
Shinya Kitaoka 120a6e
  TStencilControl::instance()->disableMask();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    Plastic functions  implementation
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TStageObject *plasticDeformedObj(const Stage::Player &player,
Shinya Kitaoka 120a6e
                                 const PlasticVisualSettings &pvs) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static inline bool isDeformableMeshColumn(
Shinya Kitaoka 120a6e
        TXshColumn *column, const PlasticVisualSettings &pvs) {
Shinya Kitaoka 120a6e
      return (column->getColumnType() == TXshColumn::eMeshType) &&
Shinya Kitaoka 120a6e
             (pvs.m_showOriginalColumn != column);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static inline bool isDeformableMeshLevel(TXshSimpleLevel *sl) {
Shinya Kitaoka 120a6e
      return sl && (sl->getType() == MESH_XSHLEVEL);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };  // locals
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (pvs.m_applyPlasticDeformation && player.m_column >= 0) {
Shinya Kitaoka 120a6e
    // Check whether the player's column is a direct stage-schematic child of a
Shinya Kitaoka 120a6e
    // mesh object
Shinya Kitaoka 120a6e
    TStageObject *playerObj =
Shinya Kitaoka 120a6e
        player.m_xsh->getStageObject(TStageObjectId::ColumnId(player.m_column));
Shinya Kitaoka 120a6e
    assert(playerObj);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const TStageObjectId &parentId = playerObj->getParent();
Shinya Kitaoka 120a6e
    if (parentId.isColumn() && playerObj->getParentHandle()[0] != 'H') {
Shinya Kitaoka 120a6e
      TXshColumn *parentCol = player.m_xsh->getColumn(parentId.getIndex());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (locals::isDeformableMeshColumn(parentCol, pvs) &&
Shinya Kitaoka 120a6e
          !locals::isDeformableMeshLevel(player.m_sl)) {
Shinya Kitaoka 120a6e
        const SkDP &sd = player.m_xsh->getStageObject(parentId)
Shinya Kitaoka 120a6e
                             ->getPlasticSkeletonDeformation();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        const TXshCell &parentCell =
Shinya Kitaoka 120a6e
            player.m_xsh->getCell(player.m_frame, parentId.getIndex());
Shinya Kitaoka 120a6e
        TXshSimpleLevel *parentSl = parentCell.getSimpleLevel();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (sd && locals::isDeformableMeshLevel(parentSl)) return playerObj;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void onMeshImage(TMeshImage *mi, const Stage::Player &player,
Shinya Kitaoka 120a6e
                 const ImagePainter::VisualSettings &vs,
Shinya Kitaoka 120a6e
                 const TAffine &viewAff) {
Shinya Kitaoka 120a6e
  assert(mi);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static const double soMinColor[4] = {0.0, 0.0, 0.0,
Shinya Kitaoka 120a6e
                                       0.6};  // Translucent black
Shinya Kitaoka 120a6e
  static const double soMaxColor[4] = {1.0, 1.0, 1.0,
Shinya Kitaoka 120a6e
                                       0.6};  // Translucent white
Shinya Kitaoka 120a6e
  static const double rigMinColor[4] = {0.0, 1.0, 0.0,
Shinya Kitaoka 120a6e
                                        0.6};  // Translucent green
Shinya Kitaoka 120a6e
  static const double rigMaxColor[4] = {1.0, 0.0, 0.0, 0.6};  // Translucent red
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool doOnionSkin    = (player.m_onionSkinDistance != c_noOnionSkin);
Shinya Kitaoka 120a6e
  bool onionSkinImage = doOnionSkin && (player.m_onionSkinDistance != 0);
Shinya Kitaoka 120a6e
  bool drawMeshes =
Shinya Kitaoka 120a6e
      vs.m_plasticVisualSettings.m_drawMeshesWireframe && !onionSkinImage;
Shinya Kitaoka 120a6e
  bool drawSO = vs.m_plasticVisualSettings.m_drawSO && !onionSkinImage;
Shinya Kitaoka 120a6e
  bool drawRigidity =
Shinya Kitaoka 120a6e
      vs.m_plasticVisualSettings.m_drawRigidity && !onionSkinImage;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Currently skipping onion skinned meshes
Shinya Kitaoka 120a6e
  if (onionSkinImage) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build dpi
Shinya Kitaoka 120a6e
  TPointD meshSlDpi(player.m_sl->getDpi(player.m_fid, 0));
Shinya Kitaoka 120a6e
  assert(meshSlDpi.x != 0.0 && meshSlDpi.y != 0.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build reference change affines
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TAffine &worldMeshToMeshAff =
Shinya Kitaoka 120a6e
      TScale(meshSlDpi.x / Stage::inch, meshSlDpi.y / Stage::inch);
Shinya Kitaoka 120a6e
  const TAffine &meshToWorldMeshAff =
Shinya Kitaoka 120a6e
      TScale(Stage::inch / meshSlDpi.x, Stage::inch / meshSlDpi.y);
Shinya Kitaoka 120a6e
  const TAffine &worldMeshToWorldAff = player.m_placement;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TAffine &meshToWorldAff = worldMeshToWorldAff * meshToWorldMeshAff;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Prepare OpenGL
Shinya Kitaoka 120a6e
  glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
  glEnable(GL_LINE_SMOOTH);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Push mesh coordinates
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
  tglMultMatrix(viewAff * meshToWorldAff);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Fetch deformation
Shinya Kitaoka 120a6e
  PlasticSkeletonDeformation *deformation = 0;
Shinya Kitaoka 120a6e
  double sdFrame;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (vs.m_plasticVisualSettings.m_applyPlasticDeformation &&
Shinya Kitaoka 120a6e
      player.m_column >= 0) {
Shinya Kitaoka 120a6e
    TXshColumn *column = player.m_xsh->getColumn(player.m_column);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (column != vs.m_plasticVisualSettings.m_showOriginalColumn) {
Shinya Kitaoka 120a6e
      TStageObject *playerObj = player.m_xsh->getStageObject(
Shinya Kitaoka 120a6e
          TStageObjectId::ColumnId(player.m_column));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      deformation = playerObj->getPlasticSkeletonDeformation().getPointer();
Shinya Kitaoka 120a6e
      sdFrame     = playerObj->paramsTime(player.m_frame);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (deformation) {
Shinya Kitaoka 120a6e
    // Retrieve the associated plastic deformers data (this may eventually
Shinya Kitaoka 120a6e
    // update the deforms)
Shinya Kitaoka 120a6e
    const PlasticDeformerDataGroup *dataGroup =
Shinya Kitaoka 120a6e
        PlasticDeformerStorage::instance()->process(
Shinya Kitaoka 120a6e
            sdFrame, mi, deformation, deformation->skeletonId(sdFrame),
Shinya Kitaoka 120a6e
            worldMeshToMeshAff);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Draw faces first
Shinya Kitaoka 120a6e
    if (drawSO)
Shinya Kitaoka 120a6e
      tglDrawSO(*mi, (double *)soMinColor, (double *)soMaxColor, dataGroup,
Shinya Kitaoka 120a6e
                true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (drawRigidity)
Shinya Kitaoka 120a6e
      tglDrawRigidity(*mi, (double *)rigMinColor, (double *)rigMaxColor,
Shinya Kitaoka 120a6e
                      dataGroup, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Draw edges next
Shinya Kitaoka 120a6e
    if (drawMeshes) {
Shinya Kitaoka 120a6e
      glColor4d(0.0, 1.0, 0.0, 0.7 * player.m_opacity / 255.0);  // Green
Shinya Kitaoka 120a6e
      tglDrawEdges(*mi, dataGroup);  // The mesh must be deformed
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Draw un-deformed data
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Draw faces first
Shinya Kitaoka 120a6e
    if (drawSO) tglDrawSO(*mi, (double *)soMinColor, (double *)soMaxColor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (drawRigidity)
Shinya Kitaoka 120a6e
      tglDrawRigidity(*mi, (double *)rigMinColor, (double *)rigMaxColor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Just draw the mesh image next
Shinya Kitaoka 120a6e
    if (drawMeshes) {
Shinya Kitaoka 120a6e
      glColor4d(0.0, 1.0, 0.0, 0.7 * player.m_opacity / 255.0);  // Green
Shinya Kitaoka 120a6e
      tglDrawEdges(*mi);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Cleanup OpenGL
Shinya Kitaoka 120a6e
  glPopMatrix();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glDisable(GL_LINE_SMOOTH);
Shinya Kitaoka 120a6e
  glDisable(GL_BLEND);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Applies Plastic deformation of the specified player's stage object.
Shinya Kitaoka 120a6e
void onPlasticDeformedImage(TStageObject *playerObj,
Shinya Kitaoka 120a6e
                            const Stage::Player &player,
Shinya Kitaoka 120a6e
                            const ImagePainter::VisualSettings &vs,
Shinya Kitaoka 120a6e
                            const TAffine &viewAff) {
Shinya Kitaoka 120a6e
  bool doOnionSkin    = (player.m_onionSkinDistance != c_noOnionSkin);
Shinya Kitaoka 120a6e
  bool onionSkinImage = doOnionSkin && (player.m_onionSkinDistance != 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Deal with color scaling due to transparency / onion skin
Shinya Kitaoka 120a6e
  double pixScale[4] = {1.0, 1.0, 1.0, 1.0};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (doOnionSkin) {
Shinya Kitaoka 120a6e
    if (onionSkinImage) {
Shinya Kitaoka 120a6e
      TPixel32 frontOnionColor, backOnionColor;
Shinya Kitaoka 120a6e
      bool inksOnly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      Preferences::instance()->getOnionData(frontOnionColor, backOnionColor,
Shinya Kitaoka 120a6e
                                            inksOnly);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      const TPixel32 &refColor =
Shinya Kitaoka 120a6e
          (player.m_onionSkinDistance < 0) ? backOnionColor : frontOnionColor;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      pixScale[3] =
Shinya Kitaoka 120a6e
          1.0 - OnionSkinMask::getOnionSkinFade(player.m_onionSkinDistance);
Shinya Kitaoka 120a6e
      pixScale[0] =
Shinya Kitaoka 120a6e
          (refColor.r / 255.0) * pixScale[3];  // refColor is not premultiplied
Shinya Kitaoka 120a6e
      pixScale[1] = (refColor.g / 255.0) * pixScale[3];
Shinya Kitaoka 120a6e
      pixScale[2] = (refColor.b / 255.0) * pixScale[3];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (player.m_opacity < 255) {
Shinya Kitaoka 120a6e
    pixScale[3] = player.m_opacity / 255.0;
Shinya Kitaoka 120a6e
    pixScale[0] = pixScale[1] = pixScale[2] = 0.0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build the Mesh-related data
Shinya Kitaoka 120a6e
  const TXshCell &cell =
Shinya Kitaoka 120a6e
      player.m_xsh->getCell(player.m_frame, playerObj->getParent().getIndex());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshSimpleLevel *meshLevel = cell.getSimpleLevel();
Shinya Kitaoka 120a6e
  const TFrameId &meshFid    = cell.getFrameId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TMeshImageP &mi = meshLevel->getFrame(meshFid, false);
Shinya Kitaoka 120a6e
  if (!mi) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build deformation-related data
Shinya Kitaoka 120a6e
  TStageObject *parentObj =
Shinya Kitaoka 120a6e
      player.m_xsh->getStageObject(playerObj->getParent());
Shinya Kitaoka 120a6e
  assert(playerObj);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const PlasticSkeletonDeformationP &deformation =
Shinya Kitaoka 120a6e
      parentObj->getPlasticSkeletonDeformation().getPointer();
Shinya Kitaoka 120a6e
  assert(deformation);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double sdFrame = parentObj->paramsTime(player.m_frame);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build dpis
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD meshSlDpi(meshLevel->getDpi(meshFid, 0));
Shinya Kitaoka 120a6e
  assert(meshSlDpi.x != 0.0 && meshSlDpi.y != 0.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD slDpi(player.m_sl ? player.m_sl->getDpi(player.m_fid, 0) : TPointD());
Shinya Kitaoka 120a6e
  if (slDpi.x == 0.0 || slDpi.y == 0.0 ||
Shinya Kitaoka 120a6e
      player.m_sl->getType() == PLI_XSHLEVEL)
Shinya Kitaoka 120a6e
    slDpi.x = slDpi.y = Stage::inch;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build reference transforms
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &worldTextureToWorldMeshAff =
Shinya Kitaoka 120a6e
      playerObj->getLocalPlacement(player.m_frame);
Shinya Kitaoka 120a6e
  const TAffine &worldTextureToWorldAff = player.m_placement;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fabs(worldTextureToWorldMeshAff.det()) < 1e-6)
Shinya Kitaoka 120a6e
    return;  // Skip near-singular mesh/texture placements
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &worldMeshToWorldTextureAff = worldTextureToWorldMeshAff.inv();
Shinya Kitaoka 120a6e
  const TAffine &worldMeshToWorldAff =
Shinya Kitaoka 120a6e
      worldTextureToWorldAff * worldMeshToWorldTextureAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &meshToWorldMeshAff =
Shinya Kitaoka 120a6e
      TScale(Stage::inch / meshSlDpi.x, Stage::inch / meshSlDpi.y);
Shinya Kitaoka 120a6e
  const TAffine &worldMeshToMeshAff =
Shinya Kitaoka 120a6e
      TScale(meshSlDpi.x / Stage::inch, meshSlDpi.y / Stage::inch);
Shinya Kitaoka 120a6e
  const TAffine &worldTextureToTextureAff = TScale(
Shinya Kitaoka 120a6e
      slDpi.x / Stage::inch,
Shinya Kitaoka 120a6e
      slDpi.y /
Shinya Kitaoka 120a6e
          Stage::inch);  // ::getDpiScale().inv() should be used instead...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &meshToWorldAff   = worldMeshToWorldAff * meshToWorldMeshAff;
Shinya Kitaoka 120a6e
  const TAffine &meshToTextureAff = worldTextureToTextureAff *
Shinya Kitaoka 120a6e
                                    worldMeshToWorldTextureAff *
Shinya Kitaoka 120a6e
                                    meshToWorldMeshAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve a drawable texture from the player's simple level
Shinya Kitaoka 120a6e
  const DrawableTextureDataP &texData = player.texture();
Shinya Kitaoka 120a6e
  if (!texData) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve the associated plastic deformers data (this may eventually update
Shinya Kitaoka 120a6e
  // the deforms)
Shinya Kitaoka 120a6e
  const PlasticDeformerDataGroup *dataGroup =
Shinya Kitaoka 120a6e
      PlasticDeformerStorage::instance()->process(
Shinya Kitaoka 120a6e
          sdFrame, mi.getPointer(), deformation.getPointer(),
Shinya Kitaoka 120a6e
          deformation->skeletonId(sdFrame), worldMeshToMeshAff);
Shinya Kitaoka 120a6e
  assert(dataGroup);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Set up OpenGL stuff
Shinya Kitaoka 120a6e
  glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
  glEnable(GL_LINE_SMOOTH);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Push mesh coordinates
Shinya Kitaoka 120a6e
  glPushMatrix();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tglMultMatrix(viewAff * meshToWorldAff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glEnable(GL_TEXTURE_2D);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Applying modulation by the specified transparency parameter
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glColor4d(pixScale[3], pixScale[3], pixScale[3], pixScale[3]);
Shinya Kitaoka 120a6e
  tglDraw(*mi, *texData, meshToTextureAff, *dataGroup);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glDisable(GL_TEXTURE_2D);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (onionSkinImage) {
Shinya Kitaoka 120a6e
    glBlendFunc(GL_ONE, GL_ONE);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Add Onion skin color. Observe that this way we don't consider blending
Shinya Kitaoka 120a6e
    // with the texture's
Shinya Kitaoka 120a6e
    // alpha - to obtain that, there is no simple way...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    double k = (1.0 - pixScale[3]);
Shinya Kitaoka 120a6e
    glColor4d(k * pixScale[0], k * pixScale[1], k * pixScale[2], 0.0);
Shinya Kitaoka 120a6e
    tglDrawFaces(*mi, dataGroup);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPopMatrix();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glDisable(GL_LINE_SMOOTH);
Shinya Kitaoka 120a6e
  glDisable(GL_BLEND);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace