private void _overlayObject( AbstractNode source, ObjectAbstractNode dest )
{
if ( source is ObjectAbstractNode )
{
ObjectAbstractNode src = (ObjectAbstractNode)source;
// Overlay the environment of one on top the other first
foreach ( KeyValuePair<string, string> i in src.Variables )
{
KeyValuePair<bool, string> var = dest.GetVariable( i.Key );
if ( !var.Key )
dest.SetVariable( i.Key, i.Value );
}
// Create a vector storing each pairing of override between source and destination
List<KeyValuePair<AbstractNode, AbstractNode>> overrides = new List<KeyValuePair<AbstractNode, AbstractNode>>();
// A list of indices for each destination node tracks the minimum
// source node they can index-match against
Dictionary<ObjectAbstractNode, int> indices = new Dictionary<ObjectAbstractNode, int>();
// A map storing which nodes have overridden from the destination node
Dictionary<ObjectAbstractNode, bool> overridden = new Dictionary<ObjectAbstractNode, bool>();
// Fill the vector with objects from the source node (base)
// And insert non-objects into the overrides list of the destination
int insertPos = 0;
foreach ( AbstractNode i in src.Children )
{
if ( i is ObjectAbstractNode )
{
overrides.Add( new KeyValuePair<AbstractNode, AbstractNode>( i, null ) );
}
else
{
AbstractNode newNode = i.Clone();
newNode.Parent = dest;
dest.Overrides.Add( newNode );
}
}
// Track the running maximum override index in the name-matching phase
int maxOverrideIndex = 0;
// Loop through destination children searching for name-matching overrides
for ( int i = 0; i < dest.Children.Count; i++ )
{
if ( dest.Children[ i ] is ObjectAbstractNode )
{
// Start tracking the override index position for this object
int overrideIndex = 0;
ObjectAbstractNode node = (ObjectAbstractNode)dest.Children[ i ];
indices[ node ] = maxOverrideIndex;
overridden[ node ] = false;
// special treatment for materials with * in their name
bool nodeHasWildcard = ( !string.IsNullOrEmpty( node.Name ) && node.Name.Contains( "*" ) );
// Find the matching name node
for ( int j = 0; j < overrides.Count; ++j )
{
ObjectAbstractNode temp = (ObjectAbstractNode)overrides[ j ].Key;
// Consider a match a node that has a wildcard and matches an input name
bool wildcardMatch = nodeHasWildcard &&
( ( new Regex( node.Name ) ).IsMatch( temp.Name ) ||
( node.Name.Length == 1 && string.IsNullOrEmpty( temp.Name ) ) );
if ( temp.Cls == node.Cls && !string.IsNullOrEmpty( node.Name ) && ( temp.Name == node.Name || wildcardMatch ) )
{
// Pair these two together unless it's already paired
if ( overrides[ j ].Value == null )
{
int currentIterator = i;
ObjectAbstractNode currentNode = node;
if ( wildcardMatch )
{
//If wildcard is matched, make a copy of current material and put it before the iterator, matching its name to the parent. Use same reinterpret cast as above when node is set
AbstractNode newNode = dest.Children[ i ].Clone();
dest.Children.Insert( currentIterator, newNode );
currentNode = (ObjectAbstractNode)dest.Children[ currentIterator ];
currentNode.Name = temp.Name;//make the regex match its matcher
}
overrides[ j ] = new KeyValuePair<AbstractNode, AbstractNode>( overrides[ j ].Key, dest.Children[ currentIterator ] );
// Store the max override index for this matched pair
overrideIndex = j;
overrideIndex = maxOverrideIndex = System.Math.Max( overrideIndex, maxOverrideIndex );
indices[ currentNode ] = overrideIndex;
overridden[ currentNode ] = true;
}
else
{
AddError( CompileErrorCode.DuplicateOverride, node.File, node.Line );
}
if ( !wildcardMatch )
break;
}
}
if ( nodeHasWildcard )
{
//if the node has a wildcard it will be deleted since it was duplicated for every match
dest.Children.RemoveAt( i );
i--;
}
}
}
// Now make matches based on index
// Loop through destination children searching for name-matching overrides
foreach ( AbstractNode i in dest.Children )
{
if ( i is ObjectAbstractNode )
{
ObjectAbstractNode node = (ObjectAbstractNode)i;
if ( !overridden[ node ] )
{
// Retrieve the minimum override index from the map
int overrideIndex = indices[ node ];
if ( overrideIndex < overrides.Count )
{
// Search for minimum matching override
for ( int j = overrideIndex; j < overrides.Count; ++j )
{
ObjectAbstractNode temp = (ObjectAbstractNode)overrides[ j ].Key;
if ( string.IsNullOrEmpty( temp.Name ) && temp.Cls == node.Cls && overrides[ j ].Value == null )
{
overrides[ j ] = new KeyValuePair<AbstractNode, AbstractNode>( overrides[ j ].Key, i );
break;
}
}
}
}
}
}
// Loop through overrides, either inserting source nodes or overriding
for ( int i = 0; i < overrides.Count; ++i )
{
if ( overrides[ i ].Value != null )
{
// Override the destination with the source (base) object
_overlayObject( overrides[ i ].Key, (ObjectAbstractNode)overrides[ i ].Value );
insertPos = dest.Children.IndexOf( overrides[ i ].Value );
insertPos++;
}
else
{
// No override was possible, so insert this node at the insert position
// into the destination (child) object
AbstractNode newNode = overrides[ i ].Key.Clone();
newNode.Parent = dest;
if ( insertPos != dest.Children.Count - 1 )
{
dest.Children.Insert( insertPos, newNode );
}
else
{
dest.Children.Add( newNode );
}
}
}
}
}