StageObjectsData *StageObjectsData::clone() const { StageObjectsData *data = new StageObjectsData(); // Clone each element (the new data gets ownership) int i, elementsCount = m_elements.size(); for (i = 0; i < elementsCount; ++i) data->m_elements.append(m_elements[i]->clone()); // Clone each spline (the new data gets ownership) for (i = 0; i < m_splines.size(); ++i) data->m_splines.append(m_splines[i]->clone()); // Same for internal fxs std::map<TFx *, TFx *> fxTable; // And trace the pairings with the originals std::set<TFx *>::const_iterator it; for (it = m_fxs.begin(); it != m_fxs.end(); ++it) { TFx *fxOrig = *it; assert(fxOrig); assert(fxTable.count(fxOrig) == 0); TFx *fx = fxOrig->clone(false); fx->getAttributes()->setId(fxOrig->getAttributes()->getId()); fx->getAttributes()->passiveCacheDataIdx() = -1; fx->setName(fxOrig->getName()); fx->setFxId(fxOrig->getFxId()); fxTable[fxOrig] = fx; fx->addRef(); data->m_fxs.insert(fx); } // Same with terminals for (it = m_terminalFxs.begin(); it != m_terminalFxs.end(); ++it) { TFx *fxOrig = *it; assert(fxOrig); // If the fx was not already cloned above, do it now TFx *fx = searchFx(fxTable, fxOrig); if (!fx) { fx = fxOrig->clone(false); fx->getAttributes()->setId(fxOrig->getAttributes()->getId()); fx->getAttributes()->passiveCacheDataIdx() = -1; fx->setName(fxOrig->getName()); fx->setFxId(fxOrig->getFxId()); fxTable[fxOrig] = fx; } fx->addRef(); data->m_terminalFxs.insert(fx); } if (!fxTable.empty()) updateFxLinks(fxTable); // Applies the traced map pairings to every fx descendant // of each fx stored in the map. // WARNING: m_fxsTable is NOT COPIED / CLONED !! return data; }
TXshZeraryFxColumn::TXshZeraryFxColumn(const TXshZeraryFxColumn &src) : m_zeraryColumnFx(new TZeraryColumnFx()), m_zeraryFxLevel(new TXshZeraryFxLevel()) { m_zeraryColumnFx->addRef(); m_zeraryColumnFx->setColumn(this); m_zeraryFxLevel->addRef(); m_zeraryFxLevel->setColumn(this); m_first = src.m_first; int i; for (i = 0; i < (int)src.m_cells.size(); i++) m_cells.push_back(TXshCell(m_zeraryFxLevel, src.m_cells[i].getFrameId())); assert((int)src.m_cells.size() == (int)m_cells.size()); TFx *fx = src.getZeraryColumnFx()->getZeraryFx(); if (fx) { wstring fxName = fx->getName(); fx = fx->clone(false); fx->setName(fxName); m_zeraryColumnFx->setZeraryFx(fx); } }
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(); }
std::vector<TStageObjectId> StageObjectsData::restoreObjects(std::set<int> &columnIndices, std::list<int> &restoredSpline, TXsheet *xsh, int fxFlags, const TPointD &pos) const { bool doClone = (fxFlags & eDoClone); bool resetFxDagPositions = (fxFlags & eResetFxDagPositions); QMap<TStageObjectId, TStageObjectId> idTable; // Trace stored/restored id pairings std::map<TFx *, TFx *> fxTable; // Same for fxs here std::vector<TStageObjectId> restoredIds; std::set<int>::iterator idxt = columnIndices.begin(); int index = -1; // The actual column insertion index int i, elementsCount = m_elements.size(); for (i = 0; i < elementsCount; ++i) { TStageObjectDataElement *element = m_elements[i]; TCameraDataElement *cameraElement = dynamic_cast<TCameraDataElement *>(element); TColumnDataElement *columnElement = dynamic_cast<TColumnDataElement *>(element); // Restore the object depending on its specific type TStageObjectId restoredId = TStageObjectId::NoneId; if (!cameraElement && !columnElement) restoredId = element->restoreObject(xsh, pos != TConst::nowhere); else if (cameraElement) restoredId = cameraElement->restoreCamera(xsh, pos != TConst::nowhere); else if (columnElement) { // Build the column insertion index if (idxt != columnIndices.end()) index = *idxt++; else { ++index; columnIndices.insert(index); } // Restore the column element restoredId = columnElement->restoreColumn(xsh, index, fxFlags, pos != TConst::nowhere); FxDag *fxDag = xsh->getFxDag(); TXshColumn *column = columnElement->m_column.getPointer(); TXshColumn *pastedColumn = xsh->getColumn(index); TFx *fx = column->getFx(); TFx *pastedFx = pastedColumn->getFx(); if (fx && pastedFx) fxTable[fx] = pastedFx; // Enforce the correct terminality. Added columns are terminal by default. bool terminal = (fx && (m_terminalFxs.count(fx) > 0)); if (!terminal) fxDag->getTerminalFxs()->removeFx(pastedFx); // In case we've cloned a zerary fx column, update the actual fx's data if (TXshZeraryFxColumn *zc = dynamic_cast<TXshZeraryFxColumn *>(pastedColumn)) { TZeraryColumnFx *zfx = zc->getZeraryColumnFx(); TFx *zeraryFx = zfx->getZeraryFx(); if (zeraryFx && doClone) { std::wstring app = zeraryFx->getName(); fxDag->assignUniqueId(zeraryFx); zeraryFx->setName(app); } } } // Remember stored/restored stage object pairings idTable[element->m_params->m_id] = restoredId; restoredIds.push_back(restoredId); } // Apply stage object-parental relationships for (i = 0; i < elementsCount; ++i) { TStageObjectDataElement *element = m_elements[i]; TStageObjectId id = element->m_params->m_id; TStageObjectId parentId = element->m_params->m_parentId; TStageObjectId pastedId = idTable[id]; TStageObjectId pastedParentId = parentId; if (parentId.isColumn()) // Why discriminating for columns only ? { //Columns are redirected to table ids. If no redirected parent exists, store //a void value that will be avoided later QMap<TStageObjectId, TStageObjectId>::iterator it = idTable.find(parentId); pastedParentId = (it == idTable.end()) ? TStageObjectId::NoneId : it.value(); } if (pastedParentId != TStageObjectId::NoneId) { xsh->setStageObjectParent(pastedId, pastedParentId); TStageObject *pastedObj = xsh->getStageObject(pastedId); // Shouldn't these be done outside ? pastedObj->setHandle(element->m_params->m_handle); pastedObj->setParentHandle(element->m_params->m_parentHandle); } } // Iterate stored fxs std::set<TFx *>::const_iterator fxt, end = m_fxs.end(); for (fxt = m_fxs.begin(); fxt != end; ++fxt) { TFx *fxOrig = *fxt, *fx = fxOrig; // Only NOT COLUMN fxs - ie internal fxs if (fxTable.find(fxOrig) != fxTable.end()) continue; // Internal fxs if (doClone) { fx = fxOrig->clone(false); fx->setName(fxOrig->getName()); fx->getAttributes()->setId(fxOrig->getAttributes()->getId()); fx->getAttributes()->passiveCacheDataIdx() = -1; if (resetFxDagPositions) fx->getAttributes()->setDagNodePos(TConst::nowhere); xsh->getFxDag()->assignUniqueId(fx); } fxTable[fxOrig] = fx; // Insert the passed fx in the xsheet TOutputFx *outFx = dynamic_cast<TOutputFx *>(fx); if (!outFx) xsh->getFxDag()->getInternalFxs()->addFx(fx); else xsh->getFxDag()->addOutputFx(outFx); if (m_terminalFxs.count(fxOrig) > 0) xsh->getFxDag()->getTerminalFxs()->addFx(fx); if (!doClone) { // Err.... don't remember. Inquire further? :| int fxTypeCount = xsh->getFxDag()->getFxTypeCount(fx); int maxFxTypeId = std::max(fxTypeCount, fx->getAttributes()->getId()); xsh->getFxDag()->updateFxTypeTable(fx, maxFxTypeId); xsh->getFxDag()->updateFxIdTable(fx); } bool isLinked = (fxOrig->getLinkedFx() != fxOrig); if (isLinked) { if (m_fxs.find(fxOrig->getLinkedFx()) == m_fxs.end()) fx->linkParams(fxOrig->getLinkedFx()); else { TFx *linkedFx, *oldLinkedFx = fxOrig->getLinkedFx(); if (doClone) { // Clone the linked fx too linkedFx = fx->clone(false); linkedFx->linkParams(fx); linkedFx->setName(oldLinkedFx->getName()); linkedFx->getAttributes()->setId(oldLinkedFx->getAttributes()->getId()); linkedFx->getAttributes()->passiveCacheDataIdx() = -1; if (resetFxDagPositions) linkedFx->getAttributes()->setDagNodePos(TConst::nowhere); else linkedFx->getAttributes()->setDagNodePos(oldLinkedFx->getAttributes()->getDagNodePos()); xsh->getFxDag()->assignUniqueId(linkedFx); } else linkedFx = oldLinkedFx; fxTable[oldLinkedFx] = linkedFx; xsh->getFxDag()->getInternalFxs()->addFx(linkedFx); if (m_terminalFxs.count(oldLinkedFx) > 0) xsh->getFxDag()->getTerminalFxs()->addFx(linkedFx); if (!doClone) { int fxTypeCount = xsh->getFxDag()->getFxTypeCount(linkedFx); int maxFxTypeId = std::max(fxTypeCount, linkedFx->getAttributes()->getId()); xsh->getFxDag()->updateFxTypeTable(linkedFx, maxFxTypeId); xsh->getFxDag()->updateFxIdTable(linkedFx); } } } } // Update the link, like in functions above if (!fxTable.empty() && doClone) updateFxLinks(fxTable); // Paste any associated spline (not stored im m_splines) std::map<TStageObjectSpline *, TStageObjectSpline *> splines; for (i = 0; i < (int)restoredIds.size(); ++i) { TStageObjectId id = restoredIds[i]; TStageObject *obj = xsh->getStageObject(id); TStageObjectSpline *spline = obj->getSpline(); if (!spline) continue; TStageObjectTree *objTree = xsh->getStageObjectTree(); if (objTree->containsSpline(spline)) // No need to add it if it's already there continue; std::map<TStageObjectSpline *, TStageObjectSpline *>::iterator it = splines.find(spline); if (it != splines.end()) { // Seems that multiple objects can have the same spline... // BTW, shouldn't this case stop at the continue before ? obj->setSpline(it->second); continue; } // The spline was not found. Clone and add it to the xsheet TStageObjectSpline *newSpline = spline->clone(); // Not checking doClone ? objTree->assignUniqueSplineId(newSpline); objTree->insertSpline(newSpline); obj->setSpline(newSpline); splines[spline] = newSpline; } //paste stored path QList<TSplineDataElement *>::const_iterator splinIt; for (splinIt = m_splines.begin(); splinIt != m_splines.end(); ++splinIt) { TStageObjectTree *objTree = xsh->getStageObjectTree(); TSplineDataElement *splineEl = *splinIt; TStageObjectSpline *spline = splineEl->restoreSpline(fxFlags); if (doClone) objTree->assignUniqueSplineId(spline); objTree->insertSpline(spline); restoredSpline.push_back(spline->getId()); } xsh->updateFrameCount(); if (pos != TConst::nowhere) { // Update objects positions depending on the externally supplied pos TPointD middlePos; int count = 0; for (i = 0; i < (int)restoredIds.size(); ++i) { TStageObjectId id = restoredIds[i]; TStageObject *obj = xsh->getStageObject(id); TPointD oldPos = obj->getDagNodePos(); if (oldPos == TConst::nowhere) continue; middlePos += oldPos; ++count; } middlePos = TPointD(middlePos.x / count, middlePos.y / count); TPointD offset = pos - middlePos; for (i = 0; i < (int)restoredIds.size(); ++i) { TStageObjectId id = restoredIds[i]; TStageObject *obj = xsh->getStageObject(id); TPointD oldPos = obj->getDagNodePos(); if (oldPos == TConst::nowhere) continue; obj->setDagNodePos(oldPos + offset); } } return restoredIds; }
void StageObjectsData::storeColumnFxs(const std::set<int> &columnIndexes, TXsheet *xsh, int fxFlags) { bool doClone = (fxFlags & eDoClone); bool resetFxDagPositions = (fxFlags & eResetFxDagPositions); std::set<TFx *> internalFxs; xsh->getFxDag()->getInternalFxs()->getFxs(internalFxs); // Iterate internal fxs (note: columns NOT included) // NOTE: Could this be too heavy ? Shouldn't we travel upstream from given column fxs? std::set<TFx *>::iterator it; for (it = internalFxs.begin(); it != internalFxs.end(); ++it) { TFx *fxOrig = *it, *fx = fxOrig; if (m_fxTable.find(fx) != m_fxTable.end()) // If already treated continue; if (!canGenerate(m_originalColumnFxs, fx)) // If not completely in the upstream continue; if (doClone) { // Clone the fx if required fx = fxOrig->clone(false); fx->setName(fxOrig->getName()); fx->getAttributes()->setId(fxOrig->getAttributes()->getId()); fx->getAttributes()->passiveCacheDataIdx() = -1; if (resetFxDagPositions) fx->getAttributes()->setDagNodePos(TConst::nowhere); } m_fxTable[fxOrig] = fx; fx->addRef(); m_fxs.insert(fx); if (isColumnSelectionTerminalFx( fxOrig, xsh->getFxDag()->getTerminalFxs(), m_originalColumnFxs)) { fx->addRef(); m_terminalFxs.insert(fx); } if (fxOrig->getLinkedFx() != fxOrig) // Linked fx { if (!canGenerate(m_originalColumnFxs, fxOrig->getLinkedFx())) fx->linkParams(fxOrig->getLinkedFx()); else { // Insert the linked fx directly here TFx *linkedFx, *oldLinkedFx = fxOrig->getLinkedFx(); if (doClone) { linkedFx = fx->clone(false); // Not oldLinkedFx->clone() ? linkedFx->linkParams(fx); linkedFx->setName(oldLinkedFx->getName()); linkedFx->getAttributes()->setId(oldLinkedFx->getAttributes()->getId()); linkedFx->getAttributes()->passiveCacheDataIdx() = -1; if (resetFxDagPositions) fx->getAttributes()->setDagNodePos(TConst::nowhere); // Here too ? xsh->getFxDag()->assignUniqueId(linkedFx); } else linkedFx = oldLinkedFx; m_fxTable[oldLinkedFx] = linkedFx; linkedFx->addRef(); m_fxs.insert(linkedFx); if (xsh->getFxDag()->getTerminalFxs()->containsFx(fx->getLinkedFx())) // Here too - isATerminal ? { linkedFx->addRef(); m_terminalFxs.insert(linkedFx); } } } } // Like in the functions above, update links if (!m_fxTable.empty() && doClone) updateFxLinks(m_fxTable); }
void StageObjectsData::storeFxs(const std::set<TFx *> &fxs, TXsheet *xsh, int fxFlags) { bool doClone = (fxFlags & eDoClone); bool resetFxDagPositions = (fxFlags & eResetFxDagPositions); TFxSet *terminalFxs = xsh->getFxDag()->getTerminalFxs(); // Traverse specified fxs std::set<TFx *>::const_iterator it; for (it = fxs.begin(); it != fxs.end(); ++it) { TFx *fxOrig = *it, *fx = fxOrig; if (doClone) { // If required, clone them fx = fxOrig->clone(false); fx->setName(fxOrig->getName()); fx->getAttributes()->setId(fxOrig->getAttributes()->getId()); fx->getAttributes()->passiveCacheDataIdx() = -1; if (resetFxDagPositions) fx->getAttributes()->setDagNodePos(TConst::nowhere); } // Store them (and the original/clone pairing even if not cloning) m_fxTable[fxOrig] = fx; fx->addRef(); m_fxs.insert(fx); // Find out if the fx is a terminal one in the selection. If so, store it there too. bool isTerminal = true; if (!terminalFxs->containsFx(fxOrig)) // If it's terminal in the xsheet, no doubt { // Otherwise, check terminality with respect to the selection int i, outputConnectionsCount = fxOrig->getOutputConnectionCount(); for (i = 0; i < outputConnectionsCount; ++i) { TFx *outputFx = fxOrig->getOutputConnection(i)->getOwnerFx(); if (outputFx && fxs.count(outputFx) > 0) { isTerminal = false; break; } } } // Well, excluding true TOutputFxs... TOutputFx *outFx = dynamic_cast<TOutputFx *>(fx); if (isTerminal && !outFx) { fx->addRef(); m_terminalFxs.insert(fx); } } // Updating terminality of the column fxs too! // WARNING: This requires that storeObjects() is invoked BEFORE this ! for (it = m_originalColumnFxs.begin(); it != m_originalColumnFxs.end(); ++it) { TFx *fxOrig = *it; bool isTerminal = true; if (!terminalFxs->containsFx(fxOrig)) { int i, outputConnectionsCount = fxOrig->getOutputConnectionCount(); for (i = 0; i < outputConnectionsCount; ++i) { TFx *outputFx = fxOrig->getOutputConnection(i)->getOwnerFx(); if (outputFx && fxs.count(outputFx) > 0) { isTerminal = false; break; } } } if (isTerminal) { TFx *fx = m_fxTable[fxOrig]; fx->addRef(); m_terminalFxs.insert(fx); } } if (!m_fxTable.empty() && doClone) updateFxLinks(m_fxTable); // Apply original/clone pairings // to fx relatives }