TFx *InsertFxPopup::createFx() { TApp *app = TApp::instance(); ToonzScene *scene = app->getCurrentScene()->getScene(); TXsheet *xsh = scene->getXsheet(); QTreeWidgetItem *item = m_fxTree->currentItem(); QString text = item->data(0, Qt::UserRole).toString(); if (text.isEmpty()) return 0; TFx *fx; TFilePath path = TFilePath(text.toStdWString()); if (TFileStatus(path).doesExist() && TFileStatus(path.getParentDir()).isDirectory()) { std::string folder = path.getParentDir().getName(); if (folder == "macroFx") //Devo caricare una macro fx = createMacroFxByPath(path); else //Verifico se devo caricare un preset { folder = path.getParentDir().getParentDir().getName(); if (folder == "presets") //Devo caricare un preset fx = createPresetFxByName(path); } } else fx = createFxByName(text.toStdString()); if (fx) return fx; else return 0; }
void addSoundtrack(const ToonzScene &scene, int frameOffset, int sceneFrameCount) { assert(m_status <= 2); m_status = 2; TXsheet::SoundProperties *prop = new TXsheet::SoundProperties(); prop->m_frameRate = m_fps; TSoundTrack *snd = scene.getXsheet()->makeSound(prop); if (!snd || m_filepath.getDots() == "..") { m_whiteSample += sceneFrameCount * 918; return; } long samplePerFrame = snd->getSampleRate() / m_fps; TSoundTrackP snd1 = snd->extract( frameOffset * samplePerFrame, (TINT32)((frameOffset + sceneFrameCount - 1) * samplePerFrame)); if (!m_st) { m_st = TSoundTrack::create(snd1->getFormat(), m_whiteSample); m_whiteSample = 0; } TINT32 fromSample = m_st->getSampleCount(); TINT32 numSample = std::max(TINT32(sceneFrameCount * samplePerFrame), snd1->getSampleCount()); m_st = TSop::insertBlank(m_st, fromSample, numSample + m_whiteSample); m_st->copy(snd1, TINT32(fromSample + m_whiteSample)); m_whiteSample = 0; }
bool addFrame(ToonzScene &scene, int row, bool isLast) { TAffine cameraView = scene.getXsheet()->getPlacement(TStageObjectId::CameraId(0), row).inv(); TPixel32 bgColor = scene.getProperties()->getBgColor(); TStageObject *cameraPegbar = scene.getXsheet()->getStageObject(TStageObjectId::CameraId(0)); assert(cameraPegbar); TCamera *camera = cameraPegbar->getCamera(); assert(camera); TAffine dpiAff = getDpiAffine(camera).inv(); TAffine aff = cameraView * dpiAff; Stage::VisitArgs args; args.m_scene = &scene; args.m_xsh = scene.getXsheet(); args.m_row = row; args.m_col = m_columnIndex; args.m_osm = &m_osMask; ImagePainter::VisualSettings vs; FlashStagePainter painter(m_flash, aff, vs, bgColor); m_flash.beginFrame(++m_frameIndex); Stage::visit(painter, args); /* &scene, scene.getXsheet(), row, m_columnIndex, m_osMask, false, 0); */ m_frameIndex = m_flash.endFrame(isLast, m_frameCountLoader, (m_sceneCount == m_sceneIndex)); return true; }
QScriptValue foo(QScriptContext *ctx, QScriptEngine *eng) { int r = ctx->argument(0).toInteger(); int c = ctx->argument(1).toInteger(); QScriptValue levelArg = ctx->argument(2); ScriptWrapper::Level *level = dynamic_cast<ScriptWrapper::Level *>(levelArg.toQObject()); if (level) { TXshSimpleLevel *sl = level->getLevel(); if (!sl) return QScriptValue(0); TFrameId fid(1); if (!sl->isFid(fid)) sl->setFrame(fid, sl->createEmptyFrame()); ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); scene->getXsheet()->setCell(r, c, TXshCell(sl, fid)); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } return QScriptValue(1); }
void startScene(const ToonzScene &scene, int r) { m_flash.cleanCachedImages(); m_flash.setBackgroundColor(m_bgColor); TXsheet::SoundProperties *prop = new TXsheet::SoundProperties(); prop->m_frameRate = m_fps; TSoundTrackP snd = scene.getXsheet()->makeSound(prop); if (snd) { if (m_useMarkers) { long samplePerFrame = snd->getSampleRate() / m_fps; snd = snd->extract((TINT32)(m_renderRange.first * samplePerFrame), (TINT32)(m_renderRange.second * samplePerFrame)); } m_flash.putSound(snd, 0); } if (m_sceneIndex == 0 && m_sceneCount == 1) { if (m_renderRange.first == m_renderRange.second) m_frameCountLoader = 0; else m_frameCountLoader = 1; } else if (m_sceneIndex == 0) m_frameCountLoader = m_renderRange.second - m_renderRange.first + 1; m_sceneIndex++; }
bool LevelCreatePopup::apply() { TApp *app = TApp::instance(); int row = app->getCurrentFrame()->getFrame(); int col = app->getCurrentColumn()->getColumnIndex(); int i, j; ToonzScene *scene = app->getCurrentScene()->getScene(); TXsheet *xsh = scene->getXsheet(); bool validColumn = true; if (xsh->getColumn(col)) validColumn = xsh->getColumn(col)->getColumnType() == TXshColumn::eLevelType; int from = (int)m_fromFld->getValue(); int to = (int)m_toFld->getValue(); int inc = (int)m_incFld->getValue(); int step = (int)m_stepFld->getValue(); double w = m_widthFld->getValue(); double h = m_heightFld->getValue(); double dpi = m_dpiFld->getValue(); int xres = std::max(tround(w * dpi), 1); int yres = std::max(tround(h * dpi), 1); int lType = getLevelType(); std::wstring levelName = m_nameFld->text().toStdWString(); // tolgo i blanks prima e dopo i = levelName.find_first_not_of(L' '); if (i == (int)std::wstring::npos) levelName = L""; else { int j = levelName.find_last_not_of(L' '); assert(j != (int)std::wstring::npos); levelName = levelName.substr(i, j - i + 1); } if (levelName.empty()) { error(tr("No level name specified: please choose a valid level name")); return false; } if (from > to) { error(tr("Invalid frame range")); return false; } if (inc <= 0) { error(tr("Invalid increment value")); return false; } if (step <= 0) { error(tr("Invalid step value")); return false; } int numFrames = step * (((to - from) / inc) + 1); if (scene->getLevelSet()->getLevel(levelName)) { error( tr("The level name specified is already used: please choose a " "different level name")); m_nameFld->selectAll(); return false; } TFilePath parentDir(m_pathFld->getPath().toStdWString()); TFilePath fp = scene->getDefaultLevelPath(lType, levelName).withParentDir(parentDir); TFilePath actualFp = scene->decodeFilePath(fp); if (TSystem::doesExistFileOrLevel(actualFp)) { error( tr("The level name specified is already used: please choose a " "different level name")); m_nameFld->selectAll(); return false; } parentDir = scene->decodeFilePath(parentDir); if (!TFileStatus(parentDir).doesExist()) { QString question; /*question = "Folder " +toQString(parentDir) + " doesn't exist.\nDo you want to create it?";*/ question = tr("Folder %1 doesn't exist.\nDo you want to create it?") .arg(toQString(parentDir)); int ret = DVGui::MsgBox(question, QObject::tr("Yes"), QObject::tr("No")); if (ret == 0 || ret == 2) return false; try { TSystem::mkDir(parentDir); DvDirModel::instance()->refreshFolder(parentDir.getParentDir()); } catch (...) { error(tr("Unable to create") + toQString(parentDir)); return false; } } TXshLevel *level = scene->createNewLevel(lType, levelName, TDimension(), 0, fp); TXshSimpleLevel *sl = dynamic_cast<TXshSimpleLevel *>(level); assert(sl); sl->setPath(fp, true); if (lType == TZP_XSHLEVEL || lType == OVL_XSHLEVEL) { sl->getProperties()->setDpiPolicy(LevelProperties::DP_ImageDpi); sl->getProperties()->setDpi(dpi); sl->getProperties()->setImageDpi(TPointD(dpi, dpi)); sl->getProperties()->setImageRes(TDimension(xres, yres)); } /*-- これからLevelを配置しようとしているセルが空いているかどうかのチェック * --*/ bool areColumnsShifted = false; TXshCell cell = xsh->getCell(row, col); bool isInRange = true; for (i = row; i < row + numFrames; i++) { if (!cell.isEmpty()) { isInRange = false; break; } cell = xsh->getCell(i, col); } if (!validColumn) { isInRange = false; } /*-- 別のLevelに占有されていた場合、Columnを1つ右に移動 --*/ if (!isInRange) { col += 1; TApp::instance()->getCurrentColumn()->setColumnIndex(col); areColumnsShifted = true; xsh->insertColumn(col); } CreateLevelUndo *undo = new CreateLevelUndo(row, col, numFrames, step, areColumnsShifted); TUndoManager::manager()->add(undo); for (i = from; i <= to; i += inc) { TFrameId fid(i); TXshCell cell(sl, fid); if (lType == PLI_XSHLEVEL) sl->setFrame(fid, new TVectorImage()); else if (lType == TZP_XSHLEVEL) { TRasterCM32P raster(xres, yres); raster->fill(TPixelCM32()); TToonzImageP ti(raster, TRect()); ti->setDpi(dpi, dpi); sl->setFrame(fid, ti); ti->setSavebox(TRect(0, 0, xres - 1, yres - 1)); } else if (lType == OVL_XSHLEVEL) { TRaster32P raster(xres, yres); raster->clear(); TRasterImageP ri(raster); ri->setDpi(dpi, dpi); sl->setFrame(fid, ri); } for (j = 0; j < step; j++) xsh->setCell(row++, col, cell); } if (lType == TZP_XSHLEVEL || lType == OVL_XSHLEVEL) { sl->save(fp); DvDirModel::instance()->refreshFolder(fp.getParentDir()); } undo->onAdd(sl); app->getCurrentScene()->notifySceneChanged(); app->getCurrentScene()->notifyCastChange(); app->getCurrentXsheet()->notifyXsheetChanged(); // Cambia l'immagine corrente ma non cambiano ne' il frame ne' la colonna // corrente // (entrambi notificano il cambiamento dell'immagine al tool). // devo verfificare che sia settato il tool giusto. app->getCurrentTool()->onImageChanged( (TImage::Type)app->getCurrentImageType()); return true; }
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(); }
void RenderCommand::flashRender() { ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); TSceneProperties *sprop = scene->getProperties(); FILE *fileP = fopen(m_fp, "wb"); if (!fileP) return; ProgressDialog pb("rendering " + toQString(m_fp), "Cancel", 0, m_numFrames); pb.show(); TDimension cameraSize = scene->getCurrentCamera()->getRes(); double frameRate = sprop->getOutputProperties()->getFrameRate(); TFlash flash( cameraSize.lx, cameraSize.ly, m_numFrames, frameRate, sprop->getOutputProperties()->getFileFormatProperties("swf")); flash.setBackgroundColor(sprop->getBgColor()); std::vector<TXshSoundColumn *> columns; scene->getSoundColumns(columns); if (!columns.empty()) { TXsheet::SoundProperties *prop = new TXsheet::SoundProperties(); prop->m_frameRate = frameRate; TSoundTrack *st = scene->getXsheet()->makeSound(prop); if (st) flash.putSound(st, 0); } int i = 0; for (i = 0; i < m_numFrames; ++i, m_r += m_stepd) { flash.beginFrame(m_step * i + 1); TRasterFxP rfx = buildSceneFx(scene, m_r, 0, false); assert(rfx); rfx->compute(flash, tround(m_r)); // WARNING: This should accept a DOUBLE... #ifdef BRAVODEMO TRasterImageP ri(loadBravo(scene->getCurrentCamera()->getRes())); int lx = ri->getRaster()->getLx(); int ly = ri->getRaster()->getLx(); flash.pushMatrix(); int dx = tround(0.1 * (cameraSize.lx - lx)); int dy = tround(0.1 * (cameraSize.ly - ly)); flash.multMatrix(TTranslation((cameraSize.lx - lx) / 2 - (dx > 0 ? dx : 0), -(cameraSize.ly - ly) / 2 + (dy > 0 ? dy : 0))); flash.draw(ri, 0); flash.popMatrix(); #endif flash.endFrame(i == m_numFrames - 1, 0, true); if (pb.wasCanceled()) break; pb.setValue(i + 1); } flash.writeMovie(fileP); fclose(fileP); TSystem::showDocument(m_fp); //QDesktopServices::openUrl(QUrl(toQString(m_fp))); TImageCache::instance()->remove(toString(m_fp.getWideString() + L".0")); TNotifier::instance()->notify(TSceneNameChange()); }
bool VectorizerPopup::apply() { std::set<TXshLevel *> levels; ToonzScene *scene = m_sceneHandle->getScene(); if (!scene) { assert(scene); return false; } TSceneProperties *sceneProp = scene->getProperties(); if (!sceneProp) return false; VectorizerParameters *vectorizerParameters = sceneProp->getVectorizerParameters(); if (!vectorizerParameters) return false; int r0 = 0; int c0 = 0; int r1 = 0; int c1 = 0; bool isCellSelection = getSelectedLevels(levels, r0, c0, r1, c1); if (levels.empty()) { error(tr("The current selection is invalid.")); return false; } //Initialize Progress bar m_progressDialog = new DVGui::ProgressDialog("", "Cancel", 0, 1); m_progressDialog->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint); //Don't show ? and X buttons m_progressDialog->setWindowTitle(QString("Convert To Vector...")); m_progressDialog->setAttribute(Qt::WA_DeleteOnClose); m_progressDialog->setWindowModality(Qt::WindowModal); //No user interaction is allowed during vectorization m_progressDialog->setFixedSize(200, 100); //Initialize vectorizer m_vectorizer = new Vectorizer; m_vectorizer->setParameters(*vectorizerParameters); connect(m_vectorizer, SIGNAL(frameName(QString)), this, SLOT(onFrameName(QString)), Qt::QueuedConnection); connect(m_vectorizer, SIGNAL(frameDone(int)), this, SLOT(onFrameDone(int)), Qt::QueuedConnection); connect(m_vectorizer, SIGNAL(partialDone(int, int)), this, SLOT(onPartialDone(int, int)), Qt::QueuedConnection); //We DON'T want the progress bar to be hidden at cancel press - since its modal //behavior prevents the user to interfere with a possibly still active vectorization. disconnect(m_progressDialog, SIGNAL(canceled()), m_progressDialog, SLOT(onCancel())); //We first inform the vectorizer of a cancel press; bool ret = connect(m_progressDialog, SIGNAL(canceled()), m_vectorizer, SLOT(cancel())); //which eventually transmits the command to vectorization core, allowing full-time cancels ret = ret && connect(m_progressDialog, SIGNAL(canceled()), m_vectorizer, SIGNAL(transmitCancel())); //Only after the vectorizer has terminated its process - or got cancelled, we are allowed //to proceed here. ret = ret && connect(m_vectorizer, SIGNAL(finished()), this, SLOT(onFinished()), Qt::QueuedConnection); assert(ret); int newIndexColumn = c1 + 1; std::set<TXshLevel *>::iterator it = levels.begin(); for (it; it != levels.end(); it++) { TXshSimpleLevel *sl = dynamic_cast<TXshSimpleLevel *>(*it); if (!sl || !sl->getSimpleLevel() || !isLevelToConvert(sl)) { QString levelName = tr(toString(sl->getName()).c_str()); QString errorMsg = tr("Cannot convert to vector the current selection.") + levelName; error(errorMsg); continue; } std::vector<TFrameId> fids; if (isCellSelection) getSelectedFids(fids, sl, r0, c0, r1, c1); else sl->getFids(fids); assert(fids.size() > 0); close(); // Re-initialize progress Bar m_progressDialog->setMaximum(fids.size() * 100); m_progressDialog->setValue(0); m_currFrame = 0; // Re-initialize vectorizer m_vectorizer->setLevel(sl); m_vectorizer->setFids(fids); // Start vectorizing m_vectorizer->start(); m_progressDialog->show(); // Wait the vectorizer... while (!l_quitLoop) QCoreApplication::processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents); l_quitLoop = false; // Assign output X-sheet cells TXshSimpleLevel *vl = m_vectorizer->getVectorizedLevel(); if (isCellSelection && vl) { TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet(); xsheet->insertColumn(newIndexColumn); int r, c; for (c = c0; c <= c1; c++) { for (r = r0; r <= r1; r++) { TXshCell cell = xsheet->getCell(r, c); TXshSimpleLevel *level = (!cell.isEmpty()) ? cell.getSimpleLevel() : 0; if (level != sl) continue; TFrameId curFid = cell.getFrameId(); std::vector<TFrameId> newFids; vl->getFids(newFids); std::vector<TFrameId>::iterator it1 = newFids.begin(); for (it1; it1 != newFids.end(); it1++) { TFrameId id = *it1; if (id.getNumber() == curFid.getNumber() || // Hanno stesso numero di frame (id.getNumber() == 1 && curFid.getNumber() == -2)) // La vecchia cella non ha numero di frame xsheet->setCell(r, newIndexColumn, TXshCell(vl, id)); } } } newIndexColumn += 1; } else if (vl) { std::vector<TFrameId> gomi; scene->getXsheet()->exposeLevel(0, scene->getXsheet()->getFirstFreeColumnIndex(), vl, gomi); } if (m_vectorizer->isCanceled()) break; } m_progressDialog->close(); delete m_vectorizer; TApp::instance()->getCurrentScene()->notifyCastChange(); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); return true; }
bool addFrame(ToonzScene &scene, int row, bool isLast) { assert(m_status == 3); if (!m_started) start(scene); TDimension cameraRes = scene.getCurrentCamera()->getRes(); TDimensionD cameraSize = scene.getCurrentCamera()->getSize(); TPointD center(0.5 * cameraSize.lx, 0.5 * cameraSize.ly); double sx = (double)m_offlineGlContext.getLx() / (double)cameraRes.lx; double sy = (double)m_offlineGlContext.getLy() / (double)cameraRes.ly; double sc = std::min(sx, sy); // TAffine cameraAff = // scene.getXsheet()->getPlacement(TStageObjectId::CameraId(0), row); TAffine cameraAff = scene.getXsheet()->getCameraAff(row); double dpiScale = (1.0 / Stage::inch) * (double)cameraRes.lx / cameraSize.lx; // TAffine viewAff = TScale(dpiScale*sc) * TTranslation(center)* // cameraAff.inv(); TAffine viewAff = TTranslation(0.5 * cameraRes.lx, 0.5 * cameraRes.ly) * TScale(dpiScale * sc) * cameraAff.inv(); TRect clipRect(m_offlineGlContext.getBounds()); TPixel32 bgColor = scene.getProperties()->getBgColor(); m_offlineGlContext.makeCurrent(); TPixel32 bgClearColor = m_bgColor; if (m_alphaEnabled && m_alphaNeeded) { const double maxValue = 255.0; double alpha = (double)bgClearColor.m / maxValue; bgClearColor.r *= alpha; bgClearColor.g *= alpha; bgClearColor.b *= alpha; } m_offlineGlContext.clear(bgClearColor); Stage::VisitArgs args; args.m_scene = &scene; args.m_xsh = scene.getXsheet(); args.m_row = row; args.m_col = m_columnIndex; args.m_osm = &m_osMask; ImagePainter::VisualSettings vs; Stage::OpenGlPainter painter(viewAff, clipRect, vs, false, true); Stage::visit(painter, args); /* painter, &scene, scene.getXsheet(), row, m_columnIndex, m_osMask, false,0); */ TImageWriterP writer = m_lw->getFrameWriter(m_frameIndex++); if (!writer) return false; #ifdef MACOSX glFinish(); // per fissare il bieco baco su Mac/G3 #endif TRaster32P raster = m_offlineGlContext.getRaster(); #ifdef MACOSX if (m_alphaEnabled && m_alphaNeeded) checkAndCorrectPremultipliedImage(raster); #endif if (Preferences::instance()->isSceneNumberingEnabled()) TRasterImageUtils::addSceneNumbering(TRasterImageP(raster), m_frameIndex - 1, scene.getSceneName(), row + 1); TRasterImageP img(raster); writer->save(img); return true; }