#include "toonz/scriptbinding_level.h"
#include "toonz/scriptbinding_files.h"
#include <QScriptEngine>
#include "timage_io.h"
#include "tlevel_io.h"
#include "tlevel.h"
#include "toonz/tcenterlinevectorizer.h"
#include "toonz/tcamera.h"
#include "trop.h"
#include "trasterimage.h"
#include "ttoonzimage.h"
#include "tvectorimage.h"
#include "tpalette.h"
#include "tofflinegl.h"
#include "tvectorrenderdata.h"
#include "tgeometry.h"
#include "toonz/stage.h"
#include "toonz/txshleveltypes.h"
#include "toonz/levelproperties.h"
#include "toonz/toonzscene.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/levelset.h"
#include "tfiletype.h"
#include "tsystem.h"
#include <QRegExp>
#include <QColor>
namespace TScriptBinding {
Level::Level()
: m_sl(0)
, m_type(NO_XSHLEVEL)
, m_scene(new ToonzScene())
, m_sceneOwner(true) {}
Level::Level(TXshSimpleLevel *sl)
: m_sl(sl)
, m_type(sl->getType())
, m_scene(sl->getScene())
, m_sceneOwner(false) {
sl->addRef();
}
Level::~Level() {
if (m_sceneOwner) delete m_scene;
if (m_sl) m_sl->release();
}
QScriptValue Level::ctor(QScriptContext *context, QScriptEngine *engine) {
Level *level = new Level();
QScriptValue obj = engine->newQObject(level, QScriptEngine::AutoOwnership);
if (context->argumentCount() == 1) {
return obj.property("load").call(obj, context->argumentsObject());
}
return obj;
}
QScriptValue Level::toString() {
QString info = "(";
QString comma = "";
if (getName() != "") {
info.append(comma).append(getName());
comma = ", ";
}
info.append(comma).append(tr("%1 frames").arg(getFrameCount()));
info.append(")");
if (m_type == PLI_XSHLEVEL)
return QString("Vector level %1").arg(info);
else if (m_type == TZP_XSHLEVEL)
return QString("Toonz level %1").arg(info);
else if (m_type == NO_XSHLEVEL)
return QString("Empty level");
else if (m_type == OVL_XSHLEVEL)
return QString("Raster level %1").arg(info);
else
return QString("Level %1").arg(info);
}
QString Level::getType() const {
if (m_type == NO_XSHLEVEL)
return "Empty";
else if (m_type == PLI_XSHLEVEL)
return "Vector";
else if (m_type == TZP_XSHLEVEL)
return "ToonzRaster";
else if (m_type == OVL_XSHLEVEL)
return "Raster";
else
return "Unknown";
}
int Level::getFrameCount() const { return m_sl ? m_sl->getFrameCount() : 0; }
QString Level::getName() const {
return m_sl ? QString::fromStdWString(m_sl->getName()) : "";
}
void Level::setName(const QString &name) {
if (m_sl) m_sl->setName(name.toStdWString());
}
QScriptValue Level::getPath() const {
if (m_sl) {
FilePath *result = new FilePath(m_sl->getPath());
return result->create<FilePath>(engine());
} else
return QScriptValue();
return m_sl ? QString::fromStdWString(m_sl->getName()) : "";
}
void Level::setPath(const QScriptValue &pathArg) {
TFilePath fp;
FilePath *filePath = qscriptvalue_cast<FilePath *>(pathArg);
if (filePath)
fp = filePath->getToonzFilePath();
else if (pathArg.isString())
fp = TFilePath(pathArg.toString().toStdString());
else
context()->throwError(
tr("Bad argument (%1). It should be FilePath or string")
.arg(pathArg.toString()));
if (m_sl) {
m_sl->setPath(fp);
try {
m_sl->load();
} catch (...) {
context()->throwError(
tr("Exception loading level (%1)")
.arg(QString::fromStdWString(fp.getWideString())));
}
}
}
QScriptValue Level::load(const QScriptValue &fpArg) {
if (m_sl) {
m_scene->getLevelSet()->removeLevel(m_sl, true);
m_sl->release();
m_sl = 0;
}
// get the path
TFilePath fp;
QScriptValue err = checkFilePath(context(), fpArg, fp);
if (err.isError()) return err;
QString fpStr = fpArg.toString();
try {
if (!TSystem::doesExistFileOrLevel(fp)) {
return context()->throwError(tr("File %1 doesn't exist").arg(fpStr));
}
TFileType::Type fileType = TFileType::getInfo(fp);
if (TFileType::isVector(fileType))
m_type = PLI_XSHLEVEL;
else if (0 != (fileType & TFileType::CMAPPED_IMAGE))
m_type = TZP_XSHLEVEL;
else if (0 != (fileType & TFileType::RASTER_IMAGE))
m_type = OVL_XSHLEVEL;
else {
return context()->throwError(tr("File %1 is unsupported").arg(fpStr));
}
TXshLevel *xl = m_scene->loadLevel(fp);
if (xl) {
m_sl = xl->getSimpleLevel();
m_sl->addRef();
}
return context()->thisObject();
} catch (...) {
return context()->throwError(tr("Exception reading %1").arg(fpStr));
}
}
QScriptValue Level::save(const QScriptValue &fpArg) {
if (getFrameCount() == 0) {
return context()->throwError(tr("Can't save an empty level"));
}
// get the path
TFilePath fp;
QScriptValue err = checkFilePath(context(), fpArg, fp);
if (err.isError()) return err;
QString fpStr = fpArg.toString();
// handle conversion (if it is needed and possible)
TFileType::Type fileType = TFileType::getInfo(fp);
bool isCompatible = false;
if (TFileType::isFullColor(fileType)) {
if (m_sl->getType() == OVL_XSHLEVEL) isCompatible = true;
} else if (TFileType::isVector(fileType)) {
if (m_sl->getType() == PLI_XSHLEVEL) isCompatible = true;
} else if (fileType & TFileType::CMAPPED_IMAGE) {
if (m_sl->getType() == TZP_XSHLEVEL) isCompatible = true;
} else {
return context()->throwError(tr("Unrecognized file type :").arg(fpStr));
}
if (!isCompatible) {
return context()->throwError(
tr("Can't save a %1 level to this file type : %2")
.arg(getType())
.arg(fpStr));
}
try {
m_sl->save(fp);
} catch (TSystemException se) {
return context()->throwError(
tr("Exception writing %1")
.arg(QString::fromStdWString(se.getMessage())));
}
return context()->thisObject();
}
TFrameId Level::getFid(const QScriptValue &arg, QString &err) {
if (arg.isNumber() || arg.isString()) {
QString s = arg.toString();
QRegExp re("(-?\\d+)(\\w?)");
if (re.exactMatch(s)) {
int d = re.cap(1).toInt();
QString c = re.cap(2);
TFrameId fid;
if (c.length() == 1)
fid = TFrameId(d, c[0].unicode());
else
fid = TFrameId(d);
err = "";
return fid;
}
}
err = QObject::tr("Argument '%1' does not look like a FrameId")
.arg(arg.toString());
return TFrameId();
}
TImageP Level::getImg(const TFrameId &fid) {
if (m_sl)
return m_sl->getFrame(fid, false);
else
return TImageP();
}
QScriptValue Level::getFrame(const QScriptValue &fidArg) {
if (getFrameCount() == 0)
return context()->throwError("An empty level has no frames");
QString err;
TFrameId fid = getFid(fidArg, err);
if (err != "") return context()->throwError(err);
TImageP content = m_sl->getFrame(fid, false);
if (content) {
Image *img = new Image(content.getPointer());
return create(img);
} else {
return QScriptValue();
}
}
QScriptValue Level::getFrameByIndex(const QScriptValue &indexArg) {
if (getFrameCount() == 0)
return context()->throwError("An empty level has no frames");
if (!indexArg.isNumber()) {
return context()->throwError(
tr("frame index (%1) must be a number").arg(indexArg.toString()));
}
int index = indexArg.toInteger();
if (index < 0 || index >= getFrameCount()) {
return context()->throwError(tr("frame index (%1) is out of range (0-%2)")
.arg(index)
.arg(getFrameCount() - 1));
}
TFrameId fid = m_sl->index2fid(index);
TImageP content = m_sl->getFrame(fid, false);
if (content) {
Image *img = new Image(content.getPointer());
return create(img);
} else {
return QScriptValue();
}
}
// TODO: chiamare setFrame(const TFrameId &fid, const TImageP &img)
QScriptValue Level::setFrame(const QScriptValue &fidArg,
const QScriptValue &imageArg) {
QString err;
TFrameId fid = getFid(fidArg, err);
if (err != "") return context()->throwError(err);
Image *img = qscriptvalue_cast<Image *>(imageArg);
if (!img) {
return context()->throwError(
tr("second argument (%1) is not an image").arg(imageArg.toString()));
}
QString imgType = img->getType();
int levelType = NO_XSHLEVEL;
if (imgType == "ToonzRaster")
levelType = TZP_XSHLEVEL;
else if (imgType == "Raster")
levelType = OVL_XSHLEVEL;
else if (imgType == "Vector")
levelType = PLI_XSHLEVEL;
else {
return context()->throwError(
tr("can not insert a %1 image into a level").arg(imgType));
}
if (m_type == NO_XSHLEVEL) {
m_type = levelType;
TXshLevel *xl = m_scene->createNewLevel(levelType);
m_sl = xl->getSimpleLevel();
m_sl->addRef();
m_sl->setPalette(img->getImg()->getPalette());
if (levelType != PLI_XSHLEVEL) {
LevelProperties *lprop = m_sl->getProperties();
lprop->setDpiPolicy(LevelProperties::DP_ImageDpi);
int xres = img->getWidth();
int yres = img->getHeight();
double dpi = img->getDpi();
lprop->setDpi(dpi);
lprop->setImageDpi(TPointD(dpi, dpi));
lprop->setImageRes(TDimension(xres, yres));
// lprop->setHasAlpha(true);
}
} else if (m_type != levelType) {
return context()->throwError(tr("can not insert a %1 image to a %2 level")
.arg(imgType)
.arg(getType()));
}
if (m_sl->getFrameCount() == 0) m_sl->setPalette(img->getImg()->getPalette());
m_sl->setFrame(fid, img->getImg());
m_sl->setDirtyFlag(true);
return context()->thisObject();
}
QScriptValue Level::getFrameIds() {
QList<TFrameId> fids;
getFrameIds(fids);
QScriptValue result = engine()->newArray();
quint32 index = 0;
for (const TFrameId &fid : fids) {
QString fidStr = QString::fromStdString(fid.expand());
result.setProperty(index++, fidStr);
}
return result;
}
void Level::getFrameIds(QList<TFrameId> &result) {
if (getFrameCount() > 0) {
std::vector<TFrameId> fids;
m_sl->getFids(fids);
for (std::vector<TFrameId>::iterator it = fids.begin(); it != fids.end();
++it) {
result.append(*it);
}
}
}
int Level::setFrame(const TFrameId &fid, const TImageP &img) {
TImage::Type imgType = img->getType();
int levelType = NO_XSHLEVEL;
if (imgType == TImage::TOONZ_RASTER)
levelType = TZP_XSHLEVEL;
else if (imgType == TImage::RASTER)
levelType = OVL_XSHLEVEL;
else if (imgType == TImage::VECTOR)
levelType = PLI_XSHLEVEL;
else {
return -1;
}
if (m_type == NO_XSHLEVEL) {
m_type = levelType;
TXshLevel *xl = m_scene->createNewLevel(levelType);
m_sl = xl->getSimpleLevel();
m_sl->addRef();
m_sl->setPalette(img->getPalette());
if (levelType != PLI_XSHLEVEL) {
LevelProperties *lprop = m_sl->getProperties();
lprop->setDpiPolicy(LevelProperties::DP_ImageDpi);
int xres = 0, yres = 0;
double dpix = 0, dpiy = 0;
if (TRasterImageP ri = img) {
if (ri->getRaster()) {
TDimension size = ri->getRaster()->getSize();
xres = size.lx;
yres = size.ly;
ri->getDpi(dpix, dpiy);
}
} else if (TToonzImageP ti = img) {
if (ti->getRaster()) {
TDimension size = ri->getRaster()->getSize();
xres = size.lx;
yres = size.ly;
ri->getDpi(dpix, dpiy);
}
}
lprop->setDpi(dpix);
lprop->setImageDpi(TPointD(dpix, dpiy));
lprop->setImageRes(TDimension(xres, yres));
// lprop->setHasAlpha(true);
}
} else if (m_type != levelType) {
return -2;
}
if (m_sl->getFrameCount() == 0) m_sl->setPalette(img->getPalette());
m_sl->setFrame(fid, img);
m_sl->setDirtyFlag(true);
return 1;
}
} // namespace TScriptBinding