Example #1
0
// 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;
}
Example #2
0
// 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;
}
Example #4
0
// 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;
}
Example #5
0
// 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;
}
Example #6
0
// 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;
}
Example #7
0
// 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;
}
Example #8
0
	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;
	}
Example #9
0
// 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;
}
Example #10
0
  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()));
    }
  }
Example #11
0
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;
}
Example #13
0
// 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;
}
Example #14
0
// 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;
}
Example #15
0
// 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);
}
Example #18
0
//=================================================================================
/*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;
}
Example #19
0
//=================================================================================
/*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;
}
Example #20
0
// 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;
}
Example #21
0
// 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;
}
Example #22
0
// 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;
}
Example #23
0
// 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;
}
Example #24
0
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);
		}
	}
}
Example #25
0
// 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;
}
Example #26
0
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();
}
Example #27
0
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");
	}
}
Example #28
0
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));
}
Example #29
0
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");
	}
}
Example #30
0
  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();
  }