Jeremy Bullock 764038
Jeremy Bullock 764038
#include "tiio_sprite.h"
Jeremy Bullock 764038
#include "../toonz/tapp.h"
Jeremy Bullock 764038
#include "tsystem.h"
Jeremy Bullock 764038
#include "tsound.h"
Jeremy Bullock 764038
Jeremy Bullock 764038
#include <qprocess></qprocess>
Jeremy Bullock 764038
#include <qdir></qdir>
Jeremy Bullock 764038
#include <qtgui qimage=""></qtgui>
Jeremy Bullock 764038
#include <qstringlist></qstringlist>
Jeremy Bullock 764038
#include <qpainter></qpainter>
Jeremy Bullock 764038
#include <qtextstream></qtextstream>
Jeremy Bullock 764038
#include "toonz/preferences.h"
Jeremy Bullock 764038
#include "toonz/toonzfolders.h"
Jeremy Bullock 764038
Jeremy Bullock 764038
#include "trasterimage.h"
Jeremy Bullock 764038
#include "timageinfo.h"
Jeremy Bullock 764038
Jeremy Bullock 764038
//===========================================================
Jeremy Bullock 764038
//
Jeremy Bullock 764038
//  TImageWriterSprite
Jeremy Bullock 764038
//
Jeremy Bullock 764038
//===========================================================
Jeremy Bullock 764038
Jeremy Bullock 764038
class TImageWriterSprite : public TImageWriter {
Jeremy Bullock 764038
public:
Jeremy Bullock 764038
  int m_frameIndex;
Jeremy Bullock 764038
Jeremy Bullock 764038
  TImageWriterSprite(const TFilePath &path, int frameIndex,
Jeremy Bullock 764038
                     TLevelWriterSprite *lwg)
Jeremy Bullock 764038
      : TImageWriter(path), m_frameIndex(frameIndex), m_lwg(lwg) {
Jeremy Bullock 764038
    m_lwg->addRef();
Jeremy Bullock 764038
  }
Jeremy Bullock 764038
  ~TImageWriterSprite() { m_lwg->release(); }
Jeremy Bullock 764038
Jeremy Bullock 764038
  bool is64bitOutputSupported() override { return false; }
Jeremy Bullock 764038
  void save(const TImageP &img) override { m_lwg->save(img, m_frameIndex); }
Jeremy Bullock 764038
Jeremy Bullock 764038
private:
Jeremy Bullock 764038
  TLevelWriterSprite *m_lwg;
Jeremy Bullock 764038
};
Jeremy Bullock 764038
Jeremy Bullock 764038
//===========================================================
Jeremy Bullock 764038
//
Jeremy Bullock 764038
//  TLevelWriterSprite;
Jeremy Bullock 764038
//
Jeremy Bullock 764038
//===========================================================
Jeremy Bullock 764038
Jeremy Bullock 764038
TLevelWriterSprite::TLevelWriterSprite(const TFilePath &path,
Jeremy Bullock 764038
                                       TPropertyGroup *winfo)
