#define _CRT_SECURE_NO_WARNINGS (1) // Warning treated as errors
#define _CRT_SECURE_NO_DEPRECATE (1) // use of fopen deprecated
// TFarmController includes
#include "tfarmcontroller.h"
// TnzStdfx includes
#include "stdfx/shaderfx.h"
// TnzLib includes
#include "toonz/toonzfolders.h"
#include "toonz/tlog.h"
#include "toonz/tstageobjecttree.h"
#include "toonz/stage.h"
#include "toonz/preferences.h"
#include "toonz/tproject.h"
#include "toonz/toonzscene.h"
#include "toonz/sceneproperties.h"
#include "toonz/txshsoundlevel.h"
#include "toonz/txshsoundcolumn.h"
#include "toonz/tcamera.h"
#include "toonz/scenefx.h"
#include "toonz/movierenderer.h"
#include "toonz/multimediarenderer.h"
#include "toutputproperties.h"
#include "toonz/imagestyles.h"
#include "tproperty.h"
#include "toonz/levelset.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/levelproperties.h"
#include "toonz/filepathproperties.h"
// TnzSound includes
#include "tnzsound.h"
// TnzImage includes
#include "timage_io.h"
#include "tnzimage.h"
#ifdef _WIN32
#include "avicodecrestrictions.h"
#endif
// TnzBase includes
#include "tcli.h"
#include "tunit.h"
#include "tenv.h"
#include "tpassivecachemanager.h"
// #include "tcacheresourcepool.h"
// TnzCore includes
#include "tsystem.h"
#include "tsmartpointer.h"
#include "tthread.h"
#include "tthreadmessage.h"
#include "tmsgcore.h"
#include "tstopwatch.h"
#include "timagecache.h"
#include "tstream.h"
#include "tfilepath_io.h"
#include "tpluginmanager.h"
#include "tiio_std.h"
#include "tsimplecolorstyles.h"
#include "tvectorbrushstyle.h"
#include "tpalette.h"
// TnzQt includes
#include "toonzqt/pluginloader.h"
// Qt includes
#include <QApplication>
#include <QWaitCondition>
#include <QMessageBox>
#ifdef _WIN32
#ifndef x64
#include <float.h>
#endif
#endif
//==================================================================================
using namespace std;
using namespace TCli;
typedef ArgumentT<TFilePath> FilePathArgument;
typedef QualifierT<TFilePath> FilePathQualifier;
namespace {
double currentCameraSize = 12;
double getCurrentCameraSize() { return currentCameraSize; }
} // namespace
//========================================================================
//
// Application names and versions
//
//------------------------------------------------------------------------
namespace {
//
// applicationName & Version compongono la registry root
// applicationFullName e' la title bar (e compare dentro i .tnz)
// rootVarName e' quello che dice di essere
// systemVarPrefix viene prefissa a tutte le variabili nei registry
// (es <systemVarPrefix>PROJECTS etc.)
//
const char *rootVarName = "TOONZROOT";
const char *systemVarPrefix = "TOONZ";
// TODO: forse anche questo andrebbe in tnzbase
// ci possono essere altri programmi offline oltre al tcomposer
//========================================================================
//
// fatalError
//
//------------------------------------------------------------------------
void fatalError(string msg) {
#ifdef _WIN32
std::cout << msg << std::endl;
// MessageBox(0,msg.c_str(),"Fatal error",MB_ICONERROR);
exit(1);
#else
// TODO: Come si fa ad aggiungere un messaggio di errore qui?
std::cout << msg << std::endl;
abort();
#endif
}
//
#ifdef MACOSX
inline bool isBlank(char c) { return c == ' ' || c == '\t' || c == '\n'; }
//
// TODO: se questo sistema e' il modo Mac di emulare i registry di windows
// allora **DEVE** essere messo in libreria. Parliamone.
//
//========================================================================
// setToonzFolder
//------------------------------------------------------------------------
// Ritorna il path della variabile passata come secondo argomento
// entrambe vengono lette da un file di testo (filename).
TFilePath setToonzFolder(const TFilePath &filename, std::string toonzVar) {
Tifstream is(filename);
if (!is) return TFilePath();
char buffer[1024];
while (is.getline(buffer, sizeof(buffer))) {
// le righe dentro toonzenv.txt sono del tipo
// export set TOONZPROJECT="....."
// devo trovare la linea che contiene toonzVar
char *s = buffer;
while (isBlank(*s)) s++;
// Se la riga vuota, o inizia per # o ! salto alla prossima
if (*s == '\0' || *s == '#' || *s == '!') continue;
if (*s == '=') continue; // errore: nome variabile non c'
char *t = s;
// Mi prendo la sottoStringa fino all'=
while (*t && *t != '=') t++;
if (*t != '=') continue; // errore: manca '='
char *q = t;
// Torno indietro fino al primo blank
while (q > s && !isBlank(*(q - 1))) q--;
if (q == s)
continue; // non dovrebbe mai succedere: prima di '=' tutti blanks
string toonzVarString(q, t);
// Confronto la stringa trovata con toonzVar, se lei vado avanti.
if (toonzVar != toonzVarString) continue; // errore: stringhe diverse
s = t + 1;
// Salto gli spazi
while (isBlank(*s)) s++;
if (*s == '\0') continue; // errore: dst vuoto
t = s;
while (*t) t++;
while (t > s && isBlank(*(t - 1))) t--;
if (t == s) continue;
// ATTENZIONE : tolgo le virgolette !!
string pathName(s + 1, t - s - 2);
return TFilePath(pathName);
}
return TFilePath();
}
#endif
} // namespace
//==============================================================================================
namespace {
TStopWatch Sw1;
TStopWatch Sw2;
bool UseRenderFarm = false;
QString FarmControllerName;
int FarmControllerPort;
TFarmController *FarmController = 0;
TUserLogAppend *m_userLog;
QString TaskId;
//-------------------------------------------------------------------------------
void tcomposerRunOutOfContMemHandler(unsigned long size) {
string msg("Run out of contiguous memory: tried to allocate " +
std::to_string(size >> 10) + " KB");
cout << msg << endl;
m_userLog->error(msg);
// The task will necessarily do something wrong. So we quit with an error
// code.
TImageCache::instance()->clear(true);
exit(2);
}
// Check if the scene saved with the previous version AND the premultiply option
// is set to PNG level setting
void UnsetPremultiplyOptionsInPngLevels(ToonzScene *scene) {
if (scene->getVersionNumber() <
VersionNumber(71, 1)) { // V1.4 = 71.0 , V1.5 = 71.1
QStringList modifiedPNGLevelNames;
std::vector<TXshLevel *> levels;
scene->getLevelSet()->listLevels(levels);
for (auto level : levels) {
if (!level || !level->getSimpleLevel()) continue;
TFilePath path = level->getPath();
if (path.isEmpty() || path.getType() != "png") continue;
if (level->getSimpleLevel()->getProperties()->doPremultiply()) {
level->getSimpleLevel()->getProperties()->setDoPremultiply(false);
modifiedPNGLevelNames.append(QString::fromStdWString(level->getName()));
}
}
if (!modifiedPNGLevelNames.isEmpty()) {
std::string msg =
"The Premultiply options in the following levels are disabled, since "
"PNG files are premultiplied on loading in the current version:" +
modifiedPNGLevelNames.join(", ").toStdString();
cout << msg << endl;
m_userLog->info(msg);
}
}
}
} // namespace
//==============================================================================================
class MyMovieRenderListener final : public MovieRenderer::Listener {
public:
MyMovieRenderListener(const TFilePath &fp, int frameCount,
QWaitCondition &renderCompleted, bool stereo)
: m_fp(fp)
, m_frameCount(frameCount)
, m_frameCompletedCount(0)
, m_frameFailedCount(0)
, m_renderCompleted(renderCompleted)
, m_stereo(stereo) {}
bool onFrameCompleted(int frame) override;
bool onFrameFailed(int frame, TException &e) override;
void onSequenceCompleted(const TFilePath &fp) override;
TFilePath m_fp;
int m_frameCount;
int m_frameCompletedCount;
int m_frameFailedCount;
QWaitCondition &m_renderCompleted;
bool m_stereo;
};
//==================================================================================
bool MyMovieRenderListener::onFrameCompleted(int frame) {
TFilePath fp = m_fp.withFrame(frame + 1);
string msg;
if (m_stereo)
msg = ::to_string(fp.withName(fp.getName() + "_l")) + " and " +
::to_string(fp.withName(fp.getName() + "_r")) + " computed";
else
msg = ::to_string(fp) + " computed";
cout << msg << endl;
m_userLog->info(msg);
DVGui::info(QString::fromStdString(msg));
if (FarmController) {
try {
FarmController->taskProgress(TaskId,
m_frameCompletedCount + m_frameFailedCount,
m_frameCount, frame + 1, FrameDone);
} catch (...) {
msg = "Unable to connect to " + std::to_string(FarmControllerPort) + "@" +
FarmControllerName.toStdString();
cout << msg;
m_userLog->error(msg);
}
}
m_frameCompletedCount++;
return true;
}
//------------------------------------------------------------------------------
bool MyMovieRenderListener::onFrameFailed(int frame, TException &e) {
TFilePath fp = m_fp.withFrame(frame + 1);
string msg;
msg = ::to_string(fp) + " failed";
if (!e.getMessage().empty()) msg += ": " + ::to_string(e.getMessage());
cout << msg << endl;
m_userLog->error(msg);
if (FarmController) {
try {
FarmController->taskProgress(TaskId,
m_frameCompletedCount + m_frameFailedCount,
m_frameCount, frame + 1, FrameFailed);
} catch (...) {
msg = "Unable to connect to " + std::to_string(FarmControllerPort) + "@" +
FarmControllerName.toStdString();
cout << msg;
m_userLog->error(msg);
}
}
m_frameFailedCount++;
return true;
}
//------------------------------------------------------------------------------
void MyMovieRenderListener::onSequenceCompleted(const TFilePath &fp) {
cout << endl;
QCoreApplication::instance()->quit();
}
//==============================================================================================
class MyMultimediaRenderListener final : public MultimediaRenderer::Listener {
public:
TFilePath m_fp;
int m_frameCount;
int m_frameCompletedCount;
int m_frameFailedCount;
MyMultimediaRenderListener(const TFilePath &fp, int frameCount)
: m_fp(fp)
, m_frameCount(frameCount)
, m_frameCompletedCount(0)
, m_frameFailedCount(0) {}
bool onFrameCompleted(int frame, int column) override;
bool onFrameFailed(int frame, int column, TException &e) override;
void onSequenceCompleted(int column) override {}
void onRenderCompleted() override {}
};
//==================================================================================
bool MyMultimediaRenderListener::onFrameCompleted(int frame, int column) {
int actualFrame = frame + 1;
string msg = ::to_string(m_fp) + ", column " + std::to_string(column) +
", frame " + std::to_string(actualFrame) + " computed";
cout << msg << endl;
m_userLog->info(msg);
if (FarmController) {
try {
FarmController->taskProgress(TaskId,
m_frameCompletedCount + m_frameFailedCount,
m_frameCount, actualFrame, FrameDone);
} catch (...) {
msg = "Unable to connect to " + std::to_string(FarmControllerPort) + "@" +
FarmControllerName.toStdString();
cout << msg;
m_userLog->error(msg);
}
}
m_frameCompletedCount++;
return true;
}
//------------------------------------------------------------------------------
bool MyMultimediaRenderListener::onFrameFailed(int frame, int column,
TException &e) {
int actualFrame = frame + 1;
string msg = ::to_string(m_fp) + ", column " + std::to_string(column) +
", frame " + std::to_string(actualFrame) + " failed";
if (!e.getMessage().empty()) msg += ": " + ::to_string(e.getMessage());
cout << msg << endl;
m_userLog->error(msg);
if (FarmController) {
try {
FarmController->taskProgress(TaskId,
m_frameCompletedCount + m_frameFailedCount,
m_frameCount, actualFrame, FrameFailed);
} catch (...) {
msg = "Unable to connect to " + std::to_string(FarmControllerPort) + "@" +
FarmControllerName.toStdString();
cout << msg;
m_userLog->error(msg);
}
}
m_frameFailedCount++;
return true;
}
//==================================================================================
static std::pair<int, int> generateMovie(ToonzScene *scene, const TFilePath &fp,
int r0, int r1, int step, int shrink,
int threadCount, int maxTileSize) {
QWaitCondition renderCompleted;
// riporto gli indici a base zero
r0 = r0 - 1;
r1 = r1 - 1;
if (r0 < 0) r0 = 0;
if (r1 < 0 || r1 >= scene->getFrameCount()) r1 = scene->getFrameCount() - 1;
string msg;
assert(r1 >= r0);
TSceneProperties *sprop = scene->getProperties();
TOutputProperties outputSettings = *sprop->getOutputProperties();
currentCameraSize = scene->getCurrentCamera()->getSize().lx;
TDimension cameraSize = scene->getCurrentCamera()->getRes();
TSystem::touchParentDir(fp);
string ext = fp.getType();
#ifdef _WIN32
if (ext == "avi") {
TPropertyGroup *props =
scene->getProperties()->getOutputProperties()->getFileFormatProperties(
ext);
string codecName = props->getProperty(0)->getValueAsString();
TDimension res = scene->getCurrentCamera()->getRes();
if (!AviCodecRestrictions::canWriteMovie(::to_wstring(codecName), res)) {
string msg(
"The resolution of the output camera does not fit with the options "
"chosen for the output file format.");
m_userLog->error(msg);
exit(1);
}
}
#endif
double cameraXDpi, cameraYDpi;
TPointD camDpi = scene->getCurrentCamera()->getDpi();
cameraXDpi = camDpi.x;
cameraYDpi = camDpi.y;
int which = outputSettings.getWhichLevels();
double stretchTo = (double)outputSettings.getRenderSettings().m_timeStretchTo;
double stretchFrom =
(double)outputSettings.getRenderSettings().m_timeStretchFrom;
double timeStretchFactor = stretchFrom / stretchTo;
int numFrames = (int)((r1 - r0 + 1) / timeStretchFactor);
double r = (r0)*timeStretchFactor;
double stepd = step * timeStretchFactor;
int multimediaRender = outputSettings.getMultimediaRendering();
//---------------------------------------------------------
// Multimedia render
//---------------------------------------------------------
if (multimediaRender) {
MultimediaRenderer multimediaRenderer(scene, fp, multimediaRender,
threadCount);
TRenderSettings rs = outputSettings.getRenderSettings();
rs.m_maxTileSize = maxTileSize;
rs.m_shrinkX = rs.m_shrinkY = shrink;
multimediaRenderer.setRenderSettings(rs);
multimediaRenderer.setDpi(cameraXDpi, cameraYDpi);
multimediaRenderer.enablePrecomputing(true);
for (int i = 0; i < numFrames; i += step, r += stepd)
multimediaRenderer.addFrame(r);
MyMultimediaRenderListener *listener = new MyMultimediaRenderListener(
fp, multimediaRenderer.getFrameCount() *
multimediaRenderer.getColumnsCount());
multimediaRenderer.addListener(listener);
multimediaRenderer.start();
//----------------- main thread remains above until render is done
//----------------
// NOTE: the passed total frame count "columns * frames" is an overestimate
// in this case:
// columns which do not appear on certain frames are not rendered. So, just
// realize the
// number of failed frames if any.
std::pair<int, int> framePair =
std::make_pair(listener->m_frameCount, listener->m_frameCount);
delete listener;
return framePair;
}
//---------------------------------------------------------
// Movie render
//---------------------------------------------------------
else {
MovieRenderer movieRenderer(scene, fp, threadCount, false);
TRenderSettings rs = outputSettings.getRenderSettings();
rs.m_maxTileSize = maxTileSize;
rs.m_shrinkX = rs.m_shrinkY = shrink;
movieRenderer.setRenderSettings(rs);
movieRenderer.setDpi(cameraXDpi, cameraYDpi);
movieRenderer.enablePrecomputing(true);
MyMovieRenderListener *listener =
new MyMovieRenderListener(fp, tceil((numFrames) / (float)step),
renderCompleted, rs.m_stereoscopic);
movieRenderer.addListener(listener);
for (int i = 0; i < numFrames; i += step, r += stepd) {
TFxPair fx;
if (rs.m_stereoscopic) scene->shiftCameraX(-rs.m_stereoscopicShift / 2);
fx.m_frameA = (TRasterFxP)buildSceneFx(scene, scene->getXsheet(), r,
which, shrink, false);
if (rs.m_fieldPrevalence != TRenderSettings::NoField)
fx.m_frameB = (TRasterFxP)buildSceneFx(scene, scene->getXsheet(),
r + 0.5 * timeStretchFactor,
which, shrink, false);
else if (rs.m_stereoscopic) {
scene->shiftCameraX(rs.m_stereoscopicShift);
fx.m_frameB = (TRasterFxP)buildSceneFx(scene, scene->getXsheet(), r,
which, shrink, false);
scene->shiftCameraX(-rs.m_stereoscopicShift / 2);
} else
fx.m_frameB = TRasterFxP();
movieRenderer.addFrame(r, fx);
}
movieRenderer.start();
// Start main loop
QCoreApplication::instance()->exec();
//----------------- tcomposer's main thread loops here ----------------
// int frameCompleted = listener->m_frameCompletedCount;
std::pair<int, int> framePair =
std::make_pair(listener->m_frameCompletedCount, listener->m_frameCount);
delete listener;
return framePair;
}
}
//==================================================================================
//
// main()
//
//----------------------------------------------------------------------------------
// TODO: il main comincia a diventare troppo lungo. Forse val la pena
// separarlo in varie funzioni
// (tipo initToonzEnvironment(), parseCommandLine(), ecc)
// TODO: the main starts getting too long. Perhaps it is worth
// separated into various functions
// (type initToonzEnvironment (), ParseCommandLine (), etc.)
DV_IMPORT_API void initStdFx();
DV_IMPORT_API void initColorFx();
int main(int argc, char *argv[]) {
TCli::UsageLine usageLine;
// setCurrentModule("tcomposer");
TCli::FilePathArgument srcName("srcName", "Source file");
FilePathQualifier dstName("-o dstName", "Target file");
RangeQualifier range;
IntQualifier stepOpt("-step n", "Step");
IntQualifier shrinkOpt("-shrink n", "Shrink");
IntQualifier multimedia("-multimedia n", "Multimedia rendering mode");
StringQualifier farmData("-farm data", "TFarm Controller");
StringQualifier idq("-id n", "id");
StringQualifier nthreads("-nthreads n", "Number of rendering threads");
StringQualifier tileSize("-maxtilesize n",
"Enable tile rendering of max n MB per tile");
StringQualifier tmsg("-tmsg val", "only internal use");
usageLine = srcName + dstName + range + stepOpt + shrinkOpt + multimedia +
farmData + idq + nthreads + tileSize + tmsg;
// system path qualifiers
std::map<QString, std::unique_ptr<TCli::QualifierT<TFilePath>>>
systemPathQualMap;
QString qualKey = QString("%1ROOT").arg(systemVarPrefix);
QString qualName = QString("-%1 folderpath").arg(qualKey);
QString qualHelp =
QString(
"%1 path. It will automatically set other system paths to %1 "
"unless individually specified with other qualifiers.")
.arg(qualKey);
systemPathQualMap[qualKey].reset(new TCli::QualifierT<TFilePath>(
qualName.toStdString(), qualHelp.toStdString()));
usageLine = usageLine + *systemPathQualMap[qualKey];
const std::map<std::string, std::string> &spm = TEnv::getSystemPathMap();
for (auto itr = spm.begin(); itr != spm.end(); ++itr) {
qualKey = QString("%1%2")
.arg(systemVarPrefix)
.arg(QString::fromStdString((*itr).first));
qualName = QString("-%1 folderpath").arg(qualKey);
qualHelp = QString("%1 path.").arg(qualKey);
systemPathQualMap[qualKey].reset(new TCli::QualifierT<TFilePath>(
qualName.toStdString(), qualHelp.toStdString()));
usageLine = usageLine + *systemPathQualMap[qualKey];
}
Usage usage(argv[0]);
usage.add(usageLine);
if (!usage.parse(argc, argv)) exit(1);
QHash<QString, QString> argumentPathValues;
for (auto q_itr = systemPathQualMap.begin(); q_itr != systemPathQualMap.end();
++q_itr) {
if (q_itr->second->isSelected())
argumentPathValues.insert(q_itr->first,
q_itr->second->getValue().getQString());
}
QApplication app(argc, argv);
// Create a QObject destroyed just before app - see Tnz6's main.cpp for
// rationale
std::unique_ptr<QObject> mainScope(new QObject(&app));
mainScope->setObjectName("mainScope");
#ifdef _WIN32
#ifndef x64
// Store the floating point control word. It will be re-set before Toonz
// initialization
// has ended.
unsigned int fpWord = 0;
_controlfp_s(&fpWord, 0, 0);
#endif
#endif
// Set the app's locale for numeric stuff to standard C. This is important for
// atof() and similar
// calls that are locale-dependent.
setlocale(LC_NUMERIC, "C");
// Install run out of contiguous memory callback
TBigMemoryManager::instance()->setRunOutOfContiguousMemoryHandler(
&tcomposerRunOutOfContMemHandler);
#ifdef _WIN32
// Define 64-bit precision for floating-point arithmetic. Please observe that
// the
// initImageIo() call below would already impose this precision. This just wants
// to be
// explicit.
//_controlfp_s(0, 0, 0x10000);
#endif
// Initialize thread components
TThread::init();
// questo definisce la registry root e inizializza TEnv
TEnv::setRootVarName(rootVarName);
TEnv::setSystemVarPrefix(systemVarPrefix);
TEnv::setApplicationFileName(argv[0]);
QCoreApplication::setOrganizationName("OpenToonz");
QCoreApplication::setOrganizationDomain("");
QCoreApplication::setApplicationName(
QString::fromStdString(TEnv::getApplicationName()));
QHash<QString, QString>::const_iterator argItr =
argumentPathValues.constBegin();
while (argItr != argumentPathValues.constEnd()) {
if (!TEnv::setArgPathValue(argItr.key().toStdString(),
argItr.value().toStdString()))
cerr << "The qualifier " << argItr.key().toStdString()
<< " is not a valid key name. Skipping." << endl;
++argItr;
}
TSystem::hasMainLoop(true);
// QMessageBox::information(0, QString("eccolo"), QString("composer!"));
int i;
for (i = 0; i < argc; i++) // tmsg must be set as soon as it's possible
{
QString str = argv[i];
if (str == "-tmsg") {
TMsgCore::instance()->connectTo(argv[i + 1]);
break;
}
}
if (i == argc) TMsgCore::instance()->connectTo("");
// controllo se la xxxroot e' definita e corrisponde ad un file esistente
TFilePath fp = TEnv::getStuffDir();
if (fp == TFilePath())
fatalError(string("Undefined: \"") + ::to_string(TEnv::getRootVarPath()) +
"\"");
if (!TFileStatus(fp).isDirectory())
fatalError(string("Directory \"") + ::to_string(fp) +
"\" not found or not readable");
TFilePath lRootDir = fp + "toonzfarm";
TFilePath logFilePath = lRootDir + "tcomposer.log";
m_userLog = new TUserLogAppend(logFilePath);
string msg;
// Initialize measure units
Preferences::instance(); // Loads standard (linear) units
TMeasureManager::instance()-> // Loads camera-related units
addCameraMeasures(getCurrentCameraSize); //
TFilePathSet fps = ToonzFolder::getProjectsFolders();
TFilePathSet::iterator fpIt;
for (fpIt = fps.begin(); fpIt != fps.end(); ++fpIt)
TProjectManager::instance()->addProjectsRoot(*fpIt);
TFilePath libraryFolder = ToonzFolder::getLibraryFolder();
TRasterImagePatternStrokeStyle::setRootDir(libraryFolder);
TVectorImagePatternStrokeStyle::setRootDir(libraryFolder);
TVectorBrushStyle::setRootDir(libraryFolder);
TPalette::setRootDir(libraryFolder);
TImageStyle::setLibraryDir(libraryFolder);
TFilePath cacheRoot = ToonzFolder::getCacheRootFolder();
if (cacheRoot.isEmpty()) cacheRoot = TEnv::getStuffDir() + "cache";
TImageCache::instance()->setRootDir(cacheRoot);
// #endif
TaskId = QString::fromStdString(idq.getValue());
string fdata = farmData.getValue();
if (fdata.empty())
UseRenderFarm = false;
else {
UseRenderFarm = true;
string::size_type pos = fdata.find('@');
if (pos == string::npos)
UseRenderFarm = false;
else {
FarmControllerPort = std::stoi(fdata.substr(0, pos));
FarmControllerName = QString::fromStdString(fdata.substr(pos + 1));
}
}
if (UseRenderFarm) {
TFarmControllerFactory factory;
factory.create(FarmControllerName, FarmControllerPort, &FarmController);
}
while (!PluginLoader::load_entries("")) app.processEvents();
std::pair<int, int> framePair(1, 0);
try {
Tiio::defineStd();
initImageIo();
Tiio::defineStd();
initSoundIo();
initStdFx();
initColorFx();
loadShaderInterfaces(ToonzFolder::getLibraryFolder() +
TFilePath("shaders"));
// #endif
//---------------------------------------------------------
TFilePath srcFilePath = srcName.getValue();
try {
srcFilePath = TSystem::toLocalPath(srcFilePath);
} catch (...) {
}
//---------------------------------------------------------
msg = "Loading " + srcFilePath.getName();
cout << endl << msg << endl;
m_userLog->info(msg);
TProjectManager *pm = TProjectManager::instance();
// pm->enableTabMode(true);
TProjectP project = pm->loadSceneProject(srcFilePath);
if (!project) {
msg = "Couldn't find the project"; //+ project->getName().getName();
cerr << msg << endl;
m_userLog->error(msg);
return -2;
}
msg = "project: " + project->getName().getName();
cout << msg << endl;
m_userLog->info(msg);
// pm->setCurrentProject(project, false); // false => temporaneamente
// update TFilePath condition on loading the current project
FilePathProperties *fpProp = project->getFilePathProperties();
TFilePath::setFilePathProperties(fpProp->useStandard(),
fpProp->acceptNonAlphabetSuffix(),
fpProp->letterCountForSuffix());
Sw1.start();
if (!TSystem::doesExistFileOrLevel(srcFilePath)) return -2;
ToonzScene *scene = new ToonzScene();
TImageStyle::setCurrentScene(scene);
try {
Sw2.start();
scene->load(srcFilePath);
Sw2.stop();
} catch (TException &e) {
cout << ::to_string(e.getMessage()) << endl;
m_userLog->error(::to_string(e.getMessage()));
return -2;
} catch (...) {
string msg;
msg = "There were problems loading the scene " +
::to_string(srcFilePath) + ".\n Some files may be missing.";
cout << msg << endl;
m_userLog->error(msg);
// return false;
}
// Check if the scene saved with the previous version AND the premultiply
// option is set to PNG level setting
UnsetPremultiplyOptionsInPngLevels(scene);
msg = "scene loaded";
cout << "scene loaded" << endl;
m_userLog->info(msg);
//---------------------------------------------------------
TFilePath dstFilePath;
if (dstName.isSelected())
dstFilePath = dstName.getValue();
else {
dstFilePath = scene->getProperties()->getOutputProperties()->getPath();
if (dstFilePath == TFilePath())
dstFilePath = TFilePath("+outputs") + "$scenename.tif";
else if (dstFilePath.getName() == "")
dstFilePath = (dstFilePath.getParentDir() + scene->getSceneName())
.withType(dstFilePath.getType());
}
dstFilePath = scene->decodeFilePath(dstFilePath);
//---------------------------------------------------------
msg = "Generating " + dstFilePath.getName();
cout << endl << "Generating " << dstFilePath << endl << endl;
m_userLog->info(msg);
TFilePath theDstFilePath = dstFilePath;
try {
theDstFilePath = TSystem::toLocalPath(dstFilePath);
} catch (...) {
}
int r0 = -1, r1 = -1, step = 1, shrink = 1;
TOutputProperties *outProp = scene->getProperties()->getOutputProperties();
int scene_from, scene_to, scene_step;
outProp->getRange(scene_from, scene_to, scene_step);
int scene_shrink = outProp->getRenderSettings().m_shrinkX;
if (scene_from == 0 && scene_to == -1) {
scene_from = 1;
scene_to = scene->getFrameCount();
} else {
scene_from++;
scene_to++;
}
if (range.isSelected()) {
r0 = range.getFrom();
r1 = range.getTo();
} else {
r0 = scene_from;
r1 = scene_to;
}
if (stepOpt.isSelected())
step = stepOpt.getValue();
else
step = scene_step;
if (shrinkOpt.isSelected())
shrink = shrinkOpt.getValue();
else
shrink = scene_shrink;
if (multimedia.isSelected())
scene->getProperties()->getOutputProperties()->setMultimediaRendering(
multimedia.getValue());
// Retrieve Thread count
const int procCount = TSystem::getProcessorCount();
int threadCount;
const int threadCounts[3] = {1, procCount / 2, procCount};
if (nthreads.isSelected()) {
QString threadCountStr = QString::fromStdString(nthreads.getValue());
threadCount = (threadCountStr == "single") ? threadCounts[0]
: (threadCountStr == "half") ? threadCounts[1]
: (threadCountStr == "all") ? threadCounts[2]
: threadCountStr.toInt();
if (threadCount <= 0) {
cout << "Qualifier 'nthreads': bad input" << endl;
exit(1);
}
} else {
int threadIndex = outProp->getThreadIndex();
threadCount = threadCounts[threadIndex];
}
threadCount = tcrop(1, procCount, threadCount);
// Retrieve max tile size (raster granularity)
int maxTileSize;
const int maxTileSizes[4] = {
(std::numeric_limits<int>::max)(), TOutputProperties::LargeVal,
TOutputProperties::MediumVal, TOutputProperties::SmallVal};
if (tileSize.isSelected()) {
QString tileSizeStr = QString::fromStdString(tileSize.getValue());
maxTileSize = (tileSizeStr == "none") ? maxTileSizes[0]
: (tileSizeStr == "large") ? maxTileSizes[1]
: (tileSizeStr == "medium") ? maxTileSizes[2]
: (tileSizeStr == "small") ? maxTileSizes[3]
: tileSizeStr.toInt();
if (maxTileSize <= 0) {
cout << "Qualifier 'maxtilesize': bad input" << endl;
exit(1);
}
} else {
int maxTileSizeIndex = outProp->getMaxTileSizeIndex();
maxTileSize = maxTileSizes[maxTileSizeIndex];
}
m_userLog->info("Threads count: " + std::to_string(threadCount));
if (maxTileSize != (std::numeric_limits<int>::max)())
m_userLog->info("Render tile: " + std::to_string(maxTileSize));
// Disable the Passive cache manager. It has no sense if it cannot write on
// disk...
// TCacheResourcePool::instance(); //Needs to be instanced before
// TPassiveCacheManager...
TPassiveCacheManager::instance()->setEnabled(false);
#ifdef _WIN32
#ifndef x64
// On 32-bit architecture, there could be cases in which initialization
// could alter the
// FPU floating point control word. I've seen this happen when loading some
// AVI coded (VFAPI),
// where 80-bit internal precision was used instead of the standard 64-bit
// (much faster and
// sufficient - especially considering that x86 truncates to 64-bit
// representation anyway).
// IN ANY CASE, revert to the original control word.
// In the x64 case these precision changes simply should not take place up
// to _controlfp_s
// documentation.
_controlfp_s(0, fpWord, -1);
#endif
#endif
framePair = generateMovie(scene, theDstFilePath, r0, r1, step, shrink,
threadCount, maxTileSize);
Sw1.stop();
m_userLog->info(
"Raster Allocation Peak: " +
std::to_string(TBigMemoryManager::instance()->getAllocationPeak()) +
" KB");
m_userLog->info(
"Raster Allocation Mean: " +
std::to_string(TBigMemoryManager::instance()->getAllocationMean()) +
" KB");
msg = "Compositing completed in " +
::to_string(Sw1.getTotalTime() / 1000.0, 2) + " seconds";
string msg2 =
"\n" + ::to_string(Sw2.getTotalTime() / 1000.0, 2) +
" seconds spent on loading" + "\n" +
::to_string(TStopWatch::global(0).getTotalTime() / 1000.0, 2) +
" seconds spent on saving" + "\n" +
::to_string(TStopWatch::global(8).getTotalTime() / 1000.0, 2) +
" seconds spent on rendering" + "\n";
cout << msg + msg2;
m_userLog->info(msg + msg2);
DVGui::info(QString::fromStdString(msg));
TImageCache::instance()->clear(true);
} catch (TException &e) {
msg = "Untrapped exception: " + ::to_string(e.getMessage()),
cout << msg << endl;
m_userLog->error(msg);
TImageCache::instance()->clear(true);
} catch (...) {
cout << "Untrapped exception" << endl;
m_userLog->error("Untrapped exception");
TImageCache::instance()->clear(true);
}
if (framePair.first != framePair.second) return -1;
return 0;
}