// GetObjectListNodes //------------------------------------------------------------------------------ bool Function::GetObjectListNodes( const BFFIterator & iter, const Array< AString > & objectLists, const char * inputVarName, Dependencies & nodes ) const { NodeGraph & ng = FBuild::Get().GetDependencyGraph(); 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 = ng.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; }
// 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; }
// GetCompilerNode //------------------------------------------------------------------------------ bool FunctionObjectList::GetCompilerNode( const BFFIterator & iter, const AString & compiler, CompilerNode * & compilerNode ) const { NodeGraph & ng = FBuild::Get().GetDependencyGraph(); Node * cn = ng.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) #ifdef USE_NODE_REFLECTION compilerNode = ng.CreateCompilerNode( compiler ); VERIFY( compilerNode->GetReflectionInfoV()->SetProperty( compilerNode, "AllowDistribution", false ) ); #else const bool allowDistribution = false; compilerNode = ng.CreateCompilerNode( compiler, Dependencies( 0, false ), allowDistribution ); #endif } return true; }
// GetDirectoryNodeList //------------------------------------------------------------------------------ bool Function::GetDirectoryListNodeList( 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 { NodeGraph & ng = FBuild::Get().GetDependencyGraph(); // 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 = ng.FindNode( name ); if ( node == nullptr ) { node = ng.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; }
// GetFileNode //------------------------------------------------------------------------------ bool Function::GetFileNode( 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 NodeGraph & ng = FBuild::Get().GetDependencyGraph(); Node * n = ng.FindNode( fileNodeName ); if ( n == nullptr ) { n = ng.CreateFileNode( fileNodeName ); } else if ( n->IsAFile() == false ) { Error::Error_1103_NotAFile( iter, this, name, n->GetName(), n->GetType() ); return false; } fileNode = n; return true; }
// PopulateStringHelper //------------------------------------------------------------------------------ bool Function::PopulateStringHelper( 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 = FBuild::Get().GetDependencyGraph().FindNode( string ); if ( node && ( node->GetType() == Node::ALIAS_NODE ) ) { AliasNode * aliasNode = node->CastTo< AliasNode >(); for ( const auto& aliasedNode : aliasNode->GetAliasedNodes() ) { if ( !PopulateStringHelper( 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; }
// DoDynamicDependencies //------------------------------------------------------------------------------ /*virtual*/ bool CSNode::DoDynamicDependencies( bool UNUSED( forceClean ) ) { ASSERT( m_DynamicDependencies.GetSize() == 0 ); NodeGraph & ng = FBuild::Get().GetDependencyGraph(); // preallocate a reasonable amount of space m_DynamicDependencies.SetCapacity( m_StaticDependencies.GetSize() ); // convert static deps to dynamic deps // (ignore the extra refs here) size_t numDeps = m_StaticDependencies.GetSize() - m_ExtraRefs.GetSize(); for ( size_t i=0; i<numDeps; ++i ) { Node * n = m_StaticDependencies[ i ].GetNode(); if ( n->IsAFile() ) { m_DynamicDependencies.Append( Dependency( n ) ); continue; } if ( n->GetType() == Node::DIRECTORY_LIST_NODE ) { // get the list of files DirectoryListNode * dln = n->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 * sn = ng.FindNode( fIt->m_Name ); if ( sn == nullptr ) { sn = ng.CreateFileNode( fIt->m_Name ); } else if ( sn->IsAFile() == false ) { FLOG_ERROR( "CSAssembly() .CompilerInputFile '%s' is not a FileNode (type: %s)", n->GetName().Get(), n->GetTypeName() ); return false; } m_DynamicDependencies.Append( Dependency( sn ) ); } continue; } FLOG_ERROR( "'%s' is not a supported node type (type: %s)", n->GetName().Get(), n->GetTypeName() ); return false; } return true; }
void Node::InitAlias(const Mark& mark, const Node& identity) { Clear(); m_mark = mark; m_alias = true; m_pIdentity = &identity; if(identity.m_pContent) { m_pContent = new AliasContent(identity.m_pContent); m_type = identity.GetType(); } identity.m_referenced = true; }
// GetDirectoryNodeList //------------------------------------------------------------------------------ bool Function::GetDirectoryListNodeList( const BFFIterator & iter, const Array< AString > & paths, const Array< AString > & excludePaths, const Array< AString > & filesToExclude, bool recurse, const AString & pattern, const char * inputVarName, Dependencies & nodes ) const { NodeGraph & ng = FBuild::Get().GetDependencyGraph(); 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, pattern, recurse, excludePaths, filesToExclude, name ); Node * node = ng.FindNode( name ); if ( node == nullptr ) { node = ng.CreateDirectoryListNode( name, path, pattern, recurse, excludePaths, filesToExclude ); } 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 XmlWriter::WriteNode(const Node& rNode) { switch (rNode.GetType()) { case Node::TypeElement: WriteElement(rNode.GetElement()); break; case Node::TypeText: WriteText(static_cast<const Text&>(rNode)); break; case Node::TypeComment: WriteComment(static_cast<const Comment&>(rNode)); break; case Node::TypeCdata: WriteCdata(static_cast<const Cdata&>(rNode)); break; default: STAFF_THROW_ASSERT("Invalid Node Type: " + ToString(rNode.GetType())); } }
void Subgraph::RecursivelyGetPartsOfSpeech(const Node *n, std::vector<std::string> &out) const { NodeType nodeType = n->GetType(); if (nodeType == TREE) { if (m_leaves.find(n) == m_leaves.end()) { const std::vector<Node *> &children = n->GetChildren(); for (std::vector<Node *>::const_iterator p(children.begin()); p != children.end(); ++p) { Node *child = *p; if (child->GetType() == TARGET) { out.push_back(n->GetLabel()); } else { RecursivelyGetPartsOfSpeech(child,out); } } } } }
Node *AlignmentGraph::DetermineAttachmentPoint(int index) { // Find the nearest aligned neighbour to the left, if any. int i = index; while (--i >= 0) { if (!m_sourceNodes[i]->GetParents().empty()) { break; } } // No aligned neighbours to the left, so attach to the root. if (i == -1) { return m_root; } // Find the nearest aligned neighbour to the right, if any. int j = index; while (++j < m_sourceNodes.size()) { if (!m_sourceNodes[j]->GetParents().empty()) { break; } } // No aligned neighbours to the right, so attach to the root. if (j == m_sourceNodes.size()) { return m_root; } // Construct the set of target nodes that are aligned to the left and right // neighbours. const std::vector<Node *> &leftParents = m_sourceNodes[i]->GetParents(); assert(!leftParents.empty()); const std::vector<Node *> &rightParents = m_sourceNodes[j]->GetParents(); assert(!rightParents.empty()); std::set<Node *> targetSet; targetSet.insert(leftParents.begin(), leftParents.end()); targetSet.insert(rightParents.begin(), rightParents.end()); // The attachment point is the lowest common ancestor of the target word // nodes, unless the LCA is itself a target word, in which case the LCA // is the parent. This is to avoid including introducing new word alignments. // It assumes that the parse tree uses preterminals for parts of speech. Node *lca = Node::LowestCommonAncestor(targetSet.begin(), targetSet.end()); if (lca->GetType() == TARGET) { assert(lca->GetParents().size() == 1); return lca->GetParents()[0]; } return lca; }
// LoadNode (CompilerNode) //------------------------------------------------------------------------------ /*static*/ bool Node::LoadNode( IOStream & stream, CompilerNode * & compilerNode ) { Node * node; if ( !LoadNode( stream, node ) ) { return false; } if ( node == nullptr ) { compilerNode = nullptr; return true; } if ( node->GetType() != Node::COMPILER_NODE ) { return false; } compilerNode = node->CastTo< CompilerNode >(); return true; }
// ResolveVCXProject //------------------------------------------------------------------------------ VCXProjectNode * FunctionSLN::ResolveVCXProject( const BFFIterator & iter, const AString & projectName ) const { // Find the Node NodeGraph & ng = FBuild::Get().GetDependencyGraph(); Node * node = ng.FindNode( projectName ); if ( node == nullptr ) { Error::Error_1104_TargetNotDefined( iter, this, ".Projects", projectName ); return nullptr; } VCXProjectNode * project = ResolveVCXProjectRecurse( node ); if ( project ) { return project; } // don't know how to handle this type of node Error::Error_1005_UnsupportedNodeType( iter, this, ".Projects", node->GetName(), node->GetType() ); return nullptr; }
// 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; }
void AlignmentGraph::ExtractMinimalRules(const Options &options) { // Determine which nodes are frontier nodes. std::set<Node *> frontierSet; ComputeFrontierSet(m_root, options, frontierSet); // Form the minimal frontier graph fragment rooted at each frontier node. std::vector<Subgraph> fragments; fragments.reserve(frontierSet.size()); for (std::set<Node *>::iterator p(frontierSet.begin()); p != frontierSet.end(); ++p) { Node *root = *p; Subgraph fragment = ComputeMinimalFrontierGraphFragment(root, frontierSet); assert(!fragment.IsTrivial()); // Can it form an SCFG rule? // FIXME Does this exclude non-lexical unary rules? if (root->GetType() == TREE && !root->GetSpan().empty()) { root->AddRule(new Subgraph(fragment)); } } }
Subgraph AlignmentGraph::ComputeMinimalFrontierGraphFragment( Node *root, const std::set<Node *> &frontierSet) { std::stack<Node *> expandableNodes; std::set<const Node *> expandedNodes; if (root->IsSink()) { expandedNodes.insert(root); } else { expandableNodes.push(root); } while (!expandableNodes.empty()) { Node *n = expandableNodes.top(); expandableNodes.pop(); const std::vector<Node *> &children = n->GetChildren(); for (std::vector<Node *>::const_iterator p(children.begin()); p != children.end(); ++p) { Node *child = *p; if (child->IsSink()) { expandedNodes.insert(child); continue; } std::set<Node *>::const_iterator q = frontierSet.find(child); if (q == frontierSet.end()) { //child is not from the frontier set expandableNodes.push(child); } else if (child->GetType() == TARGET) { // still need source word expandableNodes.push(child); } else { expandedNodes.insert(child); } } } return Subgraph(root, expandedNodes); }
//================================================================================= /*virtual*/ bool Node::Copy( const Node* node, Context& context, const CopyParameters& copyParameters ) { if( copyParameters.copyIdentityInfo ) { // Copy the name. name = node->name; // Copy the explanations. In the idea of clonnig a template tree, // this explanation text will become very redundant and in that way, // potentially take up a lot of space unecessarily. for( int index = 0; index < EXPLANATION_COUNT; index++ ) explanation[ index ] = node->explanation[ index ]; } // We don't know who are parent is yet unless we're just copying the node value. if( copyParameters.copyChildrenDisposition != COPY_NODE_AND_LEAVE_CHILDREN_UNTOUCHED ) parent = 0; // Remove children in preparation for copying over a new set of children, or do so if told to do so. if( copyParameters.copyChildrenDisposition == COPY_NODE_AND_CHILDREN || copyParameters.copyChildrenDisposition == COPY_NODE_AND_REMOVE_ALL_CHILDREN ) DeleteChildren(); // Clone the children of the given node if told to do so. if( node->children && copyParameters.copyChildrenDisposition == COPY_NODE_AND_CHILDREN ) { children = new std::list< Node* >(); for( List::iterator iter = node->children->begin(); iter != node->children->end(); iter++ ) { Node* child = *iter; Node* clone = child->Clone( context, copyParameters ); if( !clone ) return context.IssueError( "Failed to clone node \"%s\" of type \"%s\".", child->name.c_str(), child->GetType().c_str() ); children->push_back( clone ); clone->parent = this; } } // Clone any meta-data. if( node->metaData && copyParameters.copyMetaData ) { if( !metaData ) { Context::MetaDataCreatorFunc metaDataCreatorFunc = context.GetMetaDataCreatorFunc(); if( metaDataCreatorFunc ) metaData = metaDataCreatorFunc(); else return context.IssueError( "Failed to copy meta-data of node \"%s\" of type \"%s\", because there is no meta-data creator function.", name.c_str(), GetType().c_str() ); if( !metaData ) return context.IssueError( "Failed to copy meta-data of node \"%s\" of type \"%s\", because the meta-data creator failed.", name.c_str(), GetType().c_str() ); metaData->PostCreate( this ); } if( !metaData->Copy( node->metaData, context ) ) return context.IssueError( "Failed to copy meta-data of node \"%s\" of type \"%s\".", name.c_str(), GetType().c_str() ); } return true; }
//================================================================================= /*virtual*/ bool Node::WriteToTable( lua_State* L, Context& context ) const { bool success = false; int top = lua_gettop( L ); try { // Write the node type. lua_pushstring( L, GetType().c_str() ); lua_setfield( L, -2, "type" ); // Write the node name. lua_pushstring( L, name.c_str() ); lua_setfield( L, -2, "name" ); // Write the node explanations. for( int index = 0; index < EXPLANATION_COUNT; index++ ) { char explanationKey[ 128 ]; sprintf_s( explanationKey, sizeof( explanationKey ), "explanation%d", index ); lua_pushstring( L, explanation[ index ].c_str() ); lua_setfield( L, -2, explanationKey ); } // Are there any children? if( children && children->size() > 0 ) { // Yes. Create the children table. lua_newtable( L ); // Go populate the children table. int index = 1; for( List::iterator iter = children->begin(); iter != children->end(); iter++ ) { Node* node = *iter; lua_pushinteger( L, index++ ); lua_newtable( L ); if( !node->WriteToTable( L, context ) ) throw new Error( "The node \"%s\" of type \"%s\", or one of its children, failed to write its node contents to a Lua table.", node->name.c_str(), node->GetType().c_str() ); lua_settable( L, -3 ); } // Now that the table is populated, add it to the node table. // This also pops the table from the stack. lua_setfield( L, -2, "children" ); } // If this node has meta-data, write that out too. if( metaData ) { lua_newtable( L ); if( !metaData->WriteToTable( L, context ) ) throw new Error( "The node \"%s\" of type\"%s\" failed to write out its meta-data.", name.c_str(), GetType().c_str() ); lua_setfield( L, -2, "meta_data" ); } // We made it through the gauntlet! success = true; } catch( Error* error ) { context.IssueError( error ); } lua_settop( L, top ); return success; }
// GetInputs //------------------------------------------------------------------------------ bool FunctionObjectList::GetInputs( const BFFIterator & iter, Dependencies & inputs ) const { NodeGraph & ng = FBuild::Get().GetDependencyGraph(); // do we want to build files via a unity blob? Array< AString > inputUnities; if ( !GetStrings( iter, inputUnities, ".CompilerInputUnity", false ) ) // not required { return false; } for ( const auto& unity : inputUnities ) { Node * n = ng.FindNode( unity ); if ( n == nullptr ) { Error::Error_1104_TargetNotDefined( iter, this, "CompilerInputUnity", unity ); return false; } if ( n->GetType() != Node::UNITY_NODE ) { Error::Error_1102_UnexpectedType( iter, this, "CompilerInputUnity", unity, n->GetType(), Node::UNITY_NODE ); return false; } inputs.Append( Dependency( n ) ); } // do we want to build a files in a directory? const BFFVariable * inputPath = BFFStackFrame::GetVar( ".CompilerInputPath" ); if ( inputPath ) { // get the optional pattern and recurse options related to InputPath Array< AString > patterns; if ( !GetStrings( iter, patterns, ".CompilerInputPattern", false ) ) { return false; // GetString will have emitted an error } if ( patterns.IsEmpty() ) { patterns.Append( AStackString<>( "*.cpp" ) ); } // recursive? default to true bool recurse = true; if ( !GetBool( iter, recurse, ".CompilerInputPathRecurse", true, false ) ) { return false; // GetBool will have emitted an error } // Support an exclusion path Array< AString > excludePaths; if ( !GetFolderPaths( iter, excludePaths, ".CompilerInputExcludePath", false ) ) { return false; // GetFolderPaths will have emitted an error } Array< AString > filesToExclude; if ( !GetStrings( iter, filesToExclude, ".CompilerInputExcludedFiles", false ) ) // not required { return false; // GetStrings will have emitted an error } CleanFileNames( filesToExclude ); // Input paths Array< AString > inputPaths; if ( !GetFolderPaths( iter, inputPaths, ".CompilerInputPath", false ) ) { return false; // GetFolderPaths will have emitted an error } Dependencies dirNodes( inputPaths.GetSize() ); if ( !GetDirectoryListNodeList( iter, inputPaths, excludePaths, filesToExclude, recurse, &patterns, "CompilerInputPath", dirNodes ) ) { return false; // GetDirectoryListNodeList will have emitted an error } inputs.Append( dirNodes ); } // do we want to build a specific list of files? if ( !GetNodeList( iter, ".CompilerInputFiles", inputs, false ) ) { // helper will emit error return false; } return true; }
// GetPrecompiledHeaderNode //------------------------------------------------------------------------------ bool FunctionObjectList::GetPrecompiledHeaderNode( const BFFIterator & iter, CompilerNode * compilerNode, uint32_t objFlags, const BFFVariable * compilerOptions, const Dependencies & compilerForceUsing, ObjectNode * & precompiledHeaderNode, bool deoptimizeWritableFiles, bool deoptimizeWritableFilesWithToken ) const { const BFFVariable * pchInputFile = nullptr; const BFFVariable * pchOutputFile = nullptr; const BFFVariable * pchOptions = nullptr; if ( !GetString( iter, pchInputFile, ".PCHInputFile" ) || !GetString( iter, pchOutputFile, ".PCHOutputFile" ) || !GetString( iter, pchOptions, ".PCHOptions" ) ) { return false; } precompiledHeaderNode = nullptr; if ( pchInputFile ) { if ( !pchOutputFile || !pchOptions ) { Error::Error_1300_MissingPCHArgs( iter, this ); return false; } AStackString<> pchOptionsDeoptimized; if ( !GetString( iter, pchOptionsDeoptimized, ".PCHOptionsDeoptimized", ( deoptimizeWritableFiles || deoptimizeWritableFilesWithToken ) ) ) { return false; } NodeGraph & ng = FBuild::Get().GetDependencyGraph(); Node * pchInputNode = ng.FindNode( pchInputFile->GetString() ); if ( pchInputNode ) { // is it a file? if ( pchInputNode->IsAFile() == false ) { Error::Error_1103_NotAFile( iter, this, "PCHInputFile", pchInputNode->GetName(), pchInputNode->GetType() ); return false; } } else { // Create input node pchInputNode = ng.CreateFileNode( pchInputFile->GetString() ); } if ( ng.FindNode( pchOutputFile->GetString() ) ) { Error::Error_1301_AlreadyDefinedPCH( iter, this, pchOutputFile->GetString().Get() ); return false; } uint32_t pchFlags = ObjectNode::DetermineFlags( compilerNode, pchOptions->GetString() ); if ( pchFlags & ObjectNode::FLAG_MSVC ) { // sanity check arguments // PCH must have "Create PCH" (e.g. /Yc"PrecompiledHeader.h") if ( !( pchFlags & ObjectNode::FLAG_CREATING_PCH ) ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "/Yc", "PCHOptions" ); return false; } // PCH must have "Precompiled Header to Use" (e.g. /Fp"PrecompiledHeader.pch") if ( pchOptions->GetString().Find( "/Fp" ) == nullptr ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "/Fp", "PCHOptions" ); return false; } // PCH must have object output option (e.g. /Fo"PrecompiledHeader.obj") if ( pchOptions->GetString().Find( "/Fo" ) == nullptr ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "/Fo", "PCHOptions" ); return false; } // Object using the PCH must have "Use PCH" option (e.g. /Yu"PrecompiledHeader.h") if ( !( objFlags & ObjectNode::FLAG_USING_PCH ) ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "/Yu", "CompilerOptions" ); return false; } // Object using the PCH must have "Precompiled header to use" (e.g. /Fp"PrecompiledHeader.pch") if ( compilerOptions->GetString().Find( "/Fp" ) == nullptr ) { Error::Error_1302_MissingPCHCompilerOption( iter, this, "/Fp", "CompilerOptions" ); return false; } } // TODO:B Check PCHOptionsDeoptimized precompiledHeaderNode = ng.CreateObjectNode( pchOutputFile->GetString(), pchInputNode, compilerNode, pchOptions->GetString(), pchOptionsDeoptimized, nullptr, pchFlags, compilerForceUsing, deoptimizeWritableFiles, deoptimizeWritableFilesWithToken, nullptr, AString::GetEmpty(), 0 ); // preprocessor args not supported } return true; }
// DoBuild //------------------------------------------------------------------------------ /*static*/ Node::BuildResult JobQueue::DoBuild( Job * job ) { Timer timer; // track how long the item takes Node * node = job->GetNode(); // make sure the output path exists for files // (but don't bother for input files) if ( node->IsAFile() && ( node->GetType() != Node::FILE_NODE ) && ( node->GetType() != Node::COMPILER_NODE ) ) { if ( Node::EnsurePathExistsForFile( node->GetName() ) == false ) { // error already output by EnsurePathExistsForFile return Node::NODE_RESULT_FAILED; } } Node::BuildResult result = node->DoBuild( job ); uint32_t timeTakenMS = uint32_t( timer.GetElapsedMS() ); if ( result == Node::NODE_RESULT_OK ) { // record new build time only if built (i.e. if cached or failed, the time // does not represent how long it takes to create this resource) node->SetLastBuildTime( timeTakenMS ); node->SetStatFlag( Node::STATS_BUILT ); FLOG_INFO( "-Build: %u ms\t%s", timeTakenMS, node->GetName().Get() ); } if ( result == Node::NODE_RESULT_NEED_SECOND_BUILD_PASS ) { // nothing to check } else if ( node->IsAFile() ) { if ( result == Node::NODE_RESULT_FAILED ) { if ( node->GetControlFlags() & Node::FLAG_NO_DELETE_ON_FAIL ) { // node failed, but builder wants result left on disc } else { // build of file failed - if there is a file.... if ( FileIO::FileExists( node->GetName().Get() ) ) { // ... it is invalid, so try to delete it if ( FileIO::FileDelete( node->GetName().Get() ) == false ) { // failed to delete it - this might cause future build problems! FLOG_ERROR( "Post failure deletion failed for '%s'", node->GetName().Get() ); } } } } else { // build completed ok, or retrieved from cache... ASSERT( ( result == Node::NODE_RESULT_OK ) || ( result == Node::NODE_RESULT_OK_CACHE ) ); // (don't check existence of input files) if ( node->GetType() != Node::FILE_NODE ) { // ... ensure file exists (to detect builder logic problems) if ( !FileIO::FileExists( node->GetName().Get() ) ) { FLOG_ERROR( "File missing despite success for '%s'", node->GetName().Get() ); result = Node::NODE_RESULT_FAILED; } } } } // log processing time node->AddProcessingTime( timeTakenMS ); return result; }
// CreateDynamicObjectNode //------------------------------------------------------------------------------ bool ObjectListNode::CreateDynamicObjectNode( NodeGraph & nodeGraph, Node * inputFile, const AString & baseDir, bool isUnityNode, bool isIsolatedFromUnityNode ) { const AString & fileName = inputFile->GetName(); // Transform src file to dst object path // get file name only (no path, no ext) const char * lastSlash = fileName.FindLast( NATIVE_SLASH ); lastSlash = lastSlash ? ( lastSlash + 1 ) : fileName.Get(); const char * lastDot = fileName.FindLast( '.' ); lastDot = lastDot && ( lastDot > lastSlash ) ? lastDot : fileName.GetEnd(); // if source comes from a directory listing, use path relative to dirlist base // to replicate the folder hierearchy in the output AStackString<> subPath; if ( baseDir.IsEmpty() == false ) { ASSERT( NodeGraph::IsCleanPath( baseDir ) ); if ( PathUtils::PathBeginsWith( fileName, baseDir ) ) { // ... use everything after that subPath.Assign( fileName.Get() + baseDir.GetLength(), lastSlash ); // includes last slash } } else { if ( !m_BaseDirectory.IsEmpty() && PathUtils::PathBeginsWith( fileName, m_BaseDirectory ) ) { // ... use everything after that subPath.Assign( fileName.Get() + m_BaseDirectory.GetLength(), lastSlash ); // includes last slash } } AStackString<> fileNameOnly( lastSlash, lastDot ); AStackString<> objFile( m_CompilerOutputPath ); objFile += subPath; objFile += m_CompilerOutputPrefix; objFile += fileNameOnly; objFile += GetObjExtension(); // Create an ObjectNode to compile the above file // and depend on that Node * on = nodeGraph.FindNode( objFile ); if ( on == nullptr ) { // determine flags - TODO:B Move DetermineFlags call out of build-time const bool usingPCH = ( m_PrecompiledHeader != nullptr ); uint32_t flags = ObjectNode::DetermineFlags( m_Compiler, m_CompilerArgs, false, usingPCH ); if ( isUnityNode ) { flags |= ObjectNode::FLAG_UNITY; } if ( isIsolatedFromUnityNode ) { flags |= ObjectNode::FLAG_ISOLATED_FROM_UNITY; } uint32_t preprocessorFlags = 0; if ( m_Preprocessor ) { // determine flags - TODO:B Move DetermineFlags call out of build-time preprocessorFlags = ObjectNode::DetermineFlags( m_Preprocessor, m_PreprocessorArgs, false, usingPCH ); } on = nodeGraph.CreateObjectNode( objFile, inputFile, m_Compiler, m_CompilerArgs, m_CompilerArgsDeoptimized, m_PrecompiledHeader, flags, m_CompilerForceUsing, m_DeoptimizeWritableFiles, m_DeoptimizeWritableFilesWithToken, m_AllowDistribution, m_AllowCaching, m_Preprocessor, m_PreprocessorArgs, preprocessorFlags ); } else if ( on->GetType() != Node::OBJECT_NODE ) { FLOG_ERROR( "Node '%s' is not an ObjectNode (type: %s)", on->GetName().Get(), on->GetTypeName() ); return false; } else { ObjectNode * other = on->CastTo< ObjectNode >(); if ( inputFile != other->GetSourceFile() ) { FLOG_ERROR( "Conflicting objects found:\n" " File A: %s\n" " File B: %s\n" " Both compile to: %s\n", inputFile->GetName().Get(), other->GetSourceFile()->GetName().Get(), objFile.Get() ); return false; } } m_DynamicDependencies.Append( Dependency( on ) ); return true; }
void GameplayScreen::DrawDebug(SDL_Renderer* renderer) { // Iterate over each node in the level graph for (std::vector<Node*>::iterator iter = levelManager->GetLegalNodes().begin(); iter != levelManager->GetLegalNodes().end(); ++iter) { Node* node = (*iter); Vector2f loc = node->GetPosition(); // Temporarily set the rendering color to white for the nodes SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // white switch (node->GetType()) { //case NodeType::Empty: //SDL_RenderCopy(renderer, TextureManager::GetTexture(, NULL, &boundingRect); } SDL_RenderDrawPoint(renderer, loc.x, loc.y); // Draw each node's bounding rectangle (*iter)->Render(renderer); SDL_Texture* nodeIdText = NULL; // Display the node id if (nodeDisplayFlags[ID]) { Utils::RenderText(renderer, arialFont, std::to_string((*iter)->GetNodeId()), SDL_Color{ 255, 255, 255 }, (*iter)->GetBoundingRect()); } // Display the G val if (nodeDisplayFlags[G]) { Utils::RenderText(renderer, arialFont, std::to_string((*iter)->GetMovementCost()), SDL_Color{ 255, 255, 255 }, (*iter)->GetBoundingRect()); } // Display the H val if (nodeDisplayFlags[H]) { Utils::RenderText(renderer, arialFont, std::to_string((*iter)->GetHeuristic()), SDL_Color{ 255, 255, 255 }, (*iter)->GetBoundingRect()); } // Display the F val if (nodeDisplayFlags[F]) { Utils::RenderText(renderer, arialFont, std::to_string((*iter)->GetTotalCost()), SDL_Color{ 255, 255, 255 }, (*iter)->GetBoundingRect()); } SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // black } // Display the current node ID for each ghost auto ghostList = levelManager->GetGhosts(); for (int i = 0; i < ghostList.size(); i++) { if (ghostList[i]->GetCurrentNode() != NULL) { const int OFFSET = 20; SDL_Rect loc; loc.x = 100; loc.y = 200 + (i * OFFSET); loc.w = 40; loc.h = 30; Utils::RenderText(renderer, arialFont, std::to_string(ghostList[i]->GetCurrentNode()->GetNodeId()), SDL_Color{ 255, 255, 255 }, &loc); } } }
// GetNodeListRecurse //------------------------------------------------------------------------------ bool Function::GetNodeListRecurse( const BFFIterator & iter, const char * name, Dependencies & nodes, const AString & nodeName, bool allowCopyDirNodes, bool allowUnityNodes, bool allowRemoveDirNodes ) const { NodeGraph & ng = FBuild::Get().GetDependencyGraph(); // get node Node * n = ng.FindNode( nodeName ); if ( n == nullptr ) { // not found - create a new file node n = ng.CreateFileNode( nodeName ); nodes.Append( Dependency( n ) ); return true; } // found - is it a file? if ( n->IsAFile() ) { // found file - just use as is nodes.Append( Dependency( n ) ); return true; } // found - is it an ObjectList? if ( n->GetType() == Node::OBJECT_LIST_NODE ) { // use as-is nodes.Append( Dependency( n ) ); return true; } // extra types if ( allowCopyDirNodes ) { // found - is it an ObjectList? if ( n->GetType() == Node::COPY_DIR_NODE ) { // use as-is nodes.Append( Dependency( n ) ); return true; } } if ( allowRemoveDirNodes ) { // found - is it a RemoveDirNode? if ( n->GetType() == Node::REMOVE_DIR_NODE ) { // use as-is nodes.Append( Dependency( n ) ); return true; } } if ( allowUnityNodes ) { // found - is it an ObjectList? if ( n->GetType() == Node::UNITY_NODE ) { // use as-is nodes.Append( Dependency( n ) ); return true; } } // found - is it a group? if ( n->GetType() == Node::ALIAS_NODE ) { AliasNode * an = n->CastTo< AliasNode >(); const Dependencies & aNodes = an->GetAliasedNodes(); for ( const Dependency * it = aNodes.Begin(); it != aNodes.End(); ++it ) { // TODO:C by passing as string we'll be looking up again for no reason const AString & subName = it->GetNode()->GetName(); if ( !GetNodeListRecurse( iter, name, nodes, subName, allowCopyDirNodes, allowUnityNodes, allowRemoveDirNodes ) ) { return false; } } return true; } // don't know how to handle this type of node Error::Error_1005_UnsupportedNodeType( iter, this, name, n->GetName(), n->GetType() ); return false; }
Value IdentExpr::Evaluate(SymbolTable* scope, EvalContext& context, bool asbool) { /// Scope override; must do this for every expression that might contain an identifier if(this->scope != NULL) scope = this->scope; //context.file = this->file; //context.line = this->linenumber; // To evaluate an identifier expression: // First, we have to look up the symbol and check the type of its value. // If it's a constant, we just evaluate the constant (provided there are no // parameters given; if there are parameters, we should report an error.) // If it's a command, we need to: // - bind each argument expression to the corresponding symbol in the commands // parameter list. // - invoke the command. Module* module = context.module; SymbolTable* lookupScope = scope; // If the ident expr's "file" field is not empty, we'll look it up in a different module if(!file.empty()) { Module* mod = module->GetSiblingContext(file); if(!mod) { Error("reference to nonexistent module '" + file + "'"); return Value::Null; } lookupScope = mod->GetRootTable(); } Value found = lookupScope->Lookup(name); if(found != Value::Undefined) { // In most cases, we just return the value. if(found.GetType() != Type::Macro) { // However, evaluated vars are not importable. if(lookupScope != scope) { Error("cannot access local variable declaration '" + name + "' in module '" + file + "'"); return Value::Null; } return found; } Node* node = found.GetNode(); Value result; if(node->GetType() == conststmt) { if(hasparens) { Error("'" + GetFullName() + "' refers to a constant; cannot use parentheses"); return Value(); } result = dynamic_cast<ConstDef*>(node)->EvaluateExpr(scope, context, asbool); } else if(node->GetType() == commandstmt) { for(unsigned int i = 0; i < args.size(); ++i) args[i]->scope = scope; CommandDef* cmd = dynamic_cast<CommandDef*>(found.GetNode()); if(cmd->GetArgCount() != args.size()) Error("incorrect number of parameters to command '" + GetFullName() + "'"); else result = cmd->Invoke(context, args); } else if(node->GetType() == ambiguousid) { AmbiguousID* ambig = dynamic_cast<AmbiguousID*>(found.GetNode()); Error(ambig->ToString("")); result = Value::Null; } else if(node->IsExpression()) { result = dynamic_cast<Expression*>(node)->Evaluate(scope, context, asbool); } else { Error("invalid type"); } return result; } // Didn't find it in the symbol table, check the jumps table Anchor* foundanchor = lookupScope->LookupAnchor(name); if(foundanchor) { if(hasparens) { Error("'" + GetFullName() + "' refers to a label; cannot use parentheses"); return Value(); } String* val = new String(); val->Long(foundanchor->GetTarget()); // The targeted label might not have its address computed yet, so we register a // reference to the target label (unless refs are forbidden by the context) if(!context.norefs) val->AddReference(val->GetPos()-4, foundanchor); return Value(val); } Error("use of undefined identifier '" + GetFullName() + "'"); return Value(); }
void GlslGeneratorInstance::PrintNodeInit(size_t nodeIndex) { Node* node = nodeInits[nodeIndex]; switch(node->GetType()) { case Node::typeFloatConst: PrintNodeInitBegin(nodeIndex); text << std::fixed << std::setprecision(10) << fast_cast<FloatConstNode*>(node)->GetValue();// << 'f'; PrintNodeInitEnd(); break; case Node::typeIntConst: PrintNodeInitBegin(nodeIndex); text << fast_cast<IntConstNode*>(node)->GetValue(); PrintNodeInitEnd(); break; case Node::typeAttribute: { AttributeNode* attributeNode = fast_cast<AttributeNode*>(node); PrintNodeInitBegin(nodeIndex); // WebGL hack for integer attributes // (only for case of using another hack - changing integer attributes to float) bool intConversion = false; if(glslVersion == GlslVersions::webgl) intConversion = PrintWebGLConversionToIntegerBegin(attributeNode->GetValueType()); text << "a" << attributeNode->GetElementIndex(); if(intConversion) PrintWebGLConversionToIntegerEnd(); PrintNodeInitEnd(); } break; case Node::typeUniform: // uniform doesn't have initialization break; case Node::typeSampler: // sampler doesn't have initialization break; case Node::typeReadUniform: { PrintNodeInitBegin(nodeIndex); ReadUniformNode* readUniformNode = fast_cast<ReadUniformNode*>(node); PrintUniform(readUniformNode->GetUniformNode()); PrintNodeInitEnd(); } break; case Node::typeIndexUniformArray: { PrintNodeInitBegin(nodeIndex); IndexUniformArrayNode* indexUniformArrayNode = fast_cast<IndexUniformArrayNode*>(node); PrintUniform(indexUniformArrayNode->GetUniformNode()); text << '['; PrintNode(indexUniformArrayNode->GetIndexNode()); text << ']'; PrintNodeInitEnd(); } break; case Node::typeTransformed: PrintNodeInitBegin(nodeIndex); text << "v" << fast_cast<TransformedNode*>(node)->GetSemantic(); PrintNodeInitEnd(); break; case Node::typeInterpolate: { InterpolateNode* interpolateNode = fast_cast<InterpolateNode*>(node); text << "\tv" << interpolateNode->GetSemantic() << " = "; PrintNode(interpolateNode->GetNode()); PrintNodeInitEnd(); } break; case Node::typeSequence: // sequence node doesn't have initialization break; case Node::typeSwizzle: { PrintNodeInitBegin(nodeIndex); SwizzleNode* swizzleNode = fast_cast<SwizzleNode*>(node); PrintNode(swizzleNode->GetA()); text << '.' << swizzleNode->GetMap(); PrintNodeInitEnd(); } break; case Node::typeOperation: PrintNodeInitBegin(nodeIndex); PrintOperationNodeInit(fast_cast<OperationNode*>(node)); PrintNodeInitEnd(); break; case Node::typeAction: PrintActionNodeInit(fast_cast<ActionNode*>(node)); break; case Node::typeSample: { PrintNodeInitBegin(nodeIndex); SampleNode* sampleNode = fast_cast<SampleNode*>(node); int slot = sampleNode->GetSamplerNode()->GetSlot(); ValueNode* coordsNode = sampleNode->GetCoordsNode(); ValueNode* offsetNode = sampleNode->GetOffsetNode(); ValueNode* lodNode = sampleNode->GetLodNode(); ValueNode* biasNode = sampleNode->GetBiasNode(); ValueNode* gradXNode = sampleNode->GetGradXNode(); ValueNode* gradYNode = sampleNode->GetGradYNode(); auto printOffsetNode = [&]() { // offset node is required to be constant expression, // but AMD driver requires it also to be compile-time expression // so HACK: print value inline, only for known node // PrintNode(offsetNode); if(offsetNode->GetType() != Node::typeOperation) THROW("wrong offset node"); OperationNode* offsetOperationNode = fast_cast<OperationNode*>(offsetNode); if( offsetOperationNode->GetOperation() != OperationNode::operationInt11to2 || offsetOperationNode->GetA()->GetType() != Node::typeIntConst || offsetOperationNode->GetB()->GetType() != Node::typeIntConst ) THROW("wrong offset node"); text << "ivec2(" << offsetOperationNode->GetA().FastCast<IntConstNode>()->GetValue() << ", " << offsetOperationNode->GetB().FastCast<IntConstNode>()->GetValue() << ")"; }; if(lodNode) { text << "textureLod"; if(offsetNode) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(lodNode); if(offsetNode) { text << ", "; printOffsetNode(); } } else if(biasNode) { text << "texture"; if(offsetNode) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); if(offsetNode) { text << ", "; printOffsetNode(); } text << ", "; PrintNode(biasNode); } else if(gradXNode && gradYNode) { text << "textureGrad"; if(offsetNode) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(gradXNode); text << ", "; PrintNode(gradYNode); if(offsetNode) { text << ", "; printOffsetNode(); } } else { text << (glslVersion == GlslVersions::webgl ? "texture2D" : "texture"); if(offsetNode && glslVersion != GlslVersions::webgl) text << "Offset"; text << '(' << samplerPrefix << slot << ", "; PrintNode(coordsNode); if(offsetNode && glslVersion != GlslVersions::webgl) { text << ", "; printOffsetNode(); } } // close sample call text << ')'; // sample always returns four-component vector, so make some swizzle if needed int valueSize = GetVectorDataTypeDimensions(sampleNode->GetValueType()); if(valueSize < 4) { text << '.'; for(int i = 0; i < valueSize; ++i) text << "xyzw"[i]; } PrintNodeInitEnd(); } break; case Node::typeFragment: { FragmentNode* fragmentNode = fast_cast<FragmentNode*>(node); switch(glslVersion) { case GlslVersions::opengl33: text << "\tr" << fragmentNode->GetTarget(); break; case GlslVersions::webgl: if(fragmentTargetsCount > 1) text << "gl_FragData[" << fragmentNode->GetTarget() << ']'; else text << "gl_FragColor"; break; } text << " = "; PrintNode(fragmentNode->GetNode()); PrintNodeInitEnd(); } break; case Node::typeDualFragment: { DualFragmentNode* dualFragmentNode = fast_cast<DualFragmentNode*>(node); switch(glslVersion) { case GlslVersions::opengl33: text << "\tr0 = "; PrintNode(dualFragmentNode->GetNode0()); PrintNodeInitEnd(); text << "\tr1 = "; PrintNode(dualFragmentNode->GetNode1()); PrintNodeInitEnd(); break; case GlslVersions::webgl: text << "\tgl_FragData[0] = "; PrintNode(dualFragmentNode->GetNode0()); PrintNodeInitEnd(); text << "\tgl_FragData[1] = "; PrintNode(dualFragmentNode->GetNode1()); PrintNodeInitEnd(); break; } } break; case Node::typeCast: { PrintNodeInitBegin(nodeIndex); CastNode* castNode = fast_cast<CastNode*>(node); PrintDataType(castNode->GetValueType()); text << '('; PrintNode(castNode->GetA()); text << ')'; PrintNodeInitEnd(); } break; default: THROW("Unknown node type"); } }
ptr<ShaderSource> Hlsl11GeneratorInstance::Generate() { // first stage: register all nodes RegisterNode(rootNode); // find out if we need instance id for(size_t i = 0; i < nodeInits.size(); ++i) { Node* node = nodeInits[i]; if(node->GetType() == Node::typeOperation) { OperationNode* operationNode = fast_cast<OperationNode*>(node); if(operationNode->GetOperation() == OperationNode::operationGetInstanceID) needInstanceID = true; } } // выборы в зависимости от типа шейдера const char* mainFunctionName; const char* inputTypeName; const char* inputName; const char* outputTypeName; const char* outputName; const char* profile; switch(shaderType) { case ShaderTypes::vertex: mainFunctionName = "VS"; inputTypeName = "A"; inputName = "a"; outputTypeName = "V"; outputName = "v"; profile = "vs_4_0"; break; case ShaderTypes::pixel: mainFunctionName = "PS"; inputTypeName = "V"; inputName = "v"; outputTypeName = "R"; outputName = "r"; profile = "ps_4_0"; break; default: THROW("Unknown shader type"); } // вывести атрибуты, если вершинный шейдер if(shaderType == ShaderTypes::vertex) { text << "struct A\n{\n"; struct IndexSorter { bool operator()(AttributeNode* a, AttributeNode* b) const { return a->GetElementIndex() < b->GetElementIndex(); } }; std::sort(attributes.begin(), attributes.end(), IndexSorter()); for(size_t i = 0; i < attributes.size(); ++i) { AttributeNode* node = attributes[i]; text << '\t'; PrintDataType(node->GetValueType()); int index = node->GetElementIndex(); text << " a" << index << " : " << Dx11System::GetSemanticString(index) << ";\n"; } text << "};\n"; } // print transformed nodes if(shaderType == ShaderTypes::pixel) { text << "struct V\n{\n"; struct SemanticSorter { bool operator()(TransformedNode* a, TransformedNode* b) const { return a->GetSemantic() < b->GetSemantic(); } }; std::sort(transformedNodes.begin(), transformedNodes.end(), SemanticSorter()); for(size_t i = 0; i < transformedNodes.size(); ++i) { TransformedNode* node = transformedNodes[i]; text << '\t'; PrintDataType(node->GetValueType()); int semantic = node->GetSemantic(); text << " v" << semantic << " : " << Dx11System::GetSemanticString(semantic) << ";\n"; } text << "};\n"; } // print interpolate nodes if(shaderType == ShaderTypes::vertex) { text << "struct V\n{\n"; struct SemanticSorter { bool operator()(InterpolateNode* a, InterpolateNode* b) const { return a->GetSemantic() < b->GetSemantic(); } }; std::sort(interpolateNodes.begin(), interpolateNodes.end(), SemanticSorter()); for(size_t i = 0; i < interpolateNodes.size(); ++i) { InterpolateNode* node = interpolateNodes[i]; text << '\t'; PrintDataType(node->GetValueType()); int semantic = node->GetSemantic(); text << " v" << semantic << " : " << Dx11System::GetSemanticString(semantic) << ";\n"; } // вывести SV_Position text << "\tfloat4 vTP : SV_Position;\n"; text << "};\n"; } // вывести пиксельные переменные, если это пиксельный шейдер if(shaderType == ShaderTypes::pixel) { text << "struct R\n{\n"; for(int i = 0; i < fragmentTargetsCount; ++i) { text << '\t'; PrintDataType(DataTypes::_vec4); text << " r" << i << " : SV_Target" << i << ";\n"; } text << "};\n"; } // вывести uniform-буферы PrintUniforms(); // семплеры struct SamplerSlotSorter { bool operator()(SamplerNode* a, SamplerNode* b) const { return a->GetSlot() < b->GetSlot(); } }; std::sort(samplers.begin(), samplers.end(), SamplerSlotSorter()); for(size_t i = 0; i < samplers.size(); ++i) { SamplerNode* samplerNode = samplers[i]; const char* textureStr; switch(samplerNode->GetCoordType()) { case SamplerNode::_1D: textureStr = "Texture1D"; break; case SamplerNode::_2D: textureStr = "Texture2D"; break; case SamplerNode::_3D: textureStr = "Texture3D"; break; case SamplerNode::_Cube: textureStr = "TextureCube"; break; default: THROW("Invalid sampler coord type"); } // текстура text << textureStr << '<'; PrintDataType(samplerNode->GetValueType()); int slot = samplerNode->GetSlot(); text << "> t" << slot << " : register(t" << slot << ");\n"; // семплер text << "SamplerState s" << slot << " : register(s" << slot << ");\n"; } //** заголовок функции шейдера text << outputTypeName << ' ' << mainFunctionName << '(' << inputTypeName << ' ' << inputName; // если шейдер использует instance ID, добавить аргумент if(needInstanceID) text << ", uint sI : SV_InstanceID"; // завершить заголовок text << ")\n{\n\t" << outputTypeName << ' ' << outputName << ";\n"; // shader code for(size_t i = 0; i < nodeInits.size(); ++i) PrintNodeInit(i); // завершение шейдера text << "\treturn " << outputName << ";\n}\n"; // получить маски ресурсов int uniformBuffersMask = 0; for(size_t i = 0; i < uniforms.size(); ++i) uniformBuffersMask |= 1 << uniforms[i].first->GetSlot(); int samplersMask = 0; for(size_t i = 0; i < samplers.size(); ++i) samplersMask |= 1 << samplers[i]->GetSlot(); Dx11ShaderResources resources(uniformBuffersMask, samplersMask); return NEW(Hlsl11Source(Strings::String2File(text.str()), mainFunctionName, profile, resources)); }
void Hlsl11GeneratorInstance::PrintNodeInit(size_t nodeIndex) { Node* node = nodeInits[nodeIndex]; switch(node->GetType()) { case Node::typeFloatConst: PrintNodeInitBegin(nodeIndex); text << std::fixed << std::setprecision(10) << fast_cast<FloatConstNode*>(node)->GetValue() << 'f'; PrintNodeInitEnd(); break; case Node::typeIntConst: PrintNodeInitBegin(nodeIndex); text << fast_cast<IntConstNode*>(node)->GetValue(); PrintNodeInitEnd(); break; case Node::typeAttribute: PrintNodeInitBegin(nodeIndex); text << "a.a" << fast_cast<AttributeNode*>(node)->GetElementIndex(); PrintNodeInitEnd(); break; case Node::typeUniform: // uniform doesn't have initialization break; case Node::typeSampler: // sampler doesn't have initialization break; case Node::typeReadUniform: { PrintNodeInitBegin(nodeIndex); ReadUniformNode* readUniformNode = fast_cast<ReadUniformNode*>(node); PrintUniform(readUniformNode->GetUniformNode()); PrintNodeInitEnd(); } break; case Node::typeIndexUniformArray: { PrintNodeInitBegin(nodeIndex); IndexUniformArrayNode* indexUniformArrayNode = fast_cast<IndexUniformArrayNode*>(node); PrintUniform(indexUniformArrayNode->GetUniformNode()); text << '['; PrintNode(indexUniformArrayNode->GetIndexNode()); text << ']'; PrintNodeInitEnd(); } break; case Node::typeTransformed: PrintNodeInitBegin(nodeIndex); text << "v.v" << fast_cast<TransformedNode*>(node)->GetSemantic(); PrintNodeInitEnd(); break; case Node::typeInterpolate: { InterpolateNode* interpolateNode = fast_cast<InterpolateNode*>(node); text << "\tv.v" << interpolateNode->GetSemantic() << " = "; PrintNode(interpolateNode->GetNode()); PrintNodeInitEnd(); } break; case Node::typeSequence: // sequence node doesn't have initialization break; case Node::typeSwizzle: { PrintNodeInitBegin(nodeIndex); SwizzleNode* swizzleNode = fast_cast<SwizzleNode*>(node); PrintNode(swizzleNode->GetA()); text << '.' << swizzleNode->GetMap(); PrintNodeInitEnd(); } break; case Node::typeOperation: PrintNodeInitBegin(nodeIndex); PrintOperationNodeInit(fast_cast<OperationNode*>(node)); PrintNodeInitEnd(); break; case Node::typeAction: PrintActionNodeInit(fast_cast<ActionNode*>(node)); break; case Node::typeSample: { PrintNodeInitBegin(nodeIndex); SampleNode* sampleNode = fast_cast<SampleNode*>(node); int slot = sampleNode->GetSamplerNode()->GetSlot(); text << 't' << slot; ValueNode* coordsNode = sampleNode->GetCoordsNode(); ValueNode* offsetNode = sampleNode->GetOffsetNode(); ValueNode* lodNode = sampleNode->GetLodNode(); ValueNode* biasNode = sampleNode->GetBiasNode(); ValueNode* gradXNode = sampleNode->GetGradXNode(); ValueNode* gradYNode = sampleNode->GetGradYNode(); if(lodNode) { text << ".SampleLevel(s" << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(lodNode); } else if(biasNode) { text << ".SampleBias(s" << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(biasNode); } else if(gradXNode && gradYNode) { text << ".SampleGrad(s" << slot << ", "; PrintNode(coordsNode); text << ", "; PrintNode(gradXNode); text << ", "; PrintNode(gradYNode); } else { text << ".Sample(s" << slot << ", "; PrintNode(coordsNode); } // add offset if needed if(offsetNode) { text << ", "; PrintNode(offsetNode); } text << ')'; PrintNodeInitEnd(); } break; case Node::typeFragment: { FragmentNode* fragmentNode = fast_cast<FragmentNode*>(node); text << "\tr.r" << fragmentNode->GetTarget() << " = "; PrintNode(fragmentNode->GetNode()); PrintNodeInitEnd(); } break; case Node::typeCast: { PrintNodeInitBegin(nodeIndex); CastNode* castNode = fast_cast<CastNode*>(node); text << '('; PrintDataType(castNode->GetValueType()); text << ")"; PrintNode(castNode->GetA()); PrintNodeInitEnd(); } break; default: THROW("Unknown node type"); } }
bool AreaNodeIndexGenerator::Import(const ImportParameter& parameter, Progress& progress, const TypeConfig& typeConfig) { FileScanner nodeScanner; FileWriter writer; std::set<TypeId> remainingNodeTypes; //! Set of types we still must process std::vector<TypeData> nodeTypeData; size_t level; size_t maxLevel=0; nodeTypeData.resize(typeConfig.GetTypes().size()); if (!nodeScanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "nodes.dat"), FileScanner::Sequential, true)) { progress.Error("Cannot open 'nodes.dat'"); return false; } // // Scanning distribution // progress.SetAction("Scanning level distribution of node types"); // Initially we must process all types that represents nodes and that should // not be ignored for (size_t i=0; i<typeConfig.GetTypes().size(); i++) { if (typeConfig.GetTypeInfo(i).CanBeNode() && !typeConfig.GetTypeInfo(i).GetIgnore()) { remainingNodeTypes.insert(i); } } level=parameter.GetAreaNodeMinMag(); while (!remainingNodeTypes.empty()) { uint32_t nodeCount=0; std::set<TypeId> currentNodeTypes(remainingNodeTypes); double cellWidth=360.0/pow(2.0,(int)level); double cellHeight=180.0/pow(2.0,(int)level); std::vector<std::map<Pixel,size_t> > cellFillCount; cellFillCount.resize(typeConfig.GetTypes().size()); progress.Info("Scanning Level "+NumberToString(level)+" ("+NumberToString(remainingNodeTypes.size())+" types still to process)"); nodeScanner.GotoBegin(); if (!nodeScanner.Read(nodeCount)) { progress.Error("Error while reading number of data entries in file"); return false; } for (uint32_t n=1; n<=nodeCount; n++) { progress.SetProgress(n,nodeCount); FileOffset offset; Node node; nodeScanner.GetPos(offset); if (!node.Read(nodeScanner)) { progress.Error(std::string("Error while reading data entry ")+ NumberToString(n)+" of "+ NumberToString(nodeCount)+ " in file '"+ nodeScanner.GetFilename()+"'"); return false; } // If we still need to handle this type, // count number of entries per type and tile cell if (currentNodeTypes.find(node.GetType())!=currentNodeTypes.end()) { uint32_t xc=(uint32_t)floor((node.GetLon()+180.0)/cellWidth); uint32_t yc=(uint32_t)floor((node.GetLat()+90.0)/cellHeight); cellFillCount[node.GetType()][Pixel(xc,yc)]++; } } // Check statistics for each type // If statistics are within goal limits, use this level // for this type (else try again with the next higher level) for (size_t i=0; i<typeConfig.GetTypes().size(); i++) { if (currentNodeTypes.find(i)!=currentNodeTypes.end()) { size_t entryCount=0; size_t max=0; nodeTypeData[i].indexLevel=(uint32_t)level; nodeTypeData[i].indexCells=cellFillCount[i].size(); nodeTypeData[i].indexEntries=0; if (!cellFillCount[i].empty()) { nodeTypeData[i].cellXStart=cellFillCount[i].begin()->first.x; nodeTypeData[i].cellYStart=cellFillCount[i].begin()->first.y; nodeTypeData[i].cellXEnd=nodeTypeData[i].cellXStart; nodeTypeData[i].cellYEnd=nodeTypeData[i].cellYStart; for (std::map<Pixel,size_t>::const_iterator cell=cellFillCount[i].begin(); cell!=cellFillCount[i].end(); ++cell) { nodeTypeData[i].indexEntries+=cell->second; nodeTypeData[i].cellXStart=std::min(nodeTypeData[i].cellXStart,cell->first.x); nodeTypeData[i].cellXEnd=std::max(nodeTypeData[i].cellXEnd,cell->first.x); nodeTypeData[i].cellYStart=std::min(nodeTypeData[i].cellYStart,cell->first.y); nodeTypeData[i].cellYEnd=std::max(nodeTypeData[i].cellYEnd,cell->first.y); } } nodeTypeData[i].cellXCount=nodeTypeData[i].cellXEnd-nodeTypeData[i].cellXStart+1; nodeTypeData[i].cellYCount=nodeTypeData[i].cellYEnd-nodeTypeData[i].cellYStart+1; // Count absolute number of entries for (std::map<Pixel,size_t>::const_iterator cell=cellFillCount[i].begin(); cell!=cellFillCount[i].end(); ++cell) { entryCount+=cell->second; max=std::max(max,cell->second); } // Average number of entries per tile cell double average=entryCount*1.0/cellFillCount[i].size(); // If we do not have any entries, we store it now if (cellFillCount[i].empty()) { continue; } // If the fill rate of the index is too low, we use this index level anyway if (nodeTypeData[i].indexCells/(1.0*nodeTypeData[i].cellXCount*nodeTypeData[i].cellYCount)<= parameter.GetAreaNodeIndexMinFillRate()) { progress.Warning(typeConfig.GetTypeInfo(i).GetName()+" ("+NumberToString(i)+") is not well distributed"); continue; } // If average fill size and max fill size for tile cells // is within limits, store it now. if (max<=parameter.GetAreaNodeIndexCellSizeMax() && average<=parameter.GetAreaNodeIndexCellSizeAverage()) { continue; } // else, we remove it from the list and try again with an higher // level. currentNodeTypes.erase(i); } } // Now process all types for this limit, that are within the limits for (std::set<TypeId>::const_iterator cnt=currentNodeTypes.begin(); cnt!=currentNodeTypes.end(); cnt++) { maxLevel=std::max(maxLevel,level); progress.Info("Type "+typeConfig.GetTypeInfo(*cnt).GetName()+"(" + NumberToString(*cnt)+"), "+NumberToString(nodeTypeData[*cnt].indexCells)+" cells, "+NumberToString(nodeTypeData[*cnt].indexEntries)+" objects"); remainingNodeTypes.erase(*cnt); } level++; } // // Writing index file // progress.SetAction("Generating 'areanode.idx'"); if (!writer.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "areanode.idx"))) { progress.Error("Cannot create 'areanode.idx'"); return false; } uint32_t indexEntries=0; // Count number of types in index for (size_t i=0; i<typeConfig.GetTypes().size(); i++) { if (typeConfig.GetTypeInfo(i).CanBeNode() && nodeTypeData[i].HasEntries()) { indexEntries++; } } writer.Write(indexEntries); // Store index data for each type for (size_t i=0; i<typeConfig.GetTypes().size(); i++) { if (typeConfig.GetTypeInfo(i).CanBeNode() && nodeTypeData[i].HasEntries()) { FileOffset bitmapOffset=0; uint8_t dataOffsetBytes=0; writer.WriteNumber(typeConfig.GetTypeInfo(i).GetId()); writer.GetPos(nodeTypeData[i].indexOffset); writer.WriteFileOffset(bitmapOffset); writer.Write(dataOffsetBytes); writer.WriteNumber(nodeTypeData[i].indexLevel); writer.WriteNumber(nodeTypeData[i].cellXStart); writer.WriteNumber(nodeTypeData[i].cellXEnd); writer.WriteNumber(nodeTypeData[i].cellYStart); writer.WriteNumber(nodeTypeData[i].cellYEnd); } } // Now store index bitmap for each type in increasing level order (why?) for (size_t l=0; l<=maxLevel; l++) { std::set<TypeId> indexTypes; uint32_t nodeCount; double cellWidth=360.0/pow(2.0,(int)l); double cellHeight=180.0/pow(2.0,(int)l); for (size_t i=0; i<typeConfig.GetTypes().size(); i++) { if (typeConfig.GetTypeInfo(i).CanBeNode() && nodeTypeData[i].HasEntries() && nodeTypeData[i].indexLevel==l) { indexTypes.insert(i); } } if (indexTypes.empty()) { continue; } progress.Info("Scanning nodes for index level "+NumberToString(l)); std::vector<std::map<Pixel,std::list<FileOffset> > > typeCellOffsets; typeCellOffsets.resize(typeConfig.GetTypes().size()); nodeScanner.GotoBegin(); if (!nodeScanner.Read(nodeCount)) { progress.Error("Error while reading number of data entries in file"); return false; } // // Collect all offsets // for (uint32_t n=1; n<=nodeCount; n++) { progress.SetProgress(n,nodeCount); FileOffset offset; Node node; nodeScanner.GetPos(offset); if (!node.Read(nodeScanner)) { progress.Error(std::string("Error while reading data entry ")+ NumberToString(n)+" of "+ NumberToString(nodeCount)+ " in file '"+ nodeScanner.GetFilename()+"'"); return false; } if (indexTypes.find(node.GetType())!=indexTypes.end()) { uint32_t xc=(uint32_t)floor((node.GetLon()+180.0)/cellWidth); uint32_t yc=(uint32_t)floor((node.GetLat()+90.0)/cellHeight); typeCellOffsets[node.GetType()][Pixel(xc,yc)].push_back(offset); } } // // Write bitmap // for (std::set<TypeId>::const_iterator type=indexTypes.begin(); type!=indexTypes.end(); ++type) { size_t indexEntries=0; size_t dataSize=0; char buffer[10]; for (std::map<Pixel,std::list<FileOffset> >::const_iterator cell=typeCellOffsets[*type].begin(); cell!=typeCellOffsets[*type].end(); ++cell) { indexEntries+=cell->second.size(); dataSize+=EncodeNumber(cell->second.size(),buffer); FileOffset previousOffset=0; for (std::list<FileOffset>::const_iterator offset=cell->second.begin(); offset!=cell->second.end(); ++offset) { FileOffset data=*offset-previousOffset; dataSize+=EncodeNumber(data,buffer); previousOffset=*offset; } } // "+1" because we add +1 to every offset, to generate offset > 0 uint8_t dataOffsetBytes=BytesNeededToAddressFileData(dataSize); progress.Info("Writing map for "+ typeConfig.GetTypeInfo(*type).GetName()+", "+ NumberToString(typeCellOffsets[*type].size())+" cells, "+ NumberToString(indexEntries)+" entries, "+ ByteSizeToString(1.0*dataOffsetBytes*nodeTypeData[*type].cellXCount*nodeTypeData[*type].cellYCount)); FileOffset bitmapOffset; if (!writer.GetPos(bitmapOffset)) { progress.Error("Cannot get type index start position in file"); return false; } assert(nodeTypeData[*type].indexOffset!=0); if (!writer.SetPos(nodeTypeData[*type].indexOffset)) { progress.Error("Cannot go to type index offset in file"); return false; } writer.WriteFileOffset(bitmapOffset); writer.Write(dataOffsetBytes); if (!writer.SetPos(bitmapOffset)) { progress.Error("Cannot go to type index start position in file"); return false; } // Write the bitmap with offsets for each cell // We prefill with zero and only overwrite cells that have data // So zero means "no data for this cell" for (size_t i=0; i<nodeTypeData[*type].cellXCount*nodeTypeData[*type].cellYCount; i++) { FileOffset cellOffset=0; writer.WriteFileOffset(cellOffset, dataOffsetBytes); } FileOffset dataStartOffset; if (!writer.GetPos(dataStartOffset)) { progress.Error("Cannot get start of data section after bitmap"); return false; } // Now write the list of offsets of objects for every cell with content for (std::map<Pixel,std::list<FileOffset> >::const_iterator cell=typeCellOffsets[*type].begin(); cell!=typeCellOffsets[*type].end(); ++cell) { FileOffset bitmapCellOffset=bitmapOffset+ ((cell->first.y-nodeTypeData[*type].cellYStart)*nodeTypeData[*type].cellXCount+ cell->first.x-nodeTypeData[*type].cellXStart)*dataOffsetBytes; FileOffset previousOffset=0; FileOffset cellOffset; if (!writer.GetPos(cellOffset)) { progress.Error("Cannot get cell start position in file"); return false; } if (!writer.SetPos(bitmapCellOffset)) { progress.Error("Cannot go to cell start position in file"); return false; } writer.WriteFileOffset(cellOffset-dataStartOffset+1, dataOffsetBytes); if (!writer.SetPos(cellOffset)) { progress.Error("Cannot go back to cell start position in file"); return false; } writer.WriteNumber((uint32_t)cell->second.size()); for (std::list<FileOffset>::const_iterator offset=cell->second.begin(); offset!=cell->second.end(); ++offset) { writer.WriteNumber((FileOffset)(*offset-previousOffset)); previousOffset=*offset; } } } } return !writer.HasError() && writer.Close(); }