Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Toonz includes
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tlevel_io.h"
Toshihiro Shimizu 890ddd
#include "tofflinegl.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
#include "tvectorrenderdata.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
shun-iwasawa c96e49
#include "tvectorgl.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Qt includes
Toshihiro Shimizu 890ddd
#include <qdir></qdir>
Toshihiro Shimizu 890ddd
#include <qimage></qimage>
shun-iwasawa c96e49
#include <qoffscreensurface></qoffscreensurface>
shun-iwasawa c96e49
#include <qthread></qthread>
shun-iwasawa c96e49
#include <qguiapplication></qguiapplication>
shun-iwasawa c96e49
#include <qopenglcontext></qopenglcontext>
shun-iwasawa c96e49
#include <qopenglframebufferobject></qopenglframebufferobject>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/stylemanager.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace stuff
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TFilePath rootPath;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void convertRaster32ToImage(TRaster32P ras, QImage *image) {
Shinya Kitaoka 120a6e
  int lx = ras->getLx();
Shinya Kitaoka 120a6e
  int ly = ras->getLy();
Shinya Kitaoka 120a6e
  int i, j;
Shinya Kitaoka 120a6e
  ras->lock();
Shinya Kitaoka 120a6e
  for (i = 0; i < lx; i++)
Shinya Kitaoka 120a6e
    for (j = 0; j < ly; j++) {
Shinya Kitaoka 120a6e
      TPixel32 pix = ras->pixels(ly - 1 - j)[i];
Shinya Kitaoka 120a6e
      QRgb value;
Shinya Kitaoka 120a6e
      value = qRgba(pix.r, pix.g, pix.b, pix.m);
Shinya Kitaoka 120a6e
      image->setPixel(i, j, value);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  ras->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    StyleLoaderTask definition
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class CustomStyleManager::StyleLoaderTask final : public TThread::Runnable {
Shinya Kitaoka 120a6e
  CustomStyleManager *m_manager;
Shinya Kitaoka 120a6e
  TFilePath m_fp;
Shinya Kitaoka 120a6e
  PatternData m_data;
shun-iwasawa c96e49
  std::shared_ptr<qoffscreensurface> m_offScreenSurface;</qoffscreensurface>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  StyleLoaderTask(CustomStyleManager *manager, const TFilePath &fp);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void run() override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void onFinished(TThread::RunnableP sender) override;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
CustomStyleManager::StyleLoaderTask::StyleLoaderTask(
Shinya Kitaoka 120a6e
    CustomStyleManager *manager, const TFilePath &fp)
Shinya Kitaoka 120a6e
    : m_manager(manager), m_fp(fp) {
Shinya Kitaoka 120a6e
  connect(this, SIGNAL(finished(TThread::RunnableP)), this,
Shinya Kitaoka 120a6e
          SLOT(onFinished(TThread::RunnableP)));
shun-iwasawa c96e49
shun-iwasawa c96e49
  if (QThread::currentThread() == qGuiApp->thread()) {
shun-iwasawa c96e49
    m_offScreenSurface.reset(new QOffscreenSurface());
shun-iwasawa c96e49
    m_offScreenSurface->setFormat(QSurfaceFormat::defaultFormat());
shun-iwasawa c96e49
    m_offScreenSurface->create();
shun-iwasawa c96e49
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void CustomStyleManager::StyleLoaderTask::run() {
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    // Fetch the level
Shinya Kitaoka 120a6e
    TLevelReaderP lr(m_fp);
Shinya Kitaoka 120a6e
    TLevelP level = lr->loadInfo();
Shinya Kitaoka 120a6e
    if (!level || level->getFrameCount() == 0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Fetch the image of the first frame in the level
Shinya Kitaoka 120a6e
    TLevel::Iterator frameIt = level->begin();
Shinya Kitaoka 120a6e
    if (frameIt == level->end()) return;
Shinya Kitaoka 120a6e
    TImageP img = lr->getFrameReader(frameIt->first)->load();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Process the image
Shinya Kitaoka 120a6e
    const QSize &qChipSize = m_manager->getChipSize();
Shinya Kitaoka 120a6e
    TDimension chipSize(qChipSize.width(), qChipSize.height());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TVectorImageP vimg = img;
Shinya Kitaoka 120a6e
    TRasterImageP rimg = img;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRaster32P ras;
shun-iwasawa c96e49
shun-iwasawa c96e49
    QImage *image = nullptr;
shun-iwasawa c96e49
Shinya Kitaoka 120a6e
    if (vimg) {
Shinya Kitaoka 120a6e
      assert(level->getPalette());
Shinya Kitaoka 120a6e
      TPalette *vPalette = level->getPalette();
Shinya Kitaoka 120a6e
      assert(vPalette);
Shinya Kitaoka 120a6e
      vimg->setPalette(vPalette);
Shinya Kitaoka 120a6e
shun-iwasawa c96e49
      QOpenGLContext *glContext = new QOpenGLContext();
shun-iwasawa c96e49
      if (QOpenGLContext::currentContext())
shun-iwasawa c96e49
        glContext->setShareContext(QOpenGLContext::currentContext());
shun-iwasawa c96e49
      glContext->setFormat(QSurfaceFormat::defaultFormat());
shun-iwasawa c96e49
      glContext->create();
shun-iwasawa c96e49
      glContext->makeCurrent(m_offScreenSurface.get());
shun-iwasawa c96e49
      // attaching stencil buffer here as some styles use it
shun-iwasawa c96e49
      QOpenGLFramebufferObject fb(
shun-iwasawa c96e49
          chipSize.lx, chipSize.ly,
shun-iwasawa c96e49
          QOpenGLFramebufferObject::CombinedDepthStencil);
shun-iwasawa c96e49
shun-iwasawa c96e49
      fb.bind();
shun-iwasawa c96e49
      // Draw
shun-iwasawa c96e49
      glViewport(0, 0, chipSize.lx, chipSize.ly);
shun-iwasawa c96e49
      glClearColor(1.0, 1.0, 1.0, 1.0);  // clear with white color
shun-iwasawa c96e49
      glClear(GL_COLOR_BUFFER_BIT);
shun-iwasawa c96e49
shun-iwasawa c96e49
      glMatrixMode(GL_PROJECTION);
shun-iwasawa c96e49
      glLoadIdentity();
shun-iwasawa c96e49
      gluOrtho2D(0, chipSize.lx, 0, chipSize.ly);
shun-iwasawa c96e49
shun-iwasawa c96e49
      glMatrixMode(GL_MODELVIEW);
shun-iwasawa c96e49
      glLoadIdentity();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TRectD bbox = img->getBBox();
Shinya Kitaoka 120a6e
      double scx  = 0.8 * chipSize.lx / bbox.getLx();
Shinya Kitaoka 120a6e
      double scy  = 0.8 * chipSize.ly / bbox.getLy();
Shinya Kitaoka 120a6e
      double sc   = std::min(scx, scy);
Shinya Kitaoka 120a6e
      double dx   = 0.5 * chipSize.lx;
Shinya Kitaoka 120a6e
      double dy   = 0.5 * chipSize.ly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TAffine aff =
Shinya Kitaoka 120a6e
          TTranslation(dx, dy) * TScale(sc) *
Shinya Kitaoka 120a6e
          TTranslation(-0.5 * (bbox.x0 + bbox.x1), -0.5 * (bbox.y0 + bbox.y1));
Shinya Kitaoka 120a6e
      TVectorRenderData rd(aff, chipSize, vPalette, 0, true);
Shinya Kitaoka 120a6e
shun-iwasawa c96e49
      tglDraw(rd, vimg.getPointer());
shun-iwasawa c96e49
shun-iwasawa c96e49
      image = new QImage(fb.toImage().scaled(QSize(chipSize.lx, chipSize.ly),
shun-iwasawa c96e49
                                             Qt::IgnoreAspectRatio,
shun-iwasawa c96e49
                                             Qt::SmoothTransformation));
shun-iwasawa c96e49
      fb.release();
shun-iwasawa c96e49
      glContext->deleteLater();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    } else if (rimg) {
Shinya Kitaoka 120a6e
      TDimension size = rimg->getRaster()->getSize();
Shinya Kitaoka 120a6e
      if (size == chipSize)
Shinya Kitaoka 120a6e
        ras = rimg->getRaster()->clone();  // Yep, this may be necessary
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        TRaster32P rout(chipSize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TRop::resample(rout, rimg->getRaster(),
Shinya Kitaoka 120a6e
                       TScale((double)chipSize.lx / size.lx,
Shinya Kitaoka 120a6e
                              (double)chipSize.ly / size.ly));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TRop::addBackground(rout, TPixel::White);
Shinya Kitaoka 120a6e
        ras = rout;
Shinya Kitaoka 120a6e
      }
shun-iwasawa c96e49
      image = new QImage(chipSize.lx, chipSize.ly, QImage::Format_RGB32);
shun-iwasawa c96e49
      convertRaster32ToImage(ras, image);
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      assert(!"unsupported type for custom styles!");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_data.m_patternName = m_fp.getName();
Shinya Kitaoka 120a6e
    m_data.m_isVector    = (m_fp.getType() == "pli" || m_fp.getType() == "svg");
Shinya Kitaoka 120a6e
    m_data.m_image       = image;
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void CustomStyleManager::StyleLoaderTask::onFinished(
Shinya Kitaoka 120a6e
    TThread::RunnableP sender) {
Shinya Kitaoka 120a6e
  // On the main thread...
Shinya Kitaoka 120a6e
  if (m_data.m_image)  // Everything went ok
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    m_manager->m_patterns.push_back(m_data);
Shinya Kitaoka 120a6e
    emit m_manager->patternAdded();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    CustomStyleManager implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
CustomStyleManager::CustomStyleManager(const TFilePath &stylesFolder,
Shinya Kitaoka 120a6e
                                       QString filters, QSize chipSize)
Shinya Kitaoka 120a6e
    : m_stylesFolder(stylesFolder), m_filters(filters), m_chipSize(chipSize) {
Shinya Kitaoka 120a6e
  m_executor.setMaxActiveTasks(1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int CustomStyleManager::getPatternCount() { return m_patterns.size(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
CustomStyleManager::PatternData CustomStyleManager::getPattern(int index) {
Shinya Kitaoka 120a6e
  return (index < 0 || index >= m_patterns.size()) ? PatternData()
Shinya Kitaoka 120a6e
                                                   : m_patterns[index];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFilePath CustomStyleManager::getRootPath() { return ::rootPath; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void CustomStyleManager::setRootPath(const TFilePath &rootPath) {
Shinya Kitaoka 120a6e
  ::rootPath = rootPath;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void CustomStyleManager::loadItems() {
Shinya Kitaoka 120a6e
  // Build the folder to be read
Shinya Kitaoka 120a6e
  const TFilePath &rootFP(getRootPath());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(rootFP != TFilePath());
Shinya Kitaoka 120a6e
  if (rootFP == TFilePath()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QDir patternDir(
Shinya Kitaoka 120a6e
      QString::fromStdWString((rootFP + m_stylesFolder).getWideString()));
Shinya Kitaoka 120a6e
  patternDir.setNameFilters(m_filters.split(' '));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Read the said folder
Shinya Kitaoka 120a6e
  TFilePathSet fps;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    TSystem::readDirectory(fps, patternDir);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Delete patterns no longer in the folder
Shinya Kitaoka 120a6e
  TFilePathSet newFps;
Shinya Kitaoka 120a6e
  TFilePathSet::iterator it;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_patterns.size(); i++) {
Shinya Kitaoka 120a6e
    PatternData data = m_patterns.at(i);
Shinya Kitaoka 120a6e
    for (it = fps.begin(); it != fps.end(); ++it) {
Shinya Kitaoka 120a6e
      if (data.m_patternName == it->getName() &&
Shinya Kitaoka 120a6e
          data.m_isVector == (it->getType() == "pli"))
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (it == fps.end()) {
Shinya Kitaoka 120a6e
      m_patterns.removeAt(i);
Shinya Kitaoka 120a6e
      i--;
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      fps.erase(it);  // The style is not new, so don't generate tasks for it
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // For each (now new) file entry, generate a fetching task
Shinya Kitaoka 120a6e
  for (TFilePathSet::iterator it = fps.begin(); it != fps.end(); it++)
Shinya Kitaoka 120a6e
    m_executor.addTask(new StyleLoaderTask(this, *it));
Toshihiro Shimizu 890ddd
}