// GetFileNode //------------------------------------------------------------------------------ bool Function::GetFileNode( NodeGraph & nodeGraph, const BFFIterator & iter, Node * & fileNode, const char * name, bool required ) const { // get the string containing the node name AStackString<> fileNodeName; if ( GetString( iter, fileNodeName, name, required ) == false ) { return false; } // handle not-present if ( fileNodeName.IsEmpty() ) { ASSERT( required == false ); // GetString should have managed required string fileNode = nullptr; return true; } // get/create the FileNode Node * n = nodeGraph.FindNode( fileNodeName ); if ( n == nullptr ) { n = nodeGraph.CreateFileNode( fileNodeName ); } else if ( n->IsAFile() == false ) { Error::Error_1103_NotAFile( iter, this, name, n->GetName(), n->GetType() ); return false; } fileNode = n; return true; }
// GetCompilerNode //------------------------------------------------------------------------------ bool FunctionObjectList::GetCompilerNode( NodeGraph & nodeGraph, const BFFIterator & iter, const AString & compiler, CompilerNode * & compilerNode ) const { Node * cn = nodeGraph.FindNode( compiler ); compilerNode = nullptr; if ( cn != nullptr ) { if ( cn->GetType() == Node::ALIAS_NODE ) { AliasNode * an = cn->CastTo< AliasNode >(); cn = an->GetAliasedNodes()[ 0 ].GetNode(); } if ( cn->GetType() != Node::COMPILER_NODE ) { Error::Error_1102_UnexpectedType( iter, this, "Compiler", cn->GetName(), cn->GetType(), Node::COMPILER_NODE ); return false; } compilerNode = cn->CastTo< CompilerNode >(); } else { // create a compiler node - don't allow distribution // (only explicitly defined compiler nodes can be distributed) AStackString<> compilerClean; NodeGraph::CleanPath( compiler, compilerClean ); compilerNode = nodeGraph.CreateCompilerNode( compilerClean ); VERIFY( compilerNode->GetReflectionInfoV()->SetProperty( compilerNode, "AllowDistribution", false ) ); } return true; }
// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionCopyDir::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const { // Get input paths Array< AString > inputPaths; if ( !GetFolderPaths( funcStartIter, inputPaths, ".SourcePaths", true ) ) { return false; // GetFolderPaths will have emitted an error } // get the optional params Array< AString > patterns; bool recurse = true; Array< AString > excludePaths; if ( !GetStrings( funcStartIter, patterns, ".SourcePathsPattern" ) || !GetBool( funcStartIter, recurse, ".SourcePathsRecurse", true ) || // recursive by default !GetStrings( funcStartIter, excludePaths, ".SourceExcludePaths" ) ) { return false; // Get* will have emitted error } // convert input paths to DirectoryListNodes Dependencies staticDeps( inputPaths.GetSize() ); if ( !GetDirectoryListNodeList( nodeGraph, funcStartIter, inputPaths, excludePaths, Array< AString >(), Array< AString >(), recurse, patterns.IsEmpty() ? nullptr : &patterns, ".SourcePaths", staticDeps ) ) { return false; // GetDirectoryListNodeList will have emitted an error } // Get output path AStackString<> destPath; if ( !GetString( funcStartIter, destPath, ".Dest", true ) ) { return false; } NodeGraph::CleanPath( destPath ); // Pre-build dependencies Dependencies preBuildDeps; if ( !GetNodeList( nodeGraph, funcStartIter, ".PreBuildDependencies", preBuildDeps, false ) ) { return false; // GetNodeList will have emitted an error } // sanity check we defined something useful if ( staticDeps.IsEmpty() ) { Error::Error_1006_NothingToBuild( funcStartIter, this ); return false; } // check node doesn't already exist if ( nodeGraph.FindNode( m_AliasForFunction ) ) { Error::Error_1100_AlreadyDefined( funcStartIter, this, m_AliasForFunction ); return false; } // create our node nodeGraph.CreateCopyDirNode( m_AliasForFunction, staticDeps, destPath, preBuildDeps ); return true; }
// DependOnNode //------------------------------------------------------------------------------ /*static*/ bool LinkerNode::DependOnNode( NodeGraph & nodeGraph, const BFFIterator & iter, const Function * function, const AString & nodeName, Dependencies & nodes ) { // silently ignore empty nodes if ( nodeName.IsEmpty() ) { return true; } Node * node = nodeGraph.FindNode( nodeName ); // does it exist? if ( node != nullptr ) { // process it return DependOnNode( iter, function, node, nodes ); } // node not found - create a new FileNode, assuming we are // linking against an externally built library node = nodeGraph.CreateFileNode( nodeName ); nodes.Append( Dependency( node ) ); return true; }
NodePtr Gui::createReader() { NodePtr ret; std::vector<std::string> filters; appPTR->getSupportedReaderFileFormats(&filters); std::string pattern = popOpenFileDialog( true, filters, _imp->_lastLoadSequenceOpenedDir.toStdString(), true ); if ( !pattern.empty() ) { NodeGraph* graph = 0; if (_imp->_lastFocusedGraph) { graph = _imp->_lastFocusedGraph; } else { graph = _imp->_nodeGraphArea; } NodeCollectionPtr group = graph->getGroup(); assert(group); CreateNodeArgsPtr args(CreateNodeArgs::create(PLUGINID_NATRON_READ, group)); ret = getApp()->createReader(pattern, args); } return ret; } // Gui::createReader
void Gui::createGroupGui(const NodePtr & group, CreateNodeReason reason) { boost::shared_ptr<NodeGroup> isGrp = boost::dynamic_pointer_cast<NodeGroup>( group->getEffectInstance()->shared_from_this() ); assert(isGrp); boost::shared_ptr<NodeCollection> collection = boost::dynamic_pointer_cast<NodeCollection>(isGrp); assert(collection); TabWidget* where = 0; if (_imp->_lastFocusedGraph) { TabWidget* isTab = dynamic_cast<TabWidget*>( _imp->_lastFocusedGraph->parentWidget() ); if (isTab) { where = isTab; } else { QMutexLocker k(&_imp->_panesMutex); assert( !_imp->_panes.empty() ); where = _imp->_panes.front(); } } QGraphicsScene* scene = new QGraphicsScene(this); scene->setItemIndexMethod(QGraphicsScene::NoIndex); NodeGraph* nodeGraph = new NodeGraph(this, collection, scene, this); nodeGraph->setObjectName( QString::fromUtf8(group->getLabel().c_str()) ); _imp->_groups.push_back(nodeGraph); if ( where && reason == eCreateNodeReasonUserCreate && !getApp()->isCreatingPythonGroup() ) { where->appendTab(nodeGraph, nodeGraph); QTimer::singleShot( 25, nodeGraph, SLOT(centerOnAllNodes()) ); } else { nodeGraph->setVisible(false); } }
// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionXCodeProject::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const { AStackString<> name; if ( GetNameForNode( nodeGraph, funcStartIter, XCodeProjectNode::GetReflectionInfoS(), name ) == false ) { return false; } if ( nodeGraph.FindNode( name ) ) { Error::Error_1100_AlreadyDefined( funcStartIter, this, name ); return false; } auto * xcodeProjNode = nodeGraph.CreateXCodeProjectNode( name ); if ( !PopulateProperties( nodeGraph, funcStartIter, xcodeProjNode ) ) { return false; } if ( !xcodeProjNode->Initialize( nodeGraph, funcStartIter, this ) ) { return false; } // handle alias creation return ProcessAlias( nodeGraph, funcStartIter, xcodeProjNode ); }
ViewerTab::~ViewerTab() { Gui* gui = getGui(); if (gui) { NodeGraph* graph = 0; ViewerNodePtr internalNode = getInternalNode(); ViewerInstancePtr viewerNode = internalNode ? internalNode->getInternalViewerNode() : ViewerInstancePtr(); if (viewerNode) { NodeCollectionPtr collection = viewerNode->getNode()->getGroup(); if (collection) { NodeGroupPtr isGrp = toNodeGroup(collection); if (isGrp) { NodeGraphI* graph_i = isGrp->getNodeGraph(); if (graph_i) { graph = dynamic_cast<NodeGraph*>(graph_i); assert(graph); } } else { graph = gui->getNodeGraph(); } } internalNode->invalidateUiContext(); } else { graph = gui->getNodeGraph(); } assert(graph); GuiAppInstancePtr app = gui->getApp(); if ( app && !app->isClosing() && graph && (graph->getLastSelectedViewer() == this) ) { graph->setLastSelectedViewer(0); } } _imp->nodesContext.clear(); }
// GetDirectoryNodeList //------------------------------------------------------------------------------ bool Function::GetDirectoryListNodeList( NodeGraph & nodeGraph, const BFFIterator & iter, const Array< AString > & paths, const Array< AString > & excludePaths, const Array< AString > & filesToExclude, bool recurse, const Array< AString > * patterns, const char * inputVarName, Dependencies & nodes ) const { // Handle special case of excluded files beginning with ../ // Since they can be used seinsibly by matching just the end // of a path, assume they are relative to the working dir. // TODO:C Move this during bff parsing when everything is using reflection Array< AString > filesToExcludeCleaned( filesToExclude.GetSize(), true ); for ( const AString& file : filesToExclude ) { if ( file.BeginsWith( ".." ) ) { AStackString<> fullPath; NodeGraph::CleanPath( file, fullPath ); filesToExcludeCleaned.Append( fullPath ); } else { filesToExcludeCleaned.Append( file ); } } const AString * const end = paths.End(); for ( const AString * it = paths.Begin(); it != end; ++it ) { const AString & path = *it; // get node for the dir we depend on AStackString<> name; DirectoryListNode::FormatName( path, patterns, recurse, excludePaths, filesToExcludeCleaned, name ); Node * node = nodeGraph.FindNode( name ); if ( node == nullptr ) { node = nodeGraph.CreateDirectoryListNode( name, path, patterns, recurse, excludePaths, filesToExcludeCleaned ); } else if ( node->GetType() != Node::DIRECTORY_LIST_NODE ) { Error::Error_1102_UnexpectedType( iter, this, inputVarName, node->GetName(), node->GetType(), Node::DIRECTORY_LIST_NODE ); return false; } nodes.Append( Dependency( node ) ); } return true; }
void Gui::createNewViewer() { NodeGraph* graph = _imp->_lastFocusedGraph ? _imp->_lastFocusedGraph : _imp->_nodeGraphArea; assert(graph); if (!graph) { throw std::logic_error(""); } CreateNodeArgsPtr args(CreateNodeArgs::create(PLUGINID_NATRON_VIEWER_GROUP, graph->getGroup() )); args->setProperty<bool>(kCreateNodeArgsPropSubGraphOpened, false); ignore_result( getApp()->createNode(args) ); }
void Gui::createGroupGui(const NodePtr & group, const CreateNodeArgs& args) { NodeGroupPtr isGrp = toNodeGroup( group->getEffectInstance()->shared_from_this() ); assert(isGrp); NodeCollectionPtr collection = boost::dynamic_pointer_cast<NodeCollection>(isGrp); assert(collection); TabWidget* where = 0; if (_imp->_lastFocusedGraph) { TabWidget* isTab = dynamic_cast<TabWidget*>( _imp->_lastFocusedGraph->parentWidget() ); if (isTab) { where = isTab; } else { std::list<TabWidgetI*> panes = getApp()->getTabWidgetsSerialization(); assert( !panes.empty() ); where = dynamic_cast<TabWidget*>(panes.front()); } } QGraphicsScene* scene = new QGraphicsScene(this); scene->setItemIndexMethod(QGraphicsScene::NoIndex); std::string newName = isGrp->getNode()->getFullyQualifiedName(); for (std::size_t i = 0; i < newName.size(); ++i) { if (newName[i] == '.') { newName[i] = '_'; } } newName += "_NodeGraph"; std::string label = tr(" Node Graph").toStdString(); NodeGraph::makeFullyQualifiedLabel(group, &label); NodeGraph* nodeGraph = new NodeGraph(this, collection, newName, scene, this); nodeGraph->setLabel(label); nodeGraph->setObjectName( QString::fromUtf8( group->getLabel().c_str() ) ); _imp->_groups.push_back(nodeGraph); SERIALIZATION_NAMESPACE::NodeSerializationPtr serialization = args.getPropertyUnsafe<SERIALIZATION_NAMESPACE::NodeSerializationPtr>(kCreateNodeArgsPropNodeSerialization); bool showSubGraph = args.getPropertyUnsafe<bool>(kCreateNodeArgsPropSubGraphOpened); if ( showSubGraph && where && !serialization ) { where->appendTab(nodeGraph, nodeGraph); QTimer::singleShot( 25, nodeGraph, SLOT(centerOnAllNodes()) ); } else { nodeGraph->setVisible(false); } }
boost::shared_ptr<NodeCollection> Gui::getLastSelectedNodeCollection() const { NodeGraph* graph = 0; if (_imp->_lastFocusedGraph) { graph = _imp->_lastFocusedGraph; } else { graph = _imp->_nodeGraphArea; } boost::shared_ptr<NodeCollection> group = graph->getGroup(); assert(group); return group; }
NodeCollectionPtr Gui::getLastSelectedNodeCollection() const { NodeGraph* graph = 0; if (_imp->_lastFocusedGraph) { graph = _imp->_lastFocusedGraph; } else { graph = _imp->_nodeGraphArea; } NodeCollectionPtr group = graph->getGroup(); assert(group); return group; }
// GetOtherLibrary //------------------------------------------------------------------------------ bool LinkerNode::GetOtherLibrary( NodeGraph & nodeGraph, const BFFIterator & iter, const Function * function, Dependencies & libs, const AString & path, const AString & lib, bool & found ) const { found = false; AStackString<> potentialNodeName( path ); if ( !potentialNodeName.IsEmpty() ) { PathUtils::EnsureTrailingSlash( potentialNodeName ); } potentialNodeName += lib; AStackString<> potentialNodeNameClean; NodeGraph::CleanPath( potentialNodeName, potentialNodeNameClean ); // see if a node already exists Node * node = nodeGraph.FindNode( potentialNodeNameClean ); if ( node ) { // aliases not supported - must point to something that provides a file if ( node->IsAFile() == false ) { Error::Error_1103_NotAFile( iter, function, ".LinkerOptions", potentialNodeNameClean, node->GetType() ); return false; } // found existing node libs.Append( Dependency( node ) ); found = true; return true; // no error } // see if the file exists on disk at this location if ( FileIO::FileExists( potentialNodeNameClean.Get() ) ) { node = nodeGraph.CreateFileNode( potentialNodeNameClean ); libs.Append( Dependency( node ) ); found = true; FLOG_INFO( "Additional library '%s' assumed to be '%s'\n", lib.Get(), potentialNodeNameClean.Get() ); return true; // no error } return true; // no error }
// GetObjectListNodes //------------------------------------------------------------------------------ bool Function::GetObjectListNodes( NodeGraph & nodeGraph, const BFFIterator & iter, const Array< AString > & objectLists, const char * inputVarName, Dependencies & nodes ) const { const AString * const end = objectLists.End(); for ( const AString * it = objectLists.Begin(); it != end; ++it ) { const AString & objectList = *it; // get node for the dir we depend on Node * node = nodeGraph.FindNode( objectList ); if ( node == nullptr ) { Error::Error_1104_TargetNotDefined( iter, this, inputVarName, objectList ); return false; } else if ( node->GetType() != Node::OBJECT_LIST_NODE ) { Error::Error_1102_UnexpectedType( iter, this, inputVarName, node->GetName(), node->GetType(), Node::OBJECT_LIST_NODE ); return false; } nodes.Append( Dependency( node ) ); } return true; }
// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionAlias::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const { if ( nodeGraph.FindNode( m_AliasForFunction ) ) { Error::Error_1100_AlreadyDefined( funcStartIter, this, m_AliasForFunction ); return false; } AliasNode * aliasNode = nodeGraph.CreateAliasNode( m_AliasForFunction ); if ( !PopulateProperties( nodeGraph, funcStartIter, aliasNode ) ) { return false; } return aliasNode->Initialize( nodeGraph, funcStartIter, this ); }
// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionSettings::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const { AStackString<> name( "$$Settings$$" ); if ( nodeGraph.FindNode( name ) ) { Error::Error_1100_AlreadyDefined( funcStartIter, this, name ); return false; } SettingsNode * settingsNode = nodeGraph.CreateSettingsNode( name ); if ( !PopulateProperties( nodeGraph, funcStartIter, settingsNode ) ) { return false; } return settingsNode->Initialize( nodeGraph, funcStartIter, this ); }
void GuiAppInstance::onGroupCreationFinished(const NodePtr& node, CreateNodeReason reason) { if (reason == eCreateNodeReasonUserCreate) { NodeGraph* graph = 0; boost::shared_ptr<NodeCollection> collection = node->getGroup(); assert(collection); NodeGroup* isGrp = dynamic_cast<NodeGroup*>( collection.get() ); if (isGrp) { NodeGraphI* graph_i = isGrp->getNodeGraph(); assert(graph_i); graph = dynamic_cast<NodeGraph*>(graph_i); } else { graph = _imp->_gui->getNodeGraph(); } assert(graph); if (!graph) { throw std::logic_error(""); } NodesGuiList selectedNodes = graph->getSelectedNodes(); NodeGuiPtr selectedNode; if ( !selectedNodes.empty() ) { selectedNode = selectedNodes.front(); if ( dynamic_cast<BackdropGui*>( selectedNode.get() ) ) { selectedNode.reset(); } } boost::shared_ptr<NodeGuiI> node_gui_i = node->getNodeGui(); assert(node_gui_i); NodeGuiPtr nodeGui = boost::dynamic_pointer_cast<NodeGui>(node_gui_i); graph->moveNodesForIdealPosition(nodeGui, selectedNode, true); } AppInstance::onGroupCreationFinished(node, reason); /*std::list<ViewerInstance* > viewers; node->hasViewersConnected(&viewers); for (std::list<ViewerInstance* >::iterator it2 = viewers.begin(); it2 != viewers.end(); ++it2) { (*it2)->renderCurrentFrame(false); }*/ }
void GuiAppInstance::onGroupCreationFinished(const NodePtr& node, const NodeSerializationPtr& serialization, bool autoConnect) { NodeGuiIPtr node_gui_i = node->getNodeGui(); if (autoConnect && !serialization && node_gui_i) { NodeGraph* graph = 0; NodeCollectionPtr collection = node->getGroup(); assert(collection); NodeGroupPtr isGrp = toNodeGroup(collection); if (isGrp) { NodeGraphI* graph_i = isGrp->getNodeGraph(); assert(graph_i); graph = dynamic_cast<NodeGraph*>(graph_i); } else { graph = _imp->_gui->getNodeGraph(); } assert(graph); if (!graph) { throw std::logic_error(""); } NodesGuiList selectedNodes = graph->getSelectedNodes(); NodeGuiPtr selectedNode; if ( !selectedNodes.empty() ) { selectedNode = selectedNodes.front(); if (toBackdropGui(selectedNode) ) { selectedNode.reset(); } } NodeGuiPtr nodeGui = boost::dynamic_pointer_cast<NodeGui>(node_gui_i); graph->moveNodesForIdealPosition(nodeGui, selectedNode, true); } AppInstance::onGroupCreationFinished(node, serialization, autoConnect); /*std::list<ViewerInstancePtr> viewers; node->hasViewersConnected(&viewers); for (std::list<ViewerInstancePtr>::iterator it2 = viewers.begin(); it2 != viewers.end(); ++it2) { (*it2)->renderCurrentFrame(false); }*/ }
// GetFileNode //------------------------------------------------------------------------------ bool Function::GetFileNode( NodeGraph & nodeGraph, const BFFIterator & iter, const AString & file, const char * inputVarName, Dependencies & nodes ) const { // get node for the dir we depend on Node * node = nodeGraph.FindNode( file ); if ( node == nullptr ) { node = nodeGraph.CreateFileNode( file ); } else if ( node->IsAFile() == false ) { Error::Error_1005_UnsupportedNodeType( iter, this, inputVarName, node->GetName(), node->GetType() ); return false; } nodes.Append( Dependency( node ) ); return true; }
// GetNameForNode //------------------------------------------------------------------------------ bool Function::GetNameForNode( NodeGraph & nodeGraph, const BFFIterator & iter, const ReflectionInfo * ri, AString & name ) const { // get object MetaData const Meta_Name * nameMD = ri->HasMetaData< Meta_Name >(); ASSERT( nameMD ); // should not call this on types without this MetaData // Format "Name" as ".Name" - TODO:C Would be good to eliminate this string copy AStackString<> propertyName( "." ); propertyName += nameMD->GetName(); // Find the value for this property from the BFF const BFFVariable * variable = BFFStackFrame::GetVar( propertyName ); if ( variable == nullptr ) { Error::Error_1101_MissingProperty( iter, this, propertyName ); return false; } if ( variable->IsString() ) { Array< AString > strings; if ( !PopulateStringHelper( nodeGraph, iter, nullptr, ri->HasMetaData< Meta_File >(), variable, strings ) ) { return false; // PopulateStringHelper will have emitted an error } // Handle empty strings if ( strings.IsEmpty() || strings[0].IsEmpty() ) { Error::Error_1004_EmptyStringPropertyNotAllowed( iter, this, variable->GetName().Get() ); return false; } if ( strings.GetSize() != 1 ) { Error::Error_1050_PropertyMustBeOfType( iter, this, variable->GetName().Get(), BFFVariable::VAR_ARRAY_OF_STRINGS, BFFVariable::VAR_STRING ); return false; } // Check that name isn't already used if ( nodeGraph.FindNode( strings[0] ) ) { Error::Error_1100_AlreadyDefined( iter, this, strings[0] ); return false; } name = strings[0]; return true; } Error::Error_1050_PropertyMustBeOfType( iter, this, variable->GetName().Get(), variable->GetType(), BFFVariable::VAR_STRING ); return false; }
NodePtr Gui::createWriter() { NodePtr ret; std::vector<std::string> filters; appPTR->getSupportedWriterFileFormats(&filters); std::string file; bool useDialogForWriters = appPTR->getCurrentSettings()->isFileDialogEnabledForNewWriters(); if (useDialogForWriters) { file = popSaveFileDialog( true, filters, _imp->_lastSaveSequenceOpenedDir.toStdString(), true ); if ( file.empty() ) { return NodePtr(); } } if ( !file.empty() ) { std::string patternCpy = file; std::string path = SequenceParsing::removePath(patternCpy); _imp->_lastSaveSequenceOpenedDir = QString::fromUtf8( path.c_str() ); } NodeGraph* graph = 0; if (_imp->_lastFocusedGraph) { graph = _imp->_lastFocusedGraph; } else { graph = _imp->_nodeGraphArea; } NodeCollectionPtr group = graph->getGroup(); assert(group); CreateNodeArgsPtr args(CreateNodeArgs::create(PLUGINID_NATRON_WRITE, group)); ret = getApp()->createWriter(file, args); return ret; }
// ProcessAlias //------------------------------------------------------------------------------ bool Function::ProcessAlias( NodeGraph & nodeGraph, const BFFIterator & iter, Dependencies & nodesToAlias ) const { if ( m_AliasForFunction.IsEmpty() ) { return true; // no alias required } // check for duplicates if ( nodeGraph.FindNode( m_AliasForFunction ) ) { Error::Error_1100_AlreadyDefined( iter, this, m_AliasForFunction ); return false; } // create an alias against the node AliasNode * an = nodeGraph.CreateAliasNode( m_AliasForFunction ); an->m_StaticDependencies = nodesToAlias; // TODO: make this use m_Targets & Initialize() // clear the string so it can't be used again m_AliasForFunction.Clear(); return true; }
// PopulateStringHelper //------------------------------------------------------------------------------ bool Function::PopulateStringHelper( NodeGraph & nodeGraph, const BFFIterator & iter, const Meta_Path * pathMD, const Meta_File * fileMD, const BFFVariable * variable, const AString & string, Array< AString > & outStrings ) const { // Full paths to files can support aliases if ( fileMD && ( !fileMD->IsRelative() ) ) { // Is it an Alias? Node * node = nodeGraph.FindNode( string ); if ( node && ( node->GetType() == Node::ALIAS_NODE ) ) { AliasNode * aliasNode = node->CastTo< AliasNode >(); for ( const auto& aliasedNode : aliasNode->GetAliasedNodes() ) { if ( !PopulateStringHelper( nodeGraph, iter, pathMD, fileMD, variable, aliasedNode.GetNode()->GetName(), outStrings ) ) { return false; // PopulateStringHelper will have emitted an error } } return true; } // Not an alias - fall through to normal handling } AStackString<> stringToFix( string ); if ( !PopulatePathAndFileHelper( iter, pathMD, fileMD, variable->GetName(), stringToFix ) ) { return false; // PopulatePathAndFileHelper will have emitted an error } outStrings.Append( stringToFix ); return true; }
// Load //------------------------------------------------------------------------------ bool Dependencies::Load( NodeGraph & nodeGraph, IOStream & stream ) { uint32_t numDeps; if ( stream.Read( numDeps ) == false ) { return false; } if ( GetCapacity() < GetSize() + numDeps ) { SetCapacity( GetSize() + numDeps ); } for ( uint32_t i=0; i<numDeps; ++i ) { // Read node index uint32_t index( INVALID_NODE_INDEX ); if ( stream.Read( index ) == false ) { return false; } // Convert to Node * Node * node = nodeGraph.GetNodeByIndex( index ); ASSERT( node ); // Read weak flag bool isWeak( false ); if ( stream.Read( isWeak ) == false ) { return false; } // Recombine dependency info Append( Dependency( node, isWeak ) ); } return true; }
// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionLibrary::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const { // make sure all required variables are defined const BFFVariable * outputLib; const BFFVariable * compiler; const BFFVariable * compilerOptions; AStackString<> compilerOptionsDeoptimized; AStackString<> compilerOutputPath; AStackString<> compilerOutputPrefix; const BFFVariable * compilerOutputExtension; const BFFVariable * librarian; const BFFVariable * librarianOptions; if ( !GetString( funcStartIter, outputLib, ".LibrarianOutput", true ) || !GetString( funcStartIter, compiler, ".Compiler", true ) || !GetString( funcStartIter, compilerOptions, ".CompilerOptions", true ) || !GetString( funcStartIter, compilerOptionsDeoptimized, ".CompilerOptionsDeoptimized", false ) || !GetString( funcStartIter, compilerOutputPath, ".CompilerOutputPath", true ) || !GetString( funcStartIter, compilerOutputPrefix, ".CompilerOutputPrefix", false ) || !GetString( funcStartIter, compilerOutputExtension, ".CompilerOutputExtension", false ) || !GetString( funcStartIter, librarian, ".Librarian", true ) || !GetString( funcStartIter, librarianOptions, ".LibrarianOptions", true ) ) { return false; } PathUtils::FixupFolderPath( compilerOutputPath ); // find or create the compiler node CompilerNode * compilerNode = nullptr; if ( !FunctionObjectList::GetCompilerNode( nodeGraph, funcStartIter, compiler->GetString(), compilerNode ) ) { return false; // GetCompilerNode will have emitted error } // Compiler Force Using Dependencies compilerForceUsing; if ( !GetNodeList( nodeGraph, funcStartIter, ".CompilerForceUsing", compilerForceUsing, false ) ) { return false; // GetNodeList will have emitted an error } // de-optimization setting bool deoptimizeWritableFiles = false; bool deoptimizeWritableFilesWithToken = false; if ( !GetBool( funcStartIter, deoptimizeWritableFiles, ".DeoptimizeWritableFiles", false, false ) ) { return false; // GetBool will have emitted error } if ( !GetBool( funcStartIter, deoptimizeWritableFilesWithToken, ".DeoptimizeWritableFilesWithToken", false, false ) ) { return false; // GetBool will have emitted error } if ( ( deoptimizeWritableFiles || deoptimizeWritableFilesWithToken ) && compilerOptionsDeoptimized.IsEmpty() ) { Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".CompilerOptionsDeoptimized" ) ); return false; } // cache & distribution control bool allowDistribution( true ); bool allowCaching( true ); if ( !GetBool( funcStartIter, allowDistribution, ".AllowDistribution", true ) || !GetBool( funcStartIter, allowCaching, ".AllowCaching", true ) ) { return false; // GetBool will have emitted error } // Precompiled Header support ObjectNode * precompiledHeaderNode = nullptr; AStackString<> compilerOutputExtensionStr( compilerOutputExtension ? compilerOutputExtension->GetString().Get() : ".obj" ); if ( !GetPrecompiledHeaderNode( nodeGraph, funcStartIter, compilerNode, compilerOptions, compilerForceUsing, precompiledHeaderNode, deoptimizeWritableFiles, deoptimizeWritableFilesWithToken, allowDistribution, allowCaching, compilerOutputExtensionStr ) ) { return false; // GetPrecompiledHeaderNode will have emitted error } // Sanity check compile flags const bool usingPCH = ( precompiledHeaderNode != nullptr ); uint32_t objFlags = ObjectNode::DetermineFlags( compilerNode, compilerOptions->GetString(), false, usingPCH ); if ( ( objFlags & ObjectNode::FLAG_MSVC ) && ( objFlags & ObjectNode::FLAG_CREATING_PCH ) ) { // must not specify use of precompiled header (must use the PCH specific options) Error::Error_1303_PCHCreateOptionOnlyAllowedOnPCH( funcStartIter, this, "Yc", "CompilerOptions" ); return false; } // Check input/output for Compiler { bool hasInputToken = false; bool hasOutputToken = false; bool hasCompileToken = false; const AString & args = compilerOptions->GetString(); Array< AString > tokens; args.Tokenize( tokens ); for ( const AString & token : tokens ) { if ( token.Find( "%1" ) ) { hasInputToken = true; } else if ( token.Find( "%2" ) ) { hasOutputToken = true; } else { if ( objFlags & ObjectNode::FLAG_MSVC ) { if ( ( token == "/c" ) || ( token == "-c" ) ) { hasCompileToken = true; } } else { if ( token == "-c" ) { hasCompileToken = true; } } } } if ( hasInputToken == false ) { Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "%1" ); return false; } if ( hasOutputToken == false ) { Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "%2" ); return false; } // check /c or -c if ( objFlags & ObjectNode::FLAG_MSVC ) { if ( hasCompileToken == false ) { Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "/c or -c" ); return false; } } else if ( objFlags & ( ObjectNode::FLAG_SNC | ObjectNode::FLAG_GCC | ObjectNode::FLAG_CLANG ) ) { if ( hasCompileToken == false ) { Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".CompilerOptions", "-c" ); return false; } } } // Check input/output for Librarian { const AString & args = librarianOptions->GetString(); bool hasInputToken = ( args.Find( "%1" ) || args.Find( "\"%1\"" ) ); if ( hasInputToken == false ) { Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".LibrarianOptions", "%1" ); return false; } bool hasOutputToken = ( args.Find( "%2" ) || args.Find( "\"%2\"" ) ); if ( hasOutputToken == false ) { Error::Error_1106_MissingRequiredToken( funcStartIter, this, ".LibrarianOptions", "%2" ); return false; } } // Get the (optional) Preprocessor & PreprocessorOptions const BFFVariable * preprocessor = nullptr; const BFFVariable * preprocessorOptions = nullptr; CompilerNode * preprocessorNode = nullptr; if ( !GetString( funcStartIter, preprocessor, ".Preprocessor", false ) ) { return false; // GetString will have emitted an error } if ( preprocessor ) { // get the preprocessor executable if ( !FunctionObjectList::GetCompilerNode( nodeGraph, funcStartIter, preprocessor->GetString(), preprocessorNode ) ) { return false; // GetCompilerNode will have emitted an error } // get the command line args for the preprocessor if ( !GetString( funcStartIter, preprocessorOptions, ".PreprocessorOptions", true ) ) // required { return false; // GetString will have emitted an error } } // Pre-build dependencies Dependencies preBuildDependencies; if ( !GetNodeList( nodeGraph, funcStartIter, ".PreBuildDependencies", preBuildDependencies, false ) ) { return false; // GetNodeList will have emitted an error } Dependencies staticDeps( 32, true ); if ( !GetInputs( nodeGraph, funcStartIter, staticDeps ) ) { return false; // GetStaticDeps will gave emitted error } // are the additional inputs to merge into the libaray? Dependencies additionalInputs; if ( !GetNodeList( nodeGraph, funcStartIter, ".LibrarianAdditionalInputs", additionalInputs, false ) ) { return false;// helper will emit error } if ( staticDeps.IsEmpty() && additionalInputs.IsEmpty() ) { Error::Error_1006_NothingToBuild( funcStartIter, this ); return false; } uint32_t flags = LibraryNode::DetermineFlags( librarian->GetString() ); // Create library node which depends on the single file or list if ( nodeGraph.FindNode( outputLib->GetString() ) ) { Error::Error_1100_AlreadyDefined( funcStartIter, this, outputLib->GetString() ); return false; } AStackString<> baseDirectory; if ( !GetBaseDirectory( funcStartIter, baseDirectory ) ) { return false; // GetBaseDirectory will have emitted error } AStackString<> extraPDBPath, extraASMPath; GetExtraOutputPaths( compilerOptions->GetString(), extraPDBPath, extraASMPath ); LibraryNode * libNode = nodeGraph.CreateLibraryNode( outputLib->GetString(), staticDeps, compilerNode, compilerOptions->GetString(), compilerOptionsDeoptimized, compilerOutputPath, librarian->GetString(), librarianOptions->GetString(), flags, precompiledHeaderNode, compilerForceUsing, preBuildDependencies, additionalInputs, deoptimizeWritableFiles, deoptimizeWritableFilesWithToken, allowDistribution, allowCaching, preprocessorNode, preprocessorOptions ? preprocessorOptions->GetString() : AString::GetEmpty(), baseDirectory ); if ( compilerOutputExtension ) { libNode->m_ObjExtensionOverride = compilerOutputExtension->GetString(); } libNode->m_CompilerOutputPrefix = compilerOutputPrefix; libNode->m_ExtraPDBPath = extraPDBPath; libNode->m_ExtraASMPath = extraASMPath; return ProcessAlias( nodeGraph, funcStartIter, libNode ); }
void Gui::renderSelectedNode() { NodeGraph* graph = getLastSelectedGraph(); if (!graph) { return; } NodesGuiList selectedNodes = graph->getSelectedNodes(); if ( selectedNodes.empty() ) { Dialogs::warningDialog( tr("Render").toStdString(), tr("You must select a node to render first!").toStdString() ); return; } std::list<AppInstance::RenderWork> workList; bool useStats = getApp()->isRenderStatsActionChecked(); for (NodesGuiList::const_iterator it = selectedNodes.begin(); it != selectedNodes.end(); ++it) { NodePtr internalNode = (*it)->getNode(); if (!internalNode) { continue; } EffectInstPtr effect = internalNode->getEffectInstance(); if (!effect) { continue; } if ( effect->isWriter() ) { if ( !effect->areKnobsFrozen() ) { //if ((*it)->getNode()->is) ///if the node is a writer, just use it to render! AppInstance::RenderWork w; w.writer = dynamic_cast<OutputEffectInstance*>( effect.get() ); assert(w.writer); w.firstFrame = INT_MIN; w.lastFrame = INT_MAX; w.frameStep = INT_MIN; w.useRenderStats = useStats; workList.push_back(w); } } else { if (selectedNodes.size() == 1) { ///create a node and connect it to the node and use it to render #ifndef NATRON_ENABLE_IO_META_NODES NodePtr writer = createWriter(); #else NodeGraph* graph = selectedNodes.front()->getDagGui(); NodePtr writer = getApp()->createWriter( "", eCreateNodeReasonInternal, graph->getGroup() ); #endif if (writer) { AppInstance::RenderWork w; w.writer = dynamic_cast<OutputEffectInstance*>( writer->getEffectInstance().get() ); assert(w.writer); w.firstFrame = INT_MIN; w.lastFrame = INT_MAX; w.frameStep = INT_MIN; w.useRenderStats = useStats; workList.push_back(w); } } } } _imp->_appInstance->startWritersRendering(false, workList); } // Gui::renderSelectedNode
void GuiAppInstance::createNodeGui(const NodePtr &node, const NodePtr& parentMultiInstance, const CreateNodeArgs& args) { boost::shared_ptr<NodeCollection> group = node->getGroup(); NodeGraph* graph; if (group) { NodeGraphI* graph_i = group->getNodeGraph(); assert(graph_i); graph = dynamic_cast<NodeGraph*>(graph_i); assert(graph); } else { graph = _imp->_gui->getNodeGraph(); } if (!graph) { throw std::logic_error(""); } NodesGuiList selectedNodes = graph->getSelectedNodes(); NodeGuiPtr nodegui = _imp->_gui->createNodeGUI(node, args); assert(nodegui); if (parentMultiInstance && nodegui) { nodegui->hideGui(); boost::shared_ptr<NodeGuiI> parentNodeGui_i = parentMultiInstance->getNodeGui(); assert(parentNodeGui_i); nodegui->setParentMultiInstance( boost::dynamic_pointer_cast<NodeGui>(parentNodeGui_i) ); } ///It needs to be here because we rely on the _nodeMapping member bool isViewer = node->isEffectViewer() != 0; if (isViewer) { _imp->_gui->createViewerGui(node); } ///must be done after the viewer gui has been created if ( node->isRotoPaintingNode() ) { _imp->_gui->createNewRotoInterface( nodegui.get() ); } if ( ( node->isTrackerNodePlugin() || node->getEffectInstance()->isBuiltinTrackerNode() ) && !parentMultiInstance ) { _imp->_gui->createNewTrackerInterface( nodegui.get() ); } NodeGroup* isGroup = node->isEffectGroup(); if ( isGroup && isGroup->isSubGraphUserVisible() ) { _imp->_gui->createGroupGui(node, args.reason); } ///Don't initialize inputs if it is a multi-instance child since it is not part of the graph if (!parentMultiInstance) { nodegui->initializeInputs(); } if ( (args.reason == eCreateNodeReasonUserCreate) && !isViewer ) { ///we make sure we can have a clean preview. node->computePreviewImage( getTimeLine()->currentFrame() ); triggerAutoSave(); } ///only move main instances if ( node->getParentMultiInstanceName().empty() ) { bool autoConnect = args.reason == eCreateNodeReasonUserCreate; if ( selectedNodes.empty() ) { autoConnect = false; } if ( (args.xPosHint != INT_MIN) && (args.yPosHint != INT_MIN) && (!autoConnect) ) { QPointF pos = nodegui->mapToParent( nodegui->mapFromScene( QPointF(args.xPosHint, args.yPosHint) ) ); nodegui->refreshPosition( pos.x(), pos.y(), true ); } else { BackdropGui* isBd = dynamic_cast<BackdropGui*>( nodegui.get() ); if (!isBd) { NodeGuiPtr selectedNode; if ( (args.reason == eCreateNodeReasonUserCreate) && (selectedNodes.size() == 1) ) { selectedNode = selectedNodes.front(); BackdropGui* isBackdropGui = dynamic_cast<BackdropGui*>( selectedNode.get() ); if (isBackdropGui) { selectedNode.reset(); } } nodegui->getDagGui()->moveNodesForIdealPosition(nodegui, selectedNode, autoConnect); } } } } // createNodeGui
// GatherDynamicDependencies //------------------------------------------------------------------------------ /*virtual*/ bool ObjectListNode::GatherDynamicDependencies( NodeGraph & nodeGraph, bool forceClean ) { (void)forceClean; // dynamic deps are always re-added here, so this is meaningless // clear dynamic deps from previous passes m_DynamicDependencies.Clear(); #if defined( __WINDOWS__ ) // On Windows, with MSVC we compile a cpp file to generate the PCH // Filter here to ensure that doesn't get compiled twice Node * pchCPP = nullptr; if ( m_PrecompiledHeader && m_PrecompiledHeader->IsMSVC() ) { pchCPP = m_PrecompiledHeader->GetPrecompiledHeaderCPPFile(); } #endif // if we depend on any directory lists, we need to use them to get our files for ( Dependencies::Iter i = m_StaticDependencies.Begin(); i != m_StaticDependencies.End(); i++ ) { // is this a dir list? if ( i->GetNode()->GetType() == Node::DIRECTORY_LIST_NODE ) { // get the list of files DirectoryListNode * dln = i->GetNode()->CastTo< DirectoryListNode >(); const Array< FileIO::FileInfo > & files = dln->GetFiles(); m_DynamicDependencies.SetCapacity( m_DynamicDependencies.GetSize() + files.GetSize() ); for ( Array< FileIO::FileInfo >::Iter fIt = files.Begin(); fIt != files.End(); fIt++ ) { // Create the file node (or find an existing one) Node * n = nodeGraph.FindNode( fIt->m_Name ); if ( n == nullptr ) { n = nodeGraph.CreateFileNode( fIt->m_Name ); } else if ( n->IsAFile() == false ) { FLOG_ERROR( "Library() .CompilerInputFile '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() ); return false; } // ignore the precompiled header as a convenience for the user // so they don't have to exclude it explicitly #if defined( __WINDOWS__ ) if ( n == pchCPP ) { continue; } #endif // create the object that will compile the above file if ( CreateDynamicObjectNode( nodeGraph, n, dln->GetPath() ) == false ) { return false; // CreateDynamicObjectNode will have emitted error } } } else if ( i->GetNode()->GetType() == Node::UNITY_NODE ) { // get the dir list from the unity node UnityNode * un = i->GetNode()->CastTo< UnityNode >(); // unity files const Array< AString > & unityFiles = un->GetUnityFileNames(); for ( Array< AString >::Iter it = unityFiles.Begin(); it != unityFiles.End(); it++ ) { Node * n = nodeGraph.FindNode( *it ); if ( n == nullptr ) { n = nodeGraph.CreateFileNode( *it ); } else if ( n->IsAFile() == false ) { FLOG_ERROR( "Library() .CompilerInputUnity '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() ); return false; } // create the object that will compile the above file if ( CreateDynamicObjectNode( nodeGraph, n, AString::GetEmpty(), true ) == false ) { return false; // CreateDynamicObjectNode will have emitted error } } // files from unity to build individually const Array< UnityNode::FileAndOrigin > & isolatedFiles = un->GetIsolatedFileNames(); for ( Array< UnityNode::FileAndOrigin >::Iter it = isolatedFiles.Begin(); it != isolatedFiles.End(); it++ ) { Node * n = nodeGraph.FindNode( it->GetName() ); if ( n == nullptr ) { n = nodeGraph.CreateFileNode( it->GetName() ); } else if ( n->IsAFile() == false ) { FLOG_ERROR( "Library() Isolated '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() ); return false; } // create the object that will compile the above file const AString & baseDir = it->GetDirListOrigin() ? it->GetDirListOrigin()->GetPath() : AString::GetEmpty(); if ( CreateDynamicObjectNode( nodeGraph, n, baseDir, false, true ) == false ) { return false; // CreateDynamicObjectNode will have emitted error } } } else if ( i->GetNode()->IsAFile() ) { // a single file, create the object that will compile it if ( CreateDynamicObjectNode( nodeGraph, i->GetNode(), AString::GetEmpty() ) == false ) { return false; // CreateDynamicObjectNode will have emitted error } } else { ASSERT( false ); // unexpected node type } } // If we have a precompiled header, add that to our dynamic deps so that // any symbols in the PCH's .obj are also linked, when either: // a) we are a static library // b) a DLL or executable links our .obj files if ( m_PrecompiledHeader ) { m_DynamicDependencies.Append( Dependency( m_PrecompiledHeader ) ); } return true; }
void GuiAppInstance::createNodeGui(const NodePtr &node, const NodePtr& parentMultiInstance, const CreateNodeArgs& args) { NodeCollectionPtr group = node->getGroup(); NodeGraph* graph; if (group) { NodeGraphI* graph_i = group->getNodeGraph(); assert(graph_i); graph = dynamic_cast<NodeGraph*>(graph_i); assert(graph); } else { graph = _imp->_gui->getNodeGraph(); } if (!graph) { throw std::logic_error(""); } NodesGuiList selectedNodes = graph->getSelectedNodes(); NodeGuiPtr nodegui = _imp->_gui->createNodeGUI(node, args); assert(nodegui); if (parentMultiInstance && nodegui) { nodegui->hideGui(); NodeGuiIPtr parentNodeGui_i = parentMultiInstance->getNodeGui(); assert(parentNodeGui_i); nodegui->setParentMultiInstance( boost::dynamic_pointer_cast<NodeGui>(parentNodeGui_i) ); } bool isViewer = node->isEffectViewerInstance() != 0; if (isViewer) { _imp->_gui->createViewerGui(node); } // Must be done after the viewer gui has been created _imp->_gui->createNodeViewerInterface(nodegui); NodeGroupPtr isGroup = node->isEffectNodeGroup(); if ( isGroup && isGroup->isSubGraphUserVisible() ) { _imp->_gui->createGroupGui(node, args); } ///Don't initialize inputs if it is a multi-instance child since it is not part of the graph if (!parentMultiInstance) { nodegui->initializeInputs(); } NodeSerializationPtr serialization = args.getProperty<NodeSerializationPtr >(kCreateNodeArgsPropNodeSerialization); if ( !serialization && !isViewer ) { ///we make sure we can have a clean preview. node->computePreviewImage( getTimeLine()->currentFrame() ); triggerAutoSave(); } ///only move main instances if ( node->getParentMultiInstanceName().empty() && !serialization) { bool autoConnect = args.getProperty<bool>(kCreateNodeArgsPropAutoConnect); if ( selectedNodes.empty() || serialization) { autoConnect = false; } double xPosHint = serialization ? INT_MIN : args.getProperty<double>(kCreateNodeArgsPropNodeInitialPosition, 0); double yPosHint = serialization ? INT_MIN : args.getProperty<double>(kCreateNodeArgsPropNodeInitialPosition, 1); if ( (xPosHint != INT_MIN) && (yPosHint != INT_MIN) && (!autoConnect) ) { QPointF pos = nodegui->mapToParent( nodegui->mapFromScene( QPointF(xPosHint, yPosHint) ) ); nodegui->refreshPosition( pos.x(), pos.y(), true ); } else { BackdropGuiPtr isBd = toBackdropGui(nodegui); if (!isBd) { NodeGuiPtr selectedNode; if ( !serialization && (selectedNodes.size() == 1) ) { selectedNode = selectedNodes.front(); BackdropGuiPtr isBdGui = toBackdropGui(selectedNode); if (isBdGui) { selectedNode.reset(); } } nodegui->getDagGui()->moveNodesForIdealPosition(nodegui, selectedNode, autoConnect); } } } } // createNodeGui