void MultimediaRenderer::Imp::start() { //Retrieve some useful infos double stretchTo = m_renderSettings.m_timeStretchTo; double stretchFrom = m_renderSettings.m_timeStretchFrom; double timeStretchFactor = stretchFrom / stretchTo; bool fieldRendering = m_renderSettings.m_fieldPrevalence != TRenderSettings::NoField; std::wstring modeStr; switch (m_multimediaMode) { case COLUMNS: modeStr = L"_col"; break; case LAYERS: modeStr = L"_lay"; break; default: assert(0); } //Build the post processing fxs tree std::vector<TFxP> postFxs(m_framesToRender.size()); std::set<double>::iterator jt; int j; for (j = 0, jt = m_framesToRender.begin(); jt != m_framesToRender.end(); ++j, ++jt) postFxs[j] = buildPostSceneFx(m_scene, *jt, m_renderSettings.m_shrinkX, false); // Adds camera and camera dpi transforms //For each node to be rendered int i, count = m_fxsToRender.getFxCount(); for (i = 0; i < count; ++i) { //In case the process has been canceled, return if (m_canceled) return; //Then, build the scene fx for each frame to be rendered std::vector<std::pair<double, TFxPair>> pairsToBeRendered; //NOTE: The above pairs should not be directly added to a previously declared movierenderer, //since an output level would be created even before knowing if any cell to be rendered is //actually available. const BSFX_Transforms_Enum transforms = // Do NOT add camera and BSFX_Transforms_Enum(BSFX_COLUMN_TR); // camera dpi transforms int j; for (j = 0, jt = m_framesToRender.begin(); jt != m_framesToRender.end(); ++j, ++jt) { TFxPair fx; if (m_renderSettings.m_stereoscopic) m_scene->shiftCameraX(-m_renderSettings.m_stereoscopicShift / 2); fx.m_frameA = buildSceneFx(m_scene, *jt, 0, m_fxsToRender.getFx(i), transforms); if (m_renderSettings.m_stereoscopic) { m_scene->shiftCameraX(m_renderSettings.m_stereoscopicShift); fx.m_frameB = buildSceneFx(m_scene, *jt, 0, m_fxsToRender.getFx(i), transforms); m_scene->shiftCameraX(-m_renderSettings.m_stereoscopicShift / 2); } else if (fieldRendering) fx.m_frameB = buildSceneFx(m_scene, *jt + 0.5 * timeStretchFactor, 0, m_fxsToRender.getFx(i), transforms); else fx.m_frameB = TRasterFxP(); //Substitute with the post-process... if (fx.m_frameA) fx.m_frameA = addPostProcessing(fx.m_frameA, postFxs[j]); if (fx.m_frameB) fx.m_frameB = addPostProcessing(fx.m_frameB, postFxs[j]); if (fx.m_frameA) //Could be 0, if the corresponding cell is void / not rendered pairsToBeRendered.push_back(std::pair<double, TFxPair>(*jt, fx)); } if (pairsToBeRendered.size() == 0) continue; //Could be, if no cell for this column was in the frame range. //Build the output name TColumnFx *colFx = searchColumn(m_fxsToRender.getFx(i)); TFx *currFx = m_fxsToRender.getFx(i); assert(colFx); if (!colFx) continue; int columnIndex = colFx->getColumnIndex(); std::wstring columnName(colFx->getColumnName()); std::wstring columnId(colFx->getColumnId()); std::wstring fxName(currFx->getName()); std::wstring fxNameNoSpaces(::removeSpaces(fxName)); std::wstring fxId(currFx->getFxId()); std::wstring fpName = m_fp.getWideName() + L"_" + columnName + (columnId == columnName ? L"" : L"(" + columnId + L")") + (fxId.empty() ? L"" : L"_" + fxName + (fxId == fxNameNoSpaces ? L"" : L"(" + fxId + L")")); TFilePath movieFp(m_fp.withName(fpName)); //Initialize a MovieRenderer with our infos MovieRenderer movieRenderer(m_scene, movieFp, m_threadCount, false); movieRenderer.setRenderSettings(m_renderSettings); movieRenderer.setDpi(m_xDpi, m_yDpi); movieRenderer.enablePrecomputing(m_precomputingEnabled); movieRenderer.addListener(this); for (unsigned int j = 0; j < pairsToBeRendered.size(); ++j) { std::pair<double, TFxPair> ¤tPair = pairsToBeRendered[j]; movieRenderer.addFrame(currentPair.first, currentPair.second); } //Finally, start rendering currently initialized MovieRenderer. m_currentFx = i; m_currentFrame = m_framesToRender.begin(); m_currentTRenderer = movieRenderer.getTRenderer(); movieRenderer.start(); //I don't recall Toonz currently supports different, simultaneous rendering processes. //However, one rendering process is supposed to be exhausting the machine's resources //on its own - so, we'll just set up an idle (but GUI-reactive) loop here. //It will quit looping whenever the "onSequenceCompleted" notification gets called. m_eventLoop.exec(); //---------------------- Loops here -------------------------- } //Lastly, inform everyone that rendering stopped onRenderCompleted(); }
void RenderCommand::rasterRender(bool isPreview) { ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); if (isPreview) { //Let the PreviewFxManager own the rest. Just pass him the current output node. PreviewFxManager::instance()->showNewPreview((TFx *)scene->getXsheet()->getFxDag()->getCurrentOutputFx()); return; } string ext = m_fp.getType(); #ifdef WIN32 if (ext == "avi" && !isPreview) { TPropertyGroup *props = scene->getProperties()->getOutputProperties()->getFileFormatProperties(ext); string codecName = props->getProperty(0)->getValueAsString(); TDimension res = scene->getCurrentCamera()->getRes(); if (!AviCodecRestrictions::canWriteMovie(toWideString(codecName), res)) { QString msg(QObject::tr("The resolution of the output camera does not fit with the options chosen for the output file format.")); MsgBox(WARNING, msg); return; } } #endif; //Extract output properties TOutputProperties *prop = isPreview ? scene->getProperties()->getPreviewProperties() : scene->getProperties()->getOutputProperties(); //Build thread count /*-- Dedicated CPUs のコンボボックス (Single, Half, All) --*/ int index = prop->getThreadIndex(); const int procCount = TSystem::getProcessorCount(); const int threadCounts[3] = {1, procCount / 2, procCount}; int threadCount = threadCounts[index]; /*-- MovieRendererを作る。Previewの場合はファイルパスは空 --*/ MovieRenderer movieRenderer(scene, isPreview ? TFilePath() : m_fp, threadCount, isPreview); TRenderSettings rs = prop->getRenderSettings(); //Build raster granularity size index = prop->getMaxTileSizeIndex(); const int maxTileSizes[4] = { (std::numeric_limits<int>::max)(), TOutputProperties::LargeVal, TOutputProperties::MediumVal, TOutputProperties::SmallVal}; rs.m_maxTileSize = maxTileSizes[index]; //Build #ifdef BRAVODEMO rs.m_mark = loadBravo(scene->getCurrentCamera()->getRes()); #endif /*-- RenderSettingsをセット --*/ movieRenderer.setRenderSettings(rs); /*-- カメラDPIの取得、セット --*/ TPointD cameraDpi = isPreview ? scene->getCurrentPreviewCamera()->getDpi() : scene->getCurrentCamera()->getDpi(); movieRenderer.setDpi(cameraDpi.x, cameraDpi.y); movieRenderer.enablePrecomputing(true); /*-- プログレス ダイアログの作成 --*/ RenderListener *listener = new RenderListener(movieRenderer.getTRenderer(), m_fp, ((m_numFrames - 1) / m_step) + 1, isPreview); QObject::connect(listener, SIGNAL(canceled()), &movieRenderer, SLOT(onCanceled())); movieRenderer.addListener(listener); bool fieldRendering = rs.m_fieldPrevalence != TRenderSettings::NoField; /*-- buildSceneFxの進行状況を表示するプログレスバー --*/ QProgressBar *buildSceneProgressBar = new QProgressBar(TApp::instance()->getMainWindow()); buildSceneProgressBar->setAttribute(Qt::WA_DeleteOnClose); buildSceneProgressBar->setWindowFlags(Qt::SubWindow | Qt::Dialog | Qt::WindowStaysOnTopHint); buildSceneProgressBar->setMinimum(0); buildSceneProgressBar->setMaximum(m_numFrames - 1); buildSceneProgressBar->setValue(0); buildSceneProgressBar->move(600, 500); buildSceneProgressBar->setWindowTitle("Building Schematic..."); buildSceneProgressBar->show(); for (int i = 0; i < m_numFrames; ++i, m_r += m_stepd) { buildSceneProgressBar->setValue(i); if (rs.m_stereoscopic) scene->shiftCameraX(-rs.m_stereoscopicShift / 2); TFxPair fx; fx.m_frameA = buildSceneFx(scene, m_r, rs.m_shrinkX, isPreview); if (fieldRendering && !isPreview) fx.m_frameB = buildSceneFx(scene, m_r + 0.5 / m_timeStretchFactor, rs.m_shrinkX, isPreview); else if (rs.m_stereoscopic) { scene->shiftCameraX(rs.m_stereoscopicShift); fx.m_frameB = buildSceneFx(scene, m_r + 0.5 / m_timeStretchFactor, rs.m_shrinkX, isPreview); scene->shiftCameraX(-rs.m_stereoscopicShift / 2); } else fx.m_frameB = TRasterFxP(); /*-- movieRendererにフレーム毎のFxを登録 --*/ movieRenderer.addFrame(m_r, fx); } /*-- プログレスバーを閉じる --*/ buildSceneProgressBar->close(); //resetViewer(); //TODO cancella le immagini dell'eventuale render precedente //FileViewerPopupPool::instance()->getCurrent()->onClose(); movieRenderer.start(); }