Jeremy Bullock 764038
    : TLevelWriter(path, winfo) {
Jeremy Bullock 764038
  if (!m_properties) m_properties = new Tiio::SpriteWriterProperties();
Jeremy Bullock 764038
  std::string scale = m_properties->getProperty("Scale")->getValueAsString();
Jeremy Bullock 764038
  m_scale           = QString::fromStdString(scale).toInt();
Jeremy Bullock 764038
  std::string topPadding =
Jeremy Bullock 764038
      m_properties->getProperty("Top Padding")->getValueAsString();
Jeremy Bullock 764038
  m_topPadding = QString::fromStdString(topPadding).toInt();
Jeremy Bullock 764038
  std::string bottomPadding =
Jeremy Bullock 764038
      m_properties->getProperty("Bottom Padding")->getValueAsString();
Jeremy Bullock 764038
  m_bottomPadding = QString::fromStdString(bottomPadding).toInt();
Jeremy Bullock 764038
  std::string leftPadding =
Jeremy Bullock 764038
      m_properties->getProperty("Left Padding")->getValueAsString();
Jeremy Bullock 764038
  m_leftPadding = QString::fromStdString(leftPadding).toInt();
Jeremy Bullock 764038
  std::string rightPadding =
Jeremy Bullock 764038
      m_properties->getProperty("Right Padding")->getValueAsString();
Jeremy Bullock 764038
  m_rightPadding = QString::fromStdString(rightPadding).toInt();
Jeremy Bullock 764038
  m_format       = QString::fromStdWString(
Jeremy Bullock 764038
      ((TEnumProperty *)(m_properties->getProperty("Format")))->getValue());
Jeremy Bullock 6f3194
  TBoolProperty *trim =
Jeremy Bullock 6f3194
      (TBoolProperty *)m_properties->getProperty("Trim Empty Space");
Jeremy Bullock 6f3194
  m_trim = trim->getValue();
Jeremy Bullock 764038
  if (TSystem::doesExistFileOrLevel(m_path)) TSystem::deleteFile(m_path);
Jeremy Bullock 764038
}
Jeremy Bullock 764038
Jeremy Bullock 764038
//-----------------------------------------------------------
Jeremy Bullock 764038
Jeremy Bullock 764038
TLevelWriterSprite::~TLevelWriterSprite() {
Jeremy Bullock 764038
  int finalWidth    = m_right - m_left + 1;
Jeremy Bullock 764038
  int finalHeight   = m_bottom - m_top + 1;
Jeremy Bullock 764038
  int resizedWidth  = finalWidth * m_scale / 100;
Jeremy Bullock 764038
  int resizedHeight = finalHeight * m_scale / 100;
Jeremy Bullock 764038
  for (QImage *image : m_images) {
Jeremy Bullock 764038
    QImage copy = image->copy(m_left, m_top, finalWidth, finalHeight);
Jeremy Bullock 764038
    if (m_scale != 100) {
Jeremy Bullock 764038
      int width  = (copy.width() * m_scale) / 100;
Jeremy Bullock 764038
      int height = (copy.height() * m_scale) / 100;
Jeremy Bullock 764038
      copy       = copy.scaled(width, height);
Jeremy Bullock 764038
    }
Jeremy Bullock 764038
    m_imagesResized.push_back(copy);
Jeremy Bullock 764038
  }
Jeremy Bullock 764038
  for (QImage *image : m_images) {
Jeremy Bullock 764038
    delete image;
Jeremy Bullock 764038
  }
Jeremy Bullock 764038
  m_images.clear();
Jeremy Bullock 764038
  int horizDim          = 1;
Jeremy Bullock 764038
  int vertDim           = 1;
Jeremy Bullock 764038
  int vertPadding       = m_topPadding + m_bottomPadding;
Jeremy Bullock 764038
  int horizPadding      = m_leftPadding + m_rightPadding;
Jeremy Bullock 764038
  int totalVertPadding  = 0;
Jeremy Bullock 764038
  int totalHorizPadding = 0;
Jeremy Bullock 764038
  int spriteSheetWidth;
Jeremy Bullock 764038
  int spriteSheetHeight;
Jeremy Bullock 764038
  if (m_format == "Grid") {
Jeremy Bullock 59344b
    // Calculate Grid Size
Jeremy Bullock 764038
    while (horizDim * horizDim < m_imagesResized.size()) horizDim++;
Jeremy Bullock 764038
    totalHorizPadding = horizDim * horizPadding;
Jeremy Bullock 764038
    spriteSheetWidth  = horizDim * resizedWidth + totalHorizPadding;
Jeremy Bullock 764038
    vertDim           = horizDim;
shun-iwasawa e6b124
    // Figure out if there is one row too many
Jeremy Bullock dac269
    // (Such as 6 images needs 3 x 2 grid)
Jeremy Bullock 764038
    if (vertDim * vertDim - vertDim >= m_imagesResized.size()) {
Jeremy Bullock dac269
      vertDim = vertDim - 1;
Jeremy Bullock 764038
    }
Jeremy Bullock dac269
    totalVertPadding  = vertDim * vertPadding;
Jeremy Bullock 764038
    spriteSheetHeight = vertDim * resizedHeight + totalVertPadding;
Jeremy Bullock 764038
  } else if (m_format == "Vertical") {
Jeremy Bullock 764038
    spriteSheetWidth  = resizedWidth + horizPadding;
Jeremy Bullock 764038
    spriteSheetHeight = m_imagesResized.size() * (resizedHeight + vertPadding);
Jeremy Bullock 764038
    vertDim           = m_imagesResized.size();
Jeremy Bullock 764038
  } else if (m_format == "Horizontal") {
Jeremy Bullock 764038
    spriteSheetWidth  = m_imagesResized.size() * (resizedWidth + horizPadding);
Jeremy Bullock 764038
    spriteSheetHeight = resizedHeight + vertPadding;
Jeremy Bullock dac269
    horizDim          = m_imagesResized.size();
Jeremy Bullock dac269
  } else if (m_format == "Individual") {
Jeremy Bullock dac269
    for (int i = 0; i < m_imagesResized.size(); i++) {
Jeremy Bullock dac269
      QString path      = m_path.getQString();
Jeremy Bullock dac269
      QString newEnding = "_" + QString::number(i) + ".png";
Jeremy Bullock dac269
      path              = path.replace(".spritesheet", newEnding);
Jeremy Bullock dac269
      m_imagesResized[i].save(path, "PNG", -1);
Jeremy Bullock dac269
    }
Jeremy Bullock 764038
  }
Jeremy Bullock dac269
  if (m_format != "Individual") {
shun-iwasawa e6b124
    QImage spriteSheet = QImage(spriteSheetWidth, spriteSheetHeight,
shun-iwasawa e6b124
                                QImage::Format_ARGB32_Premultiplied);
Jeremy Bullock dac269
    spriteSheet.fill(qRgba(0, 0, 0, 0));
Jeremy Bullock dac269
    QPainter painter;
Jeremy Bullock dac269
    painter.begin(&spriteSheet);
Jeremy Bullock dac269
    int row    = 0;
Jeremy Bullock dac269
    int column = 0;
Jeremy Bullock dac269
    int rowPadding;
Jeremy Bullock dac269
    int columnPadding;
Jeremy Bullock dac269
    int currentImage = 0;
Jeremy Bullock dac269
    while (row < vertDim) {
Jeremy Bullock dac269
      while (column < horizDim) {
Jeremy Bullock dac269
        rowPadding    = m_topPadding;
Jeremy Bullock dac269
        columnPadding = m_leftPadding;
Jeremy Bullock dac269
        rowPadding += row * vertPadding;
Jeremy Bullock dac269
        columnPadding += column * horizPadding;
Jeremy Bullock dac269
        painter.drawImage(column * resizedWidth + columnPadding,
Jeremy Bullock dac269
                          row * resizedHeight + rowPadding,
Jeremy Bullock dac269
                          m_imagesResized[currentImage]);
Jeremy Bullock dac269
        currentImage++;
Jeremy Bullock dac269
        column++;
Jeremy Bullock dac269
        if (currentImage >= m_imagesResized.size()) break;
Jeremy Bullock dac269
      }
Jeremy Bullock dac269
      column = 0;
Jeremy Bullock dac269
      row++;
Jeremy Bullock 764038
      if (currentImage >= m_imagesResized.size()) break;
Jeremy Bullock 764038
    }
Jeremy Bullock dac269
    painter.end();
Jeremy Bullock dac269
    QString path = m_path.getQString();
Jeremy Bullock dac269
    path         = path.replace(".spritesheet", ".png");
Jeremy Bullock dac269
    spriteSheet.save(path, "PNG", -1);
Jeremy Bullock 764038
Jeremy Bullock dac269
    path = path.replace(".png", ".txt");
Jeremy Bullock dac269
    QFile file(path);
Jeremy Bullock dac269
    file.open(QIODevice::WriteOnly | QIODevice::Text);
Jeremy Bullock dac269
    QTextStream out(&file);
Jeremy Bullock dac269
    out << "Total Images: " << m_imagesResized.size() << "\n";
Jeremy Bullock dac269
    out << "Individual Image Width: " << resizedWidth << "\n";
Jeremy Bullock dac269
    out << "Individual Image Height: " << resizedHeight << "\n";
Jeremy Bullock dac269
    out << "Individual Image Width with Padding: "
Jeremy Bullock dac269
        << resizedWidth + horizPadding << "\n";
Jeremy Bullock dac269
    out << "Individual Image Height with Padding: "
Jeremy Bullock dac269
        << resizedHeight + vertPadding << "\n";
Jeremy Bullock dac269
    out << "Images Across: " << horizDim << "\n";
Jeremy Bullock dac269
    out << "Images Down : " << vertDim << "\n";
Jeremy Bullock dac269
    out << "Top Padding: " << m_topPadding << "\n";
Jeremy Bullock dac269
    out << "Bottom Padding: " << m_bottomPadding << "\n";
Jeremy Bullock dac269
    out << "Left Padding: " << m_leftPadding << "\n";
Jeremy Bullock dac269
    out << "Right Padding: " << m_rightPadding << "\n";
Jeremy Bullock dac269
    out << "Horizontal Space Between Images: " << horizPadding << "\n";
Jeremy Bullock dac269
    out << "Vertical Space Between Images: " << vertPadding << "\n";
Jeremy Bullock 764038
Jeremy Bullock dac269
    file.close();
Jeremy Bullock dac269
  }
Jeremy Bullock 764038
  m_imagesResized.clear();
Jeremy Bullock 764038
}
Jeremy Bullock 764038
Jeremy Bullock 764038
//-----------------------------------------------------------
Jeremy Bullock 764038
Jeremy Bullock 764038
TImageWriterP TLevelWriterSprite::getFrameWriter(TFrameId fid) {
Jeremy Bullock 764038
  if (fid.getLetter() != 0) return TImageWriterP(0);
Jeremy Bullock 764038
  int index               = fid.getNumber();
Jeremy Bullock 764038
  TImageWriterSprite *iwg = new TImageWriterSprite(m_path, index, this);
Jeremy Bullock 764038
  return TImageWriterP(iwg);
Jeremy Bullock 764038
}
Jeremy Bullock 764038
Jeremy Bullock 764038
//-----------------------------------------------------------
Jeremy Bullock 764038
void TLevelWriterSprite::setFrameRate(double fps) {}
Jeremy Bullock 764038
Jeremy Bullock 764038
void TLevelWriterSprite::saveSoundTrack(TSoundTrack *st) {}
Jeremy Bullock 764038
Jeremy Bullock 764038
//-----------------------------------------------------------
Jeremy Bullock 764038
Jeremy Bullock 764038
void TLevelWriterSprite::save(const TImageP &img, int frameIndex) {
Jeremy Bullock 63a3d7
  m_frameIndexOrder.push_back(frameIndex);
Jeremy Bullock 63a3d7
  std::sort(m_frameIndexOrder.begin(), m_frameIndexOrder.end());
Jeremy Bullock 764038
  TRasterImageP tempImage(img);
Jeremy Bullock 764038
  TRasterImage *image = (TRasterImage *)tempImage->cloneImage();
Jeremy Bullock 764038
Jeremy Bullock 764038
  m_lx           = image->getRaster()->getLx();
Jeremy Bullock 764038
  m_ly           = image->getRaster()->getLy();
Jeremy Bullock 764038
  int m_bpp      = image->getRaster()->getPixelSize();
Jeremy Bullock 764038
  int totalBytes = m_lx * m_ly * m_bpp;
Jeremy Bullock 764038
  image->getRaster()->yMirror();
Jeremy Bullock 764038
Jeremy Bullock 764038
  // lock raster to get data
Jeremy Bullock 764038
  image->getRaster()->lock();
Jeremy Bullock 764038
  void *buffin = image->getRaster()->getRawData();
Jeremy Bullock 764038
  assert(buffin);
Jeremy Bullock 764038
  void *buffer = malloc(totalBytes);
Jeremy Bullock 764038
  memcpy(buffer, buffin, totalBytes);
Jeremy Bullock 764038
Jeremy Bullock 764038
  image->getRaster()->unlock();
Jeremy Bullock 764038
Jeremy Bullock 764038
  // create QImage save format
Jeremy Bullock 764038
  QString m_intermediateFormat = "png";
Jeremy Bullock 764038
  QByteArray ba                = m_intermediateFormat.toUpper().toLatin1();
Jeremy Bullock 764038
  const char *format           = ba.data();
Jeremy Bullock 764038
shun-iwasawa e6b124
  QImage *qi = new QImage((uint8_t *)buffer, m_lx, m_ly,
shun-iwasawa e6b124
                          QImage::Format_ARGB32_Premultiplied);
Jeremy Bullock 764038
Jeremy Bullock 764038
  int l = qi->width(), r = 0, t = qi->height(), b = 0;
Jeremy Bullock 6f3194
  if (m_trim) {
Jeremy Bullock 6f3194
    for (int y = 0; y < qi->height(); ++y) {
Jeremy Bullock 6f3194
      QRgb *row      = (QRgb *)qi->scanLine(y);
Jeremy Bullock 6f3194
      bool rowFilled = false;
Jeremy Bullock 6f3194
      for (int x = 0; x < qi->width(); ++x) {
Jeremy Bullock 6f3194
        if (qAlpha(row[x])) {
Jeremy Bullock 6f3194
          rowFilled = true;
Jeremy Bullock 6f3194
          r         = std::max(r, x);
Jeremy Bullock 6f3194
          if (l > x) {
Jeremy Bullock 6f3194
            l = x;
Jeremy Bullock 6f3194
            x = r;
Jeremy Bullock 6f3194
          }
Jeremy Bullock 764038
        }
Jeremy Bullock 764038
      }
Jeremy Bullock 6f3194
      if (rowFilled) {
Jeremy Bullock 6f3194
        t = std::min(t, y);
Jeremy Bullock 6f3194
        b = y;
Jeremy Bullock 6f3194
      }
Jeremy Bullock 764038
    }
Jeremy Bullock 6f3194
  } else {
Jeremy Bullock 6f3194
    l = 0;
Jeremy Bullock 6f3194
    r = qi->width() - 1;
Jeremy Bullock 6f3194
    t = 0;
Jeremy Bullock 6f3194
    b = qi->height() - 1;
Jeremy Bullock 764038
  }
Jeremy Bullock 764038
  if (m_firstPass) {
Jeremy Bullock 764038
    m_firstPass = false;
Jeremy Bullock 764038
    m_left      = l;
Jeremy Bullock 764038
    m_right     = r;
Jeremy Bullock 764038
    m_top       = t;
Jeremy Bullock 764038
    m_bottom    = b;
Jeremy Bullock 764038
  } else {
Jeremy Bullock 764038
    if (l < m_left) m_left     = l;
Jeremy Bullock 764038
    if (r > m_right) m_right   = r;
Jeremy Bullock 764038
    if (t < m_top) m_top       = t;
Jeremy Bullock 764038
    if (b > m_bottom) m_bottom = b;
Jeremy Bullock 764038
  }
shun-iwasawa e6b124
  QImage *newQi = new QImage(m_lx, m_ly, QImage::Format_ARGB32_Premultiplied);
Jeremy Bullock 764038
  newQi->fill(qRgba(0, 0, 0, 0));
Jeremy Bullock 764038
  QPainter painter(newQi);
Jeremy Bullock 764038
  painter.drawImage(QPoint(0, 0), *qi);
Jeremy Bullock 63a3d7
Jeremy Bullock 63a3d7
  // Make sure to order the images according to their frame index
Jeremy Bullock 63a3d7
  // Not just what comes out first
Jeremy Bullock 63a3d7
  std::vector<int>::iterator it;</int>
Jeremy Bullock 63a3d7
  it = find(m_frameIndexOrder.begin(), m_frameIndexOrder.end(), frameIndex);
Jeremy Bullock 63a3d7
  int pos = std::distance(m_frameIndexOrder.begin(), it);
Jeremy Bullock 63a3d7
Jeremy Bullock 63a3d7
  m_images.insert(m_images.begin() + pos, newQi);
Jeremy Bullock 764038
  delete image;
Jeremy Bullock 764038
  delete qi;
Jeremy Bullock 764038
  free(buffer);
Jeremy Bullock 764038
}
Jeremy Bullock 764038
Jeremy Bullock 764038
Tiio::SpriteWriterProperties::SpriteWriterProperties()
Jeremy Bullock 764038
    : m_topPadding("Top Padding", 0, 100, 0)
