/// <summary> /// Add a node to the list of of nodes to reduce. /// </summary> /// <param name="node">The node to add.</param> /// <param name="reduceList">The list of node to reduce.</param> private static void AddNodeToReduceList(IMaterialNode node, List <IMaterialNode> reduceList) { if (!(node is IMaterialValueNode || node is MaterialTextureNode || node is MaterialShaderClassNode)) { reduceList.Add(node); } }
/// <summary> /// Gather all the textures in the node hierarchy, even the ones behind the generics. /// </summary> /// <param name="node">The node to look into.</param> /// <returns>A collection of MaterialTextureNode.</returns> private IEnumerable <MaterialTextureNode> GatherTextureValuesWithGenerics(IMaterialNode node) { var materialContext = new MaterialContext { Material = Material, ExploreGenerics = true }; return(GatherTextures(node, materialContext)); }
/// <summary> /// Inserts a new tree in the material /// </summary> /// <param name="referenceName">The name of the reference.</param> /// <param name="node">The material onde.</param> public void AddNode(string referenceName, IMaterialNode node) { if (Nodes.ContainsKey(referenceName)) { throw new Exception("A reference with name " + referenceName + " already exists"); } Nodes.Add(referenceName, node); }
public static void VisitNodes(this IMaterialNode node, Action <object, MaterialNodeEntry> callback, object context = null) { if (callback == null) { throw new ArgumentNullException("callback"); } VisitNode(new MaterialNodeEntry(node, DoNothing), callback, context); }
/// <summary> /// Initializes a new instance of the <see cref="MaterialNodeEntry"/> struct. /// </summary> /// <param name="node">The node.</param> /// <param name="setter">The setter.</param> /// <exception cref="System.ArgumentNullException">setter</exception> public MaterialNodeEntry(IMaterialNode node, Action <IMaterialNode> setter) { if (setter == null) { throw new ArgumentNullException("setter"); } this.node = node; this.setter = setter; }
/// <summary> /// Generate one shader. /// </summary> public ShaderMixinSource GenerateShaderForReduction(IMaterialNode materialNode) { shaderForReduction = true; var textureVisitor = new MaterialTextureVisitor(Material); var allTextures = textureVisitor.GetAllTextureValues(materialNode); textureVisitor.AssignDefaultTextureKeys(allTextures.Distinct(), null); return(GetShaderMixinSource(GetShaderSource(materialNode))); }
/// <summary> /// Replace all occurences of a node in a tree. /// </summary> public void Replace(IMaterialNode nodeToReplace, IMaterialNode replacementNode) { Material.VisitNodes((context, nodeEntry) => { if (ReferenceEquals(nodeEntry.Node, nodeToReplace)) { nodeEntry.Node = replacementNode; } }); }
/// <inheritdoc/> public override IEnumerable <MaterialNodeEntry> GetChildren(object context = null) { if (LeftChild != null) { yield return(new MaterialNodeEntry(LeftChild, node => LeftChild = node)); } if (RightChild != null) { yield return(new MaterialNodeEntry(RightChild, node => RightChild = node)); } }
/// <summary> /// Get the list of all the reducible sub-trees for this tree. If a tree is entirely reducible, only the rootnode will appear /// </summary> /// <returns>The list of all the reducible sub-trees</returns> public List <IMaterialNode> GetReducibleSubTrees(IMaterialNode node) { var resultList = new List <IMaterialNode>(); var criterion = new ReductionCriteria { TexcoordIndex = TextureCoordinate.TexcoordNone }; if (BuildReducibleSubTreesList(node, resultList, out criterion)) { AddNodeToReduceList(node, resultList); } return(resultList); }
/// <summary> /// Common gather texture function. /// </summary> /// <param name="node">The node to look into.</param> /// <param name="materialContext">The visitor context.</param> /// <returns>A collection of MaterialTextureNode.</returns> private IEnumerable <MaterialTextureNode> GatherTextures(IMaterialNode node, MaterialContext materialContext) { var textureValues = new List <MaterialTextureNode>(); node.VisitNodes((context, nodeEntry) => { var textureValue = nodeEntry.Node as MaterialTextureNode; if (textureValue != null) { textureValues.Add(textureValue); } }, materialContext); return(textureValues); }
/// <summary> /// Test if the tree can be reduced to a single texture or color. /// </summary> /// <param name="node">The node to explore.</param> /// <param name="texcoord">The unique texcoord if applicable.</param> /// <returns>A boolean stating this test.</returns> public bool HasUniqueTexcoord(IMaterialNode node, out TextureCoordinate texcoord) { var allTextures = GatherTextureValues(node).Distinct().ToList(); texcoord = TextureCoordinate.TexcoordNone; foreach (var texSlot in allTextures) { if (texcoord == TextureCoordinate.TexcoordNone) { texcoord = texSlot.TexcoordIndex; } if (texcoord != texSlot.TexcoordIndex) { return(false); } } return(true); }
/// <summary> /// Create a reference to a node. /// </summary> /// <param name="node">The material node.</param> /// <param name="referenceName">The name of the reference.</param> public void MakeReference(IMaterialNode node, string referenceName) { IMaterialNode prevNode; if (Nodes.TryGetValue(referenceName, out prevNode)) { if (!ReferenceEquals(node, prevNode)) { throw new Exception("Unable to create a reference with the name " + referenceName + " because there is already a reference with that name."); } } else { var matReference = new MaterialReferenceNode(referenceName); foreach (var tree in Nodes.Select(x => x.Value)) { //var replacer = new MaterialNodeReplacer. } Nodes.Add(referenceName, node); } }
/// <summary> /// Gather all the parameters in the node hierarchy. /// </summary> /// <param name="node">The node to look into.</param> /// <param name="parameters">The parameter collection to fill.</param> private void GetParametersFromNode(IMaterialNode node, ParameterCollectionData parameters) { if (node == null) { return; } node.VisitNodes((context, nodeEntry) => { var shaderNode = nodeEntry.Node as MaterialShaderClassNode; if (shaderNode != null) { //foreach (var member in shaderNode.Members) foreach (var member in shaderNode.GetParameters(context)) { parameters.Set(member.Key, member.Value); } } }, new MaterialContext { Material = Material, ExploreGenerics = false }); }
/// <summary> /// Reduce the binaryNode to its most compact form. /// </summary> /// <param name="node">The IMaterialNode binaryNode to reduce.</param> /// <returns>The reduced binaryNode.</returns> private IMaterialNode Reduce(IMaterialNode node) { if (node is MaterialBinaryNode) { return(Reduce(node as MaterialBinaryNode)); } if (node is MaterialReferenceNode) { var referenceName = (node as MaterialReferenceNode).Name; if (referenceName != null) { BeginReduction(referenceName); if (ReducedTrees.ContainsKey(referenceName)) { return(ReducedTrees[referenceName]); } return(null); } } return(node); }
/// <summary> /// Assign the Keys to the textures in the tree. /// </summary> /// <param name="node">The node to look into.</param> /// <param name="getTextureKey">The delegate function to get the correct key.</param> private void AssignParameterKeys(IMaterialNode node, TextureKeyGetter getTextureKey) { var allTextures = GatherTextureValues(node).Distinct().ToList(); var textureKeys = new Dictionary <string, ParameterKey <Graphics.Texture> >(); foreach (var texSlot in allTextures) { //TODO: compare texture sampling method ParameterKey <Graphics.Texture> pk; var textureName = texSlot.TextureName; if (textureName == null || !textureKeys.TryGetValue(textureName, out pk)) { pk = getTextureKey(this); if (textureName != null) { textureKeys.Add(textureName, pk); } } texSlot.UsedParameterKey = pk; texSlot.Sampler.SamplerParameterKey = TexturingKeys.Sampler; } }
/// <summary> /// Gather all the sampler generics in the node hierarchy. /// </summary> /// <param name="node">The node to look into.</param> /// <returns>A collection of NodeParameterSampler.</returns> private IEnumerable <NodeParameterSampler> GatherSamplerValues(IMaterialNode node) { var samplerValues = new List <NodeParameterSampler>(); node.VisitNodes((context, nodeEntry) => { var shaderClassNode = nodeEntry.Node as MaterialShaderClassNode; if (shaderClassNode != null) { foreach (var gen in shaderClassNode.Generics) { var genSampler = gen.Value as NodeParameterSampler; if (genSampler != null) { samplerValues.Add(genSampler); } } } }, new MaterialContext { Material = Material, ExploreGenerics = false }); return(samplerValues); }
/// <summary> /// Initializes a new instance of the <see cref="MaterialBinaryNode"/> class. /// </summary> /// <param name="leftChild">The left child.</param> /// <param name="rightChild">The right child.</param> /// <param name="materialBinaryOperand">The material binary operand.</param> public MaterialBinaryNode(IMaterialNode leftChild, IMaterialNode rightChild, MaterialBinaryOperand materialBinaryOperand) { LeftChild = leftChild; RightChild = rightChild; Operand = materialBinaryOperand; }
private static void DoNothing(IMaterialNode node) { }
/// <summary> /// Checks if the node can be reduced and adds to the list the ones that cannot be reduced further. /// </summary> /// <param name="node">The node to visit.</param> /// <param name="resultList">The list of node to reduce.</param> /// <param name="criterion">The current criteria to reduce the node.</param> /// <returns>True if the node can be reduced, false otherwise.</returns> private bool BuildReducibleSubTreesList(IMaterialNode node, List <IMaterialNode> resultList, out ReductionCriteria criterion) { if (node is IMaterialValueNode) { criterion.TexcoordIndex = node is MaterialTextureNode ? ((MaterialTextureNode)node).TexcoordIndex : TextureCoordinate.TexcoordNone; criterion.AddressModeU = node is MaterialTextureNode ? ((MaterialTextureNode)node).Sampler.AddressModeU : (TextureAddressMode?)null; criterion.AddressModeV = node is MaterialTextureNode ? ((MaterialTextureNode)node).Sampler.AddressModeV : (TextureAddressMode?)null; var isSingleReducible = node.IsReducible; if (node is MaterialFloatNode) { isSingleReducible &= (((MaterialFloatNode)node).Key == null); } if (node is MaterialFloat4Node) { isSingleReducible &= (((MaterialFloat4Node)node).Key == null); } if (node is MaterialColorNode) { isSingleReducible &= (((MaterialColorNode)node).Key == null); } return(isSingleReducible); } var refNode = node as MaterialReferenceNode; if (refNode != null) { return(BuildReducibleSubTreesList(Material.FindNode(refNode.Name), resultList, out criterion)); } criterion.TexcoordIndex = TextureCoordinate.TexcoordNone; criterion.AddressModeU = (TextureAddressMode?)null; criterion.AddressModeV = (TextureAddressMode?)null; bool?checkIsReducible = null; ReductionCriteria?checkCriterion = null; var reducibleNodes = new List <IMaterialNode>(); foreach (var subNodeIt in node.GetChildren(Material)) { var subNode = subNodeIt.Node; ReductionCriteria childCriterion; var childIsReducible = BuildReducibleSubTreesList(subNode, resultList, out childCriterion); if (!checkIsReducible.HasValue) { checkIsReducible = childIsReducible; checkCriterion = childCriterion; } else { checkIsReducible = checkIsReducible.Value && childIsReducible && CompatibleCriteria(childCriterion, checkCriterion.Value); checkCriterion = MergeCriteria(checkCriterion.Value, childCriterion); } if (childIsReducible) { reducibleNodes.Add(subNode); } } if (checkCriterion.HasValue) { criterion = checkCriterion.Value; } if (checkIsReducible.HasValue && !checkIsReducible.Value) { // if one child is not reducible, add all the reducible ones to the list foreach (var reducibleNode in reducibleNodes) { AddNodeToReduceList(reducibleNode, resultList); } return(false); } return(node.IsReducible); }
/// <summary> /// Adds a tree in the model. /// </summary> /// <param name="key">The key of the slot in the model.</param> /// <param name="referenceName">The name of the tree.</param> /// <param name="node">The node to add.</param> public void AddColorNode(ParameterKey <ShaderMixinSource> key, string referenceName, IMaterialNode node) { if (ColorNodes.ContainsKey(key)) { ColorNodes[key] = referenceName; } else { ColorNodes.Add(key, referenceName); } AddNode(referenceName, node); }
/// <summary> /// Assign the default texture keys to the texture slots. /// </summary> /// <param name="node">The node to look into.</param> public void AssignDefaultTextureKeys(IMaterialNode node) { AssignParameterKeys(node, GetNextDefaultTextureKey); }
/// <summary> /// Get all the textures needed for this node. /// </summary> /// <param name="node">The node to explore.</param> /// <returns>The list containing all the textures.</returns> public List <NodeParameterSampler> GetAllSamplerValues(IMaterialNode node) { return(GatherSamplerValues(node).Distinct().ToList()); }
/// <summary> /// Assign the diffuse texture keys to the texture slots. /// </summary> /// <param name="node">The node to look into.</param> public void AssignDiffuseTextureKeys(IMaterialNode node) { AssignParameterKeys(node, GetNextDiffuseTextureKey); }
/// <summary> /// Assign the specular texture keys to the texture slots. /// </summary> /// <param name="node">The node to look into.</param> public void AssignSpecularTextureKeys(IMaterialNode node) { AssignParameterKeys(node, GetNextSpecularTextureKey); }
/// <summary> /// Assign the displacement texture keys to the texture slots. /// </summary> /// <param name="node">The node to look into.</param> public void AssignDisplacementTextureKeys(IMaterialNode node) { AssignParameterKeys(node, GetNextDisplacementTextureKey); }
/// <summary> /// Assign the normal map texture keys to the texture slots. /// </summary> /// <param name="node">The node to look into.</param> public void AssignNormalMapTextureKeys(IMaterialNode node) { AssignParameterKeys(node, GetNextNormalMapTextureKey); }
/// <summary> /// Get all the textures needed for this node with the potential generic parameters. /// </summary> /// <param name="node">The node to explore.</param> /// <returns>The list containing all the textures.</returns> public List <MaterialTextureNode> GetAllTextureValuesWithGenerics(IMaterialNode node) { return(GatherTextureValuesWithGenerics(node).Distinct().ToList()); }
/// <summary> /// Gets the shader source. /// </summary> /// <param name="node">The node to process.</param> /// <returns>The shader source.</returns> private ShaderSource GetShaderSource(IMaterialNode node) { if (node == null) { return(new ShaderClassSource("ComputeColor")); } if (node is MaterialFloatNode) { return(GetShaderSource(node as MaterialFloatNode)); } if (node is MaterialFloat4Node) { return(GetShaderSource(node as MaterialFloat4Node)); } if (node is MaterialColorNode) { return(GetShaderSource(node as MaterialColorNode)); } if (node is MaterialTextureNode) { return(GetShaderSource(node as MaterialTextureNode)); } if (node is MaterialShaderClassNode) { return(GetShaderSource(node as MaterialShaderClassNode)); } if (node is MaterialBinaryNode) { return(GetShaderSource(node as MaterialBinaryNode)); } if (node is MaterialReferenceNode) { var referenceName = (node as MaterialReferenceNode).Name; if (shaderForReduction) { var refNode = Material.FindNode(referenceName); return(GetShaderSource(refNode)); } else { if (referenceName == null) { Logger.Warning("[Material] The MaterialReferenceNode [" + node + "] doesn't reference anything."); return(null); } BeginShaderCreation(referenceName, displacementShader); ShaderSource shaderSource; if (!ModelShaderSources.TryGetValue(referenceName, out shaderSource)) { return(null); } return(shaderSource); } } // TODO: error? throw new Exception("[Material] An unsupported material node was encountered during shader creation."); }