|
justburner |
0be1bc |
#include "ocaio.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include "tsystem.h"
|
|
justburner |
0be1bc |
#include "tenv.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include "toonz/tcamera.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include "toonz/toonzscene.h"
|
|
justburner |
0be1bc |
#include "toonz/tproject.h"
|
|
justburner |
0be1bc |
#include "toonz/levelset.h"
|
|
justburner |
0be1bc |
#include "toonz/txsheet.h"
|
|
justburner |
0be1bc |
#include "toonz/txshcell.h"
|
|
justburner |
0be1bc |
#include "toonz/txshsimplelevel.h"
|
|
justburner |
0be1bc |
#include "toonz/txshchildlevel.h"
|
|
justburner |
0be1bc |
#include "toonz/txsheethandle.h"
|
|
justburner |
0be1bc |
#include "toonz/tscenehandle.h"
|
|
justburner |
0be1bc |
#include "toonz/preferences.h"
|
|
justburner |
0be1bc |
#include "toonz/sceneproperties.h"
|
|
justburner |
0be1bc |
#include "toonz/tstageobject.h"
|
|
justburner |
0be1bc |
#include "toutputproperties.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include "toonzqt/gutil.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include "tapp.h"
|
|
justburner |
0be1bc |
#include "menubarcommandids.h"
|
|
justburner |
0be1bc |
#include "filebrowserpopup.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include "tiio.h"
|
|
justburner |
0be1bc |
#include "timage_io.h"
|
|
justburner |
0be1bc |
#include "tlevel_io.h"
|
|
justburner |
0be1bc |
#include "tvectorimage.h"
|
|
justburner |
0be1bc |
#include "exportlevelcommand.h"
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include <qjsonobject></qjsonobject>
|
|
justburner |
0be1bc |
#include <qjsonarray></qjsonarray>
|
|
justburner |
0be1bc |
#include <qjsondocument></qjsondocument>
|
|
justburner |
0be1bc |
#include <qdesktopservices></qdesktopservices>
|
|
justburner |
0be1bc |
#include <qcoreapplication></qcoreapplication>
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
#include <qwidget></qwidget>
|
|
justburner |
0be1bc |
#include <qlabel></qlabel>
|
|
justburner |
0be1bc |
#include <qspinbox></qspinbox>
|
|
justburner |
0be1bc |
#include <qcheckbox></qcheckbox>
|
|
justburner |
0be1bc |
#include <qvboxlayout></qvboxlayout>
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
using namespace OCAIo;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
void OCAData::write(QJsonObject &json) const {
|
|
justburner |
0be1bc |
// Header
|
|
justburner |
0be1bc |
json["name"] = m_name;
|
|
justburner |
0be1bc |
json["frameRate"] = m_framerate;
|
|
justburner |
0be1bc |
json["width"] = m_width;
|
|
justburner |
0be1bc |
json["height"] = m_height;
|
|
justburner |
0be1bc |
json["startTime"] = m_startTime + m_stOff;
|
|
justburner |
0be1bc |
json["endTime"] = m_endTime + m_stOff;
|
|
justburner |
0be1bc |
json["colorDepth"] = m_raEXR ? "U16" : "U8";
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Background color
|
|
justburner |
0be1bc |
QJsonArray bgColorArray;
|
|
justburner |
0be1bc |
bgColorArray.append(m_bgRed);
|
|
justburner |
0be1bc |
bgColorArray.append(m_bgGreen);
|
|
justburner |
0be1bc |
bgColorArray.append(m_bgBlue);
|
|
justburner |
0be1bc |
bgColorArray.append(m_bgAlpha);
|
|
justburner |
0be1bc |
json["backgroundColor"] = bgColorArray;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Layers
|
|
justburner |
0be1bc |
json["layers"] = m_layers;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Versions
|
|
justburner |
0be1bc |
json["originApp"] = "OpenToonz";
|
|
justburner |
0be1bc |
json["originAppVersion"] =
|
|
justburner |
0be1bc |
QString::fromStdString(TEnv::getApplicationVersion());
|
|
justburner |
0be1bc |
json["ocaVersion"] = "1.1.0";
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
shun-iwasawa |
a807ce |
int OCAData::frameLen(TXshCellColumn *column, const QList<int> &rows,</int>
|
|
shun-iwasawa |
a807ce |
int index) {
|
|
justburner |
0be1bc |
// Next cells must match same level and frame-id
|
|
shun-iwasawa |
a807ce |
int length = 0;
|
|
justburner |
0be1bc |
const TXshCell &stc = column->getCell(rows[index]);
|
|
justburner |
0be1bc |
for (int i = index; i < rows.count(); i++) {
|
|
justburner |
0be1bc |
int currentRow = rows[i];
|
|
justburner |
0be1bc |
const TXshCell &cell = column->getCell(currentRow);
|
|
justburner |
0be1bc |
if (stc.m_frameId != cell.m_frameId || stc.m_level != cell.m_level) break;
|
|
justburner |
0be1bc |
length++;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
return length;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
bool OCAData::isBlank(TXshCellColumn *column, int row) {
|
|
justburner |
0be1bc |
TXshCell cell = column->getCell(row);
|
|
justburner |
0be1bc |
return cell.isEmpty();
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
bool OCAData::getLayerName(TXshCellColumn *column, QString &out) {
|
|
justburner |
0be1bc |
// Layer name will be the first cel that occur on the column
|
|
justburner |
0be1bc |
TXshCell cell = column->getCell(column->getFirstRow());
|
|
justburner |
0be1bc |
if (cell.isEmpty()) return false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
out = QString::fromStdWString(cell.m_level->getName());
|
|
justburner |
0be1bc |
return true;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
bool OCAData::getCellName(TXshCellColumn *column, int row, QString &out) {
|
|
justburner |
0be1bc |
TXshCell cell = column->getCell(row);
|
|
justburner |
0be1bc |
if (cell.isEmpty()) return false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
TFilePath fp(cell.m_level->getName());
|
|
shun-iwasawa |
a807ce |
fp = fp.withFrame(cell.getFrameId(), TFrameId::FrameFormat::FOUR_ZEROS);
|
|
justburner |
0be1bc |
out = fp.getQString();
|
|
justburner |
0be1bc |
return true;
|
|
shun-iwasawa |
a807ce |
}
|
|
justburner |
0be1bc |
|
|
shun-iwasawa |
a807ce |
bool OCAData::saveCell(TXshCellColumn *column, int row, const QString &cellname,
|
|
shun-iwasawa |
a807ce |
OCAAsset &out) {
|
|
shun-iwasawa |
a807ce |
TXshCell cell = column->getCell(row);
|
|
justburner |
0be1bc |
TXshSimpleLevel *sl = cell.getSimpleLevel();
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
std::string format = m_raEXR ? "exr" : "png";
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Rasterize cell
|
|
justburner |
0be1bc |
TImageP image = IoCmd::exportedImage(format, *sl, cell.getFrameId());
|
|
justburner |
0be1bc |
if (!image) return false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (TRasterImageP ri = (TRasterImageP)(image)) {
|
|
justburner |
0be1bc |
TRasterP raster;
|
|
shun-iwasawa |
a807ce |
raster = ri->getRaster();
|
|
justburner |
0be1bc |
out.width = raster->getLx();
|
|
justburner |
0be1bc |
out.height = raster->getLy();
|
|
justburner |
0be1bc |
if (!raster) return false;
|
|
justburner |
0be1bc |
} else {
|
|
justburner |
0be1bc |
return false;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
out.fileExt = QString::fromStdString(format);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (m_veSVG) {
|
|
justburner |
0be1bc |
// Get vector image directly and discard rasterized image
|
|
justburner |
0be1bc |
TVectorImageP vectorImg = cell.getImage(false);
|
|
justburner |
0be1bc |
if (vectorImg) {
|
|
justburner |
0be1bc |
image = vectorImg;
|
|
justburner |
0be1bc |
out.fileExt = "svg";
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QString filename = QString("/%1.%2").arg(cellname, out.fileExt);
|
|
justburner |
0be1bc |
TFilePath fpr(m_path);
|
|
justburner |
0be1bc |
TFilePath fpa(m_path + filename);
|
|
justburner |
0be1bc |
out.fileName = QString::fromStdWString(fpr.getWideName()) + filename;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
TLevelWriterP lw(fpa);
|
|
justburner |
0be1bc |
lw->setFrameRate(m_framerate);
|
|
justburner |
0be1bc |
TImageWriterP iw = lw->getFrameWriter(cell.getFrameId());
|
|
shun-iwasawa |
a807ce |
iw->setFilePath(fpa); // Added to aid my own sanity!
|
|
justburner |
0be1bc |
iw->save(image);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
return true;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
bool OCAData::isGroup(TXshCellColumn *column) {
|
|
justburner |
0be1bc |
TXshCell firstcell = column->getCell(column->getFirstRow());
|
|
justburner |
0be1bc |
TXshChildLevel *cl = firstcell.getChildLevel();
|
|
justburner |
0be1bc |
return cl;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
bool OCAData::buildGroup(QJsonObject &json, const QList<int> &rows,</int>
|
|
justburner |
0be1bc |
TXshCellColumn *column) {
|
|
justburner |
0be1bc |
QString layername;
|
|
justburner |
0be1bc |
if (!getLayerName(column, layername)) return false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Get sub-xsheet
|
|
justburner |
0be1bc |
int firstrow = column->getFirstRow();
|
|
justburner |
0be1bc |
TXshCell firstcell = column->getCell(firstrow);
|
|
justburner |
0be1bc |
TXshChildLevel *cl = firstcell.getChildLevel();
|
|
shun-iwasawa |
a807ce |
TXsheet *xsheet = cl->getXsheet();
|
|
justburner |
0be1bc |
if (!xsheet) return false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Build a list of child rows
|
|
justburner |
0be1bc |
QList<int> crows;</int>
|
|
justburner |
0be1bc |
for (int i = m_startTime; i <= m_endTime; i++) {
|
|
justburner |
0be1bc |
TXshCell cell = column->getCell(i);
|
|
justburner |
0be1bc |
if (cell.isEmpty())
|
|
justburner |
0be1bc |
crows.append(-1);
|
|
justburner |
0be1bc |
else
|
|
justburner |
0be1bc |
crows.append(cell.getFrameId().getNumber() - 1);
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Build all columns from sub-xsheet
|
|
justburner |
0be1bc |
int subID = ++m_subId;
|
|
justburner |
0be1bc |
QJsonArray layers;
|
|
justburner |
0be1bc |
for (int col = 0; col < xsheet->getFirstFreeColumnIndex(); col++) {
|
|
justburner |
0be1bc |
if (xsheet->isColumnEmpty(col)) continue;
|
|
justburner |
0be1bc |
TXshCellColumn *column = xsheet->getColumn(col)->getCellColumn();
|
|
justburner |
0be1bc |
if (!column) continue; // skip non-cell column
|
|
justburner |
0be1bc |
if (!column->isPreviewVisible()) continue; // skip inactive column
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (column->getColumnType() == column->eLevelType) {
|
|
justburner |
0be1bc |
QJsonObject json;
|
|
justburner |
0be1bc |
if (isGroup(column)) {
|
|
justburner |
0be1bc |
if (buildGroup(json, crows, column)) layers.append(json);
|
|
justburner |
0be1bc |
} else {
|
|
justburner |
0be1bc |
if (buildLayer(json, crows, column)) layers.append(json);
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QJsonArray jsonBlankPos;
|
|
justburner |
0be1bc |
jsonBlankPos.append(m_width / 2);
|
|
justburner |
0be1bc |
jsonBlankPos.append(m_height / 2);
|
|
justburner |
0be1bc |
json["name"] = layername;
|
|
justburner |
0be1bc |
json["position"] = jsonBlankPos;
|
|
justburner |
0be1bc |
json["width"] = m_width;
|
|
justburner |
0be1bc |
json["height"] = m_height;
|
|
justburner |
0be1bc |
json["frames"] = QJsonArray();
|
|
justburner |
0be1bc |
json["childLayers"] = layers;
|
|
justburner |
0be1bc |
json["type"] = "grouplayer";
|
|
justburner |
0be1bc |
json["fileType"] = "png";
|
|
justburner |
0be1bc |
json["blendingMode"] = "normal";
|
|
justburner |
0be1bc |
json["animated"] = false;
|
|
justburner |
0be1bc |
json["label"] = 0;
|
|
justburner |
0be1bc |
json["opacity"] = column->getOpacity() / 255.0;
|
|
justburner |
0be1bc |
json["visible"] = column->isCamstandVisible();
|
|
justburner |
0be1bc |
json["passThrough"] = false;
|
|
justburner |
0be1bc |
json["reference"] = false;
|
|
justburner |
0be1bc |
json["inheritAlpha"] = false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
return true;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
bool OCAData::buildLayer(QJsonObject &json, const QList<int> &rows,</int>
|
|
justburner |
0be1bc |
TXshCellColumn *column) {
|
|
justburner |
0be1bc |
QJsonArray jsonFrames;
|
|
justburner |
0be1bc |
bool firstcel = true;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Layer name will be the first cel that occur on the column
|
|
justburner |
0be1bc |
int firstrow = column->getFirstRow();
|
|
justburner |
0be1bc |
QString layername;
|
|
justburner |
0be1bc |
QString cellname;
|
|
justburner |
0be1bc |
if (!getLayerName(column, layername)) return false;
|
|
justburner |
0be1bc |
if (!getCellName(column, firstrow, cellname)) return false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QJsonArray jsonBlankPos;
|
|
justburner |
0be1bc |
jsonBlankPos.append(m_width / 2);
|
|
justburner |
0be1bc |
jsonBlankPos.append(m_height / 2);
|
|
justburner |
0be1bc |
json["name"] = layername;
|
|
justburner |
0be1bc |
json["position"] = jsonBlankPos;
|
|
justburner |
0be1bc |
json["width"] = 0;
|
|
justburner |
0be1bc |
json["height"] = 0;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
for (int i = 0; i < rows.count(); i++) {
|
|
justburner |
0be1bc |
int row = rows[i];
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QJsonObject frame;
|
|
justburner |
0be1bc |
QJsonArray jsonPosition;
|
|
justburner |
0be1bc |
jsonPosition.append(m_width / 2);
|
|
justburner |
0be1bc |
jsonPosition.append(m_height / 2);
|
|
justburner |
0be1bc |
int len = frameLen(column, rows, i);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
frame["frameNumber"] = i + m_stOff;
|
|
justburner |
0be1bc |
frame["position"] = jsonPosition;
|
|
justburner |
0be1bc |
frame["opacity"] = 1.0; // OT uses Transparency Fx node
|
|
justburner |
0be1bc |
frame["duration"] = len;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (isBlank(column, row)) {
|
|
shun-iwasawa |
a807ce |
frame["name"] = "_blank";
|
|
shun-iwasawa |
a807ce |
frame["fileName"] = "";
|
|
shun-iwasawa |
a807ce |
frame["width"] = 0;
|
|
shun-iwasawa |
a807ce |
frame["height"] = 0;
|
|
justburner |
0be1bc |
} else {
|
|
justburner |
0be1bc |
// Cell name will be used for the frame name
|
|
justburner |
0be1bc |
if (!getCellName(column, row, cellname)) continue;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Save cell image as an asset
|
|
justburner |
0be1bc |
OCAAsset asset;
|
|
justburner |
0be1bc |
if (!m_assets.contains(cellname)) {
|
|
justburner |
0be1bc |
if (!saveCell(column, row, cellname, asset)) return false;
|
|
justburner |
0be1bc |
m_assets.insert(cellname, asset);
|
|
justburner |
0be1bc |
} else {
|
|
justburner |
0be1bc |
asset = m_assets.value(cellname);
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
frame["name"] = cellname;
|
|
justburner |
0be1bc |
frame["fileName"] = asset.fileName;
|
|
justburner |
0be1bc |
frame["width"] = asset.width;
|
|
justburner |
0be1bc |
frame["height"] = asset.height;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (firstcel) {
|
|
justburner |
0be1bc |
// Layer size and type will depend of the first cell too
|
|
justburner |
0be1bc |
json["width"] = asset.width;
|
|
justburner |
0be1bc |
json["height"] = asset.height;
|
|
justburner |
0be1bc |
json["fileType"] = asset.fileExt;
|
|
justburner |
0be1bc |
firstcel = false;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
jsonFrames.append(frame);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
i += len - 1;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
json["frames"] = jsonFrames;
|
|
justburner |
0be1bc |
json["childLayers"] = QJsonArray();
|
|
justburner |
0be1bc |
json["type"] = "paintlayer";
|
|
justburner |
0be1bc |
json["blendingMode"] = "normal"; // OT uses nodes Fx to make blending
|
|
justburner |
0be1bc |
// possible, how to approach this?
|
|
justburner |
0be1bc |
json["animated"] = jsonFrames.count() >= 2;
|
|
justburner |
0be1bc |
json["label"] = 0; // OT doesn't support labels
|
|
justburner |
0be1bc |
json["opacity"] = column->getOpacity() / 255.0;
|
|
justburner |
0be1bc |
json["visible"] = column->isCamstandVisible();
|
|
justburner |
0be1bc |
json["passThrough"] = false;
|
|
justburner |
0be1bc |
json["reference"] = false;
|
|
justburner |
0be1bc |
json["inheritAlpha"] = false;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
return true;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
void OCAData::setProgressDialog(DVGui::ProgressDialog *dialog) {
|
|
justburner |
0be1bc |
m_progressDialog = dialog;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
void OCAData::build(ToonzScene *scene, TXsheet *xsheet, QString name,
|
|
justburner |
0be1bc |
QString path, int startOffset, bool useEXR,
|
|
justburner |
0be1bc |
bool vectorAsSVG) {
|
|
justburner |
0be1bc |
m_name = name;
|
|
justburner |
0be1bc |
m_path = path;
|
|
justburner |
0be1bc |
m_subId = 0;
|
|
justburner |
0be1bc |
m_raEXR = useEXR;
|
|
justburner |
0be1bc |
m_veSVG = vectorAsSVG;
|
|
justburner |
0be1bc |
m_stOff = startOffset;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// if the current xsheet is top xsheet in the scene and the output
|
|
justburner |
0be1bc |
// frame range is specified, set the "to" frame value as duration
|
|
justburner |
0be1bc |
TOutputProperties *oprop = scene->getProperties()->getOutputProperties();
|
|
justburner |
0be1bc |
int from, to, step;
|
|
justburner |
0be1bc |
if (scene->getTopXsheet() == xsheet && oprop->getRange(from, to, step)) {
|
|
justburner |
0be1bc |
m_startTime = from - 1;
|
|
justburner |
0be1bc |
m_endTime = to - 1;
|
|
shun-iwasawa |
a807ce |
// m_stepTime = step;
|
|
justburner |
0be1bc |
} else {
|
|
justburner |
0be1bc |
m_startTime = 0;
|
|
justburner |
0be1bc |
m_endTime = xsheet->getFrameCount() - 1;
|
|
shun-iwasawa |
a807ce |
// m_stepTime = 1;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
if (m_endTime < 0) m_endTime = 0;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Build a list of rows
|
|
justburner |
0be1bc |
QList<int> rows;</int>
|
|
justburner |
0be1bc |
for (int i = m_startTime; i <= m_endTime; i++) {
|
|
justburner |
0be1bc |
rows.append(i);
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
m_framerate = oprop->getFrameRate();
|
|
justburner |
0be1bc |
m_width = scene->getCurrentCamera()->getRes().lx;
|
|
justburner |
0be1bc |
m_height = scene->getCurrentCamera()->getRes().ly;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
TPixel bgc = scene->getProperties()->getBgColor();
|
|
justburner |
0be1bc |
m_bgRed = bgc.r / double(TPixel::maxChannelValue);
|
|
justburner |
0be1bc |
m_bgGreen = bgc.g / double(TPixel::maxChannelValue);
|
|
justburner |
0be1bc |
m_bgBlue = bgc.b / double(TPixel::maxChannelValue);
|
|
justburner |
0be1bc |
m_bgAlpha = bgc.m / double(TPixel::maxChannelValue);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Build all columns from current xsheet
|
|
justburner |
0be1bc |
m_layers.empty();
|
|
justburner |
0be1bc |
for (int col = 0; col < xsheet->getColumnCount(); col++) {
|
|
justburner |
0be1bc |
if (xsheet->isColumnEmpty(col)) continue;
|
|
justburner |
0be1bc |
TXshCellColumn *column = xsheet->getColumn(col)->getCellColumn();
|
|
shun-iwasawa |
a807ce |
if (!column) continue; // skip non-cell column
|
|
justburner |
0be1bc |
if (!column->isPreviewVisible()) continue; // skip inactive column
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (column->getColumnType() == column->eLevelType) {
|
|
justburner |
0be1bc |
if (m_progressDialog) {
|
|
justburner |
0be1bc |
QString layername;
|
|
justburner |
0be1bc |
getLayerName(column, layername);
|
|
justburner |
0be1bc |
m_progressDialog->setLabelText(QObject::tr("Layer: ") + layername);
|
|
justburner |
0be1bc |
m_progressDialog->setMaximum(xsheet->getColumnCount());
|
|
justburner |
0be1bc |
m_progressDialog->setValue(col);
|
|
justburner |
0be1bc |
QCoreApplication::processEvents();
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QJsonObject json;
|
|
justburner |
0be1bc |
if (isGroup(column)) {
|
|
justburner |
0be1bc |
if (buildGroup(json, rows, column)) m_layers.append(json);
|
|
justburner |
0be1bc |
} else {
|
|
justburner |
0be1bc |
if (buildLayer(json, rows, column)) m_layers.append(json);
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
shun-iwasawa |
a807ce |
ExportOCACommand::ExportOCACommand() : MenuItemHandler(MI_ExportOCA) {}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
void ExportOCACommand::execute() {
|
|
justburner |
0be1bc |
ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
|
|
justburner |
0be1bc |
TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
|
|
justburner |
0be1bc |
TFilePath fp = scene->getScenePath().withType("oca");
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
static GenericSaveFilePopup *savePopup = 0;
|
|
justburner |
0be1bc |
static QCheckBox *exrImageFormat = nullptr;
|
|
justburner |
0be1bc |
static QCheckBox *rasVectors = nullptr;
|
|
justburner |
0be1bc |
static QCheckBox *doKeyframing = nullptr;
|
|
justburner |
0be1bc |
static QHBoxLayout *startingOffsetLay = nullptr;
|
|
justburner |
0be1bc |
static QLabel *startingOffsetLab = nullptr;
|
|
justburner |
0be1bc |
static QSpinBox *startingOffsetSpin = nullptr;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
static DVGui::ProgressDialog *progressDialog = nullptr;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (!savePopup) {
|
|
justburner |
0be1bc |
QWidget *customWidget = new QWidget();
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
exrImageFormat = new QCheckBox(tr("Save Images in EXR Format"));
|
|
justburner |
0be1bc |
rasVectors = new QCheckBox(tr("Rasterize Vectors"));
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
startingOffsetLay = new QHBoxLayout();
|
|
justburner |
0be1bc |
startingOffsetLab = new QLabel(tr("Frame Offset: "));
|
|
justburner |
0be1bc |
startingOffsetSpin = new QSpinBox();
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
exrImageFormat->setToolTip(
|
|
justburner |
0be1bc |
tr("Checked: Images are saved as EXR\nUnchecked: Images are "
|
|
justburner |
0be1bc |
"saved as PNG"));
|
|
justburner |
0be1bc |
rasVectors->setToolTip(
|
|
justburner |
0be1bc |
tr("Checked: Rasterize into EXR/PNG\nUnchecked: Vectors are "
|
|
justburner |
0be1bc |
"saved as SVG"));
|
|
justburner |
0be1bc |
startingOffsetLab->setToolTip(tr("Starting Frame Offset"));
|
|
justburner |
0be1bc |
startingOffsetSpin->setToolTip(tr("Starting Frame Offset"));
|
|
justburner |
0be1bc |
rasVectors->setChecked(true);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
startingOffsetSpin->setValue(1);
|
|
justburner |
0be1bc |
startingOffsetSpin->setMinimum(0);
|
|
justburner |
0be1bc |
startingOffsetSpin->setMaximum(1000000);
|
|
justburner |
0be1bc |
startingOffsetLab->adjustSize();
|
|
justburner |
0be1bc |
startingOffsetLay->setMargin(0);
|
|
justburner |
0be1bc |
startingOffsetLay->setSpacing(0);
|
|
justburner |
0be1bc |
startingOffsetLay->addWidget(startingOffsetLab, 0, Qt::AlignRight);
|
|
justburner |
0be1bc |
startingOffsetLay->addWidget(startingOffsetSpin);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QGridLayout *customLay = new QGridLayout();
|
|
justburner |
0be1bc |
customLay->setMargin(5);
|
|
justburner |
0be1bc |
customLay->setSpacing(5);
|
|
justburner |
0be1bc |
customLay->addWidget(exrImageFormat, 0, 0);
|
|
justburner |
0be1bc |
customLay->addWidget(rasVectors, 1, 0);
|
|
justburner |
0be1bc |
customLay->addLayout(startingOffsetLay, 0, 1);
|
|
justburner |
0be1bc |
customWidget->setLayout(customLay);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
progressDialog = new DVGui::ProgressDialog("", tr("Hide"), 0, 0);
|
|
justburner |
0be1bc |
progressDialog->setWindowTitle(tr("Exporting..."));
|
|
justburner |
0be1bc |
progressDialog->setWindowFlags(
|
|
justburner |
0be1bc |
Qt::Dialog | Qt::WindowTitleHint); // Don't show ? and X buttons
|
|
justburner |
0be1bc |
progressDialog->setWindowModality(Qt::WindowModal);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
savePopup = new GenericSaveFilePopup(
|
|
justburner |
0be1bc |
QObject::tr("Export Open Cel Animation (OCA)"), customWidget);
|
|
justburner |
0be1bc |
savePopup->addFilterType("oca");
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
if (!scene->isUntitled())
|
|
justburner |
0be1bc |
savePopup->setFolder(fp.getParentDir());
|
|
justburner |
0be1bc |
else
|
|
justburner |
0be1bc |
savePopup->setFolder(
|
|
justburner |
0be1bc |
TProjectManager::instance()->getCurrentProject()->getScenesPath());
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
savePopup->setFilename(fp.withoutParentDir());
|
|
justburner |
0be1bc |
fp = savePopup->getPath();
|
|
justburner |
0be1bc |
if (fp.isEmpty()) return;
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
int frameOffset = startingOffsetSpin->value();
|
|
justburner |
0be1bc |
bool exrImageFmt = exrImageFormat->isChecked();
|
|
justburner |
0be1bc |
bool rasterVecs = rasVectors->isChecked();
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Export
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
progressDialog->setLabelText(tr("Starting..."));
|
|
justburner |
0be1bc |
progressDialog->setValue(0);
|
|
justburner |
0be1bc |
progressDialog->show();
|
|
justburner |
0be1bc |
QCoreApplication::processEvents();
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QString ocafile = fp.getQString();
|
|
justburner |
0be1bc |
QString ocafolder(ocafile);
|
|
justburner |
0be1bc |
ocafolder.replace(".", "_");
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QFile saveFile(ocafile);
|
|
justburner |
0be1bc |
QDir saveDir(ocafolder);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (!saveFile.open(QIODevice::WriteOnly)) {
|
|
justburner |
97869c |
progressDialog->close();
|
|
justburner |
97869c |
DVGui::error(QObject::tr("Unable to open OCA file for saving."));
|
|
justburner |
0be1bc |
return;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
if (!saveDir.exists()) {
|
|
justburner |
97869c |
if (!saveDir.mkpath(".")) {
|
|
justburner |
97869c |
progressDialog->close();
|
|
justburner |
97869c |
DVGui::error(QObject::tr("Unable to create folder for saving layers."));
|
|
justburner |
0be1bc |
return;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
OCAData ocaData;
|
|
justburner |
0be1bc |
ocaData.setProgressDialog(progressDialog);
|
|
justburner |
0be1bc |
ocaData.build(scene, xsheet, QString::fromStdString(fp.getName()), ocafolder,
|
|
justburner |
0be1bc |
frameOffset, exrImageFmt, !rasterVecs);
|
|
justburner |
0be1bc |
if (ocaData.isEmpty()) {
|
|
justburner |
97869c |
progressDialog->close();
|
|
justburner |
0be1bc |
DVGui::error(QObject::tr("No columns can be exported."));
|
|
justburner |
0be1bc |
return;
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QJsonObject ocaObject;
|
|
justburner |
0be1bc |
ocaData.write(ocaObject);
|
|
justburner |
0be1bc |
QJsonDocument saveDoc(ocaObject);
|
|
justburner |
0be1bc |
QByteArray jsonByteArrayData = saveDoc.toJson();
|
|
justburner |
0be1bc |
saveFile.write(jsonByteArrayData);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
progressDialog->close();
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
// Done
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
QString str = QObject::tr("%1 has been exported successfully.")
|
|
justburner |
0be1bc |
.arg(QString::fromStdString(fp.getLevelName()));
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
std::vector<qstring> buttons = {QObject::tr("OK"),</qstring>
|
|
justburner |
0be1bc |
QObject::tr("Open containing folder")};
|
|
justburner |
0be1bc |
int ret = DVGui::MsgBox(DVGui::INFORMATION, str, buttons);
|
|
justburner |
0be1bc |
|
|
justburner |
0be1bc |
if (ret == 2) {
|
|
justburner |
0be1bc |
TFilePath folderPath = fp.getParentDir();
|
|
justburner |
0be1bc |
if (TSystem::isUNC(folderPath))
|
|
justburner |
0be1bc |
QDesktopServices::openUrl(QUrl(folderPath.getQString()));
|
|
justburner |
0be1bc |
else
|
|
justburner |
0be1bc |
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath.getQString()));
|
|
justburner |
0be1bc |
}
|
|
justburner |
0be1bc |
}
|
|
shun-iwasawa |
a807ce |
|
|
shun-iwasawa |
a807ce |
ExportOCACommand exportOCACommand;
|