Jeremy Bullock 764038
    , m_bottomPadding("Bottom Padding", 0, 100, 0)
Jeremy Bullock 764038
    , m_leftPadding("Left Padding", 0, 100, 0)
Jeremy Bullock 764038
    , m_rightPadding("Right Padding", 0, 100, 0)
Jeremy Bullock 764038
    , m_scale("Scale", 1, 100, 100)
Jeremy Bullock 6f3194
    , m_format("Format")
Jeremy Bullock 6f3194
    , m_trim("Trim Empty Space", true) {
Jeremy Bullock 764038
  m_format.addValue(L"Grid");
Jeremy Bullock 764038
  m_format.addValue(L"Vertical");
Jeremy Bullock 764038
  m_format.addValue(L"Horizontal");
Jeremy Bullock dac269
  m_format.addValue(L"Individual");
Jeremy Bullock 764038
  m_format.setValue(L"Grid");
Jeremy Bullock 764038
  bind(m_format);
Jeremy Bullock 764038
  bind(m_topPadding);
Jeremy Bullock 764038
  bind(m_bottomPadding);
Jeremy Bullock 764038
  bind(m_leftPadding);
Jeremy Bullock 764038
  bind(m_rightPadding);
Jeremy Bullock 764038
  bind(m_scale);
Jeremy Bullock 6f3194
  bind(m_trim);
Jeremy Bullock 764038
}
Jeremy Bullock 764038
Jeremy Bullock 764038
// Tiio::Reader* Tiio::makeSpriteReader(){ return nullptr; }
Jeremy Bullock 764038
// Tiio::Writer* Tiio::makeSpriteWriter(){ return nullptr; }