tahoma2d/toonz/sources/tcomposer/tcomposer.cpp
2016-05-18 13:03:37 +09:00

939 lines
28 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define _CRT_SECURE_NO_WARNINGS (1) //Warning treated as errors
#define _CRT_SECURE_NO_DEPRECATE (1) //use of fopen deprecated
// Tnz includes (-.-')
#include "../toonz/tapp.h"
// 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"
// TnzSound includes
#include "tnzsound.h"
// TnzImage includes
#include "timage_io.h"
#include "tnzimage.h"
#include "tflash.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>
//==================================================================================
using namespace std;
using namespace TCli;
typedef ArgumentT<TFilePath> FilePathArgument;
typedef QualifierT<TFilePath> FilePathQualifier;
namespace
{
double currentCameraSize = 12;
double getCurrentCameraSize()
{
return currentCameraSize;
}
}
//========================================================================
//
// 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 *applicationName = "OpenToonz";
const char *applicationVersion = "1.0";
const char *applicationFullName = "OpenToonz 1.0";
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 " + toString(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);
}
}
//==============================================================================================
class MyMovieRenderListener : 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);
bool onFrameFailed(int frame, TException &e);
void onSequenceCompleted(const TFilePath &fp);
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 = toString(fp.withName(fp.getName() + "_l").getWideString()) + " and " + toString(fp.withName(fp.getName() + "_r").getWideString()) + " computed";
else
msg = toString(fp.getWideString()) + " 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 " + toString(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 = toString(fp.getWideString()) + " failed";
if (!e.getMessage().empty())
msg += ": " + toString(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 " + toString(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 : 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);
bool onFrameFailed(int frame, int column, TException &e);
void onSequenceCompleted(int column) {}
void onRenderCompleted() {}
};
//==================================================================================
bool MyMultimediaRenderListener::onFrameCompleted(int frame, int column)
{
int actualFrame = frame + 1;
string msg = toString(m_fp.getWideString()) + ", column " + toString(column) + ", frame " + toString(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 " + toString(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 = toString(m_fp.getWideString()) + ", column " + toString(column) + ", frame " + toString(actualFrame) + " failed";
if (!e.getMessage().empty())
msg += ": " + toString(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 " + toString(FarmControllerPort) + "@" + FarmControllerName.toStdString();
cout << msg;
m_userLog->error(msg);
}
}
m_frameFailedCount++;
return true;
}
//==================================================================================
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(toWideString(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)
DV_IMPORT_API void initStdFx();
DV_IMPORT_API void initColorFx();
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Create a QObject destroyed just before app - see Tnz6's main.cpp for rationale
std::auto_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-dependant.
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::setApplication(applicationName, applicationVersion);
TEnv::setApplicationFullName(applicationFullName);
TEnv::setRootVarName(rootVarName);
TEnv::setSystemVarPrefix(systemVarPrefix);
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("");
// TODO: non va qui. Bisognerebbe semmai modificare l'implementazione
// delle TEnv:: precedenti. Discutiamone
#ifdef MACOSX
// StuffDir
QFileInfo infoStuff(QString("Toonz 7.1 stuff"));
TFilePath stuffDirPath(infoStuff.absoluteFilePath().toStdString());
TEnv::setStuffDir(stuffDirPath);
#endif
// controllo se la xxxroot e' definita e corrisponde ad un file esistente
TFilePath fp = TEnv::getStuffDir();
if (fp == TFilePath())
fatalError(string("Undefined: \"") + toString(TEnv::getRootVarPath().getWideString()) + "\"");
if (!TFileStatus(fp).isDirectory())
fatalError(string("Directory \"") + toString(fp.getWideString()) + "\" 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
// 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");
Usage usage(argv[0]);
usage.add(srcName + dstName + range + stepOpt + shrinkOpt + multimedia + farmData + idq + nthreads + tileSize + tmsg);
if (!usage.parse(argc, argv))
exit(1);
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 = toInt(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
Sw1.start();
if (!TSystem::doesExistFileOrLevel(srcFilePath))
return false;
ToonzScene *scene = new ToonzScene();
TImageStyle::setCurrentScene(scene);
try {
Sw2.start();
scene->load(srcFilePath);
Sw2.stop();
} catch (TException &e) {
cout << toString(e.getMessage()) << endl;
m_userLog->error(toString(e.getMessage()));
return -2;
} catch (...) {
string msg;
msg = "There were problems loading the scene " + toString(srcFilePath.getWideString()) +
".\n Some files may be missing.";
cout << msg << endl;
m_userLog->error(msg);
//return false;
}
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: " + toString(threadCount));
if (maxTileSize != (std::numeric_limits<int>::max)())
m_userLog->info("Render tile: " + toString(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: " + toString(TBigMemoryManager::instance()->getAllocationPeak()) + " KB");
m_userLog->info("Raster Allocation Mean: " + toString(TBigMemoryManager::instance()->getAllocationMean()) + " KB");
msg = "Compositing completed in " + toString(Sw1.getTotalTime() / 1000.0, 2) + " seconds";
string msg2 = "\n" + toString(Sw2.getTotalTime() / 1000.0, 2) + " seconds spent on loading" + "\n" +
toString(TStopWatch::global(0).getTotalTime() / 1000.0, 2) + " seconds spent on saving" + "\n" +
toString(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);
/*
cout << "Compositing completed in " + toString(Sw1.getTotalTime()/1000.0, 2) + " seconds";
cout << endl;
cout << toString(Sw2.getTotalTime()/1000.0, 2) << " seconds spent on loading" << endl;
cout << toString(TStopWatch::global(0).getTotalTime()/1000.0, 2) << " seconds spent on saving" << endl;
cout << toString(TStopWatch::global(8).getTotalTime()/1000.0, 2) << " seconds spent on rendering" << endl;
cout << endl;*/
} catch (TException &e) {
msg = "Untrapped exception: " + toString(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;
}