private void UpdateCompositionNodes <T>(ShaderClassType shader, ComputeShaderClassBase <T> node, IObjectNode ownerNode) where T : class, IComputeNode { var keysToRemove = new List <object>(node.CompositionNodes.Keys); var compositionNodesNode = ownerNode[nameof(ComputeShaderClassBase <T> .CompositionNodes)].Target; if (shader != null) { // TODO: is it enough detect compositions? foreach (var member in shader.Members.OfType <Variable>().Where(x => x.Type is TypeName && x.Type.TypeInference?.TargetType == null)) { // ComputeColor only if (member.Type.Name.Text == "ComputeColor") { var index = new Index(member.Name.Text); if (compositionNodesNode.Indices.Any(x => Equals(x, index))) { // This composition node already exists, keep it in the list keysToRemove.Remove(member.Name.Text); } else { // This is a new composition node, add it compositionNodesNode.Add(null, index); } } } } // Remove all composition nodes that we don't have anymore keysToRemove.Select(x => new Index(x)).ForEach(x => compositionNodesNode.Remove(compositionNodesNode.Retrieve(x), x)); }
public static ShaderClassType ParseReferencedShader <T>(this ComputeShaderClassBase <T> node, IDictionary <string, string> projectShaders) where T : class, IComputeNode { ShaderClassType shader = null; string source; if (projectShaders.TryGetValue(node.MixinReference, out source)) { var logger = new LoggerResult(); try { shader = ShaderLoader.ParseSource(source, logger); if (logger.HasErrors) { return(null); } } catch { // TODO: output messages return(null); } } return(shader); }
private void UpdateNode<T>(ComputeShaderClassBase<T> node, IObjectNode ownerNode) where T : class, IComputeNode { var projectShaders = new Dictionary<string, string>(); foreach (var asset in Directory.Package.AllAssets.Where(x => x.Asset is EffectShaderAsset)) { // TODO: we don't detect collision of name here projectShaders[asset.Name] = ((EffectShaderAsset)asset.Asset).Text; } var shader = node.ParseReferencedShader(projectShaders); // Process generics UpdateGenerics(shader, node, ownerNode); // Process composition nodes UpdateCompositionNodes(shader, node, ownerNode); }
private void UpdateGenerics<T>(ShaderClassType shader, ComputeShaderClassBase<T> node, IObjectNode ownerNode) where T : class, IComputeNode { var genericsNode = ownerNode[nameof(ComputeShaderClassBase<T>.Generics)].Target; var keysToRemove = new List<string>(node.Generics.Keys); if (shader != null) { foreach (var generic in shader.ShaderGenerics) { var parameterType = ComputeShaderClassHelper.GetComputeColorParameterType(generic.Type.Name.Text); if (parameterType == null) continue; var index = new NodeIndex(generic.Name.Text); if (genericsNode.Indices.Any(x => Equals(x, index))) { var value = genericsNode.Retrieve(index); if (parameterType.IsInstanceOfType(value)) { // This generic already exists and has the correct type, keep it in the list keysToRemove.Remove(generic.Name); } else { // This generic already exists but has a different type. Just update the value. var parameter = Activator.CreateInstance(parameterType); genericsNode.Add(parameter, index); } } else { // This is a new generic, add it var parameter = Activator.CreateInstance(parameterType); genericsNode.Add(parameter, index); } } } // Remove all generics that we don't have anymore foreach (var k in keysToRemove) { var x = new NodeIndex(k); genericsNode.Remove(genericsNode.Retrieve(x), x); } }
/// <summary> /// Load the shader and extract the information. /// </summary> public static void PrepareNode <T>(this ComputeShaderClassBase <T> _this, ConcurrentDictionary <string, string> projectShaders) where T : class, IComputeNode { // TODO: merge common keys between the previous dictionaries and the new one _this.Generics.Clear(); _this.CompositionNodes.Clear(); if (string.IsNullOrEmpty(_this.MixinReference)) { return; } var newGenerics = new ComputeColorParameters(); var newCompositionNodes = new Dictionary <string, T>(); var newMembers = new Dictionary <ParameterKey, object>(); var localMixinName = _this.MixinReference; ShaderClassType shader = null; string source; if (projectShaders.TryGetValue(localMixinName, out source)) { var logger = new LoggerResult(); try { shader = ShaderLoader.ParseSource(source, logger); if (logger.HasErrors) { logger.Messages.Clear(); return; } } catch { // TODO: output messages return; } } if (shader == null) { return; } var acceptLinkedVariable = true; foreach (var generic in shader.ShaderGenerics) { if (generic.Type.Name.Text == "float4") { _this.AddKey <Vector4>(generic.Name.Text, newGenerics); } else if (generic.Type.Name.Text == "float3") { _this.AddKey <Vector3>(generic.Name.Text, newGenerics); } else if (generic.Type.Name.Text == "float2") { _this.AddKey <Vector2>(generic.Name.Text, newGenerics); } else if (generic.Type.Name.Text == "float") { _this.AddKey <float>(generic.Name.Text, newGenerics); } else if (generic.Type.Name.Text == "int") { _this.AddKey <int>(generic.Name.Text, newGenerics); } else if (generic.Type.Name.Text == "Texture2D") { _this.AddKey <Graphics.Texture>(generic.Name.Text, newGenerics); } else if (generic.Type.Name.Text == "SamplerState") { _this.AddKey <SamplerState>(generic.Name.Text, newGenerics); } else { _this.AddKey <string>(generic.Name.Text, newGenerics); } if (generic.Type is LinkType) { acceptLinkedVariable = false; // since the behavior is unpredictable, safely prevent addition of linked variable (= with Link annotation) } } foreach (var member in shader.Members.OfType <Variable>()) { // TODO: enough detect compositions? if (member.Type is TypeName && (member.Type.TypeInference == null || member.Type.TypeInference.TargetType == null)) { // ComputeColor only if (member.Type.Name.Text == "ComputeColor") { if (_this.CompositionNodes.ContainsKey(member.Name.Text)) { newCompositionNodes.Add(member.Name.Text, _this.CompositionNodes[member.Name.Text]); } else { newCompositionNodes.Add(member.Name.Text, null); } } } else { var isColor = false; string linkName = null; var isStage = member.Qualifiers.Contains(ParadoxStorageQualifier.Stage); var isStream = member.Qualifiers.Contains(ParadoxStorageQualifier.Stream); foreach (var annotation in member.Attributes.OfType <SiliconStudio.Shaders.Ast.Hlsl.AttributeDeclaration>()) { if (annotation.Name == "Color") { isColor = true; } if (acceptLinkedVariable && annotation.Name == "Link" && annotation.Parameters.Count > 0) { linkName = (string)annotation.Parameters[0].Value; } } if (!isStream && (isStage || !string.IsNullOrEmpty(linkName))) { if (linkName == null) { linkName = localMixinName + "." + member.Name.Text; } var memberType = member.Type.ResolveType(); if (isColor) { _this.AddMember <Color4>(linkName, newMembers); } else if (memberType == ScalarType.Float || memberType == ScalarType.Half) { _this.AddMember <float>(linkName, newMembers); } else if (memberType == ScalarType.Double) { _this.AddMember <double>(linkName, newMembers); } else if (memberType == ScalarType.Int) { _this.AddMember <int>(linkName, newMembers); } else if (memberType == ScalarType.UInt) { _this.AddMember <uint>(linkName, newMembers); } else if (memberType == ScalarType.Bool) { _this.AddMember <bool>(linkName, newMembers); } else if (memberType is VectorType) { switch (((VectorType)memberType).Dimension) { case 2: _this.AddMember <Vector2>(linkName, newMembers); break; case 3: _this.AddMember <Vector3>(linkName, newMembers); break; case 4: _this.AddMember <Vector4>(linkName, newMembers); break; } } else if (member.Type.Name.Text == "Texture2D") { _this.AddMember <Graphics.Texture>(linkName, newMembers); } else if (member.Type.Name.Text == "SamplerState") { _this.AddMember <Graphics.SamplerState>(linkName, newMembers); } } } } _this.Generics = newGenerics; _this.CompositionNodes = newCompositionNodes; _this.Members = newMembers; }