public static void SetUniform(ref ShaderFieldInfo field, int location, params float[] data)
		{
			if (field.Scope != ShaderFieldScope.Uniform) return;
			if (location == -1) return;
			switch (field.Type)
			{
				case ShaderFieldType.Bool:
				case ShaderFieldType.Int:
					int[] arrI = new int[field.ArrayLength];
					for (int j = 0; j < arrI.Length; j++) arrI[j] = (int)data[j];
					GL.Uniform1(location, arrI.Length, arrI);
					break;
				case ShaderFieldType.Float:
					GL.Uniform1(location, data.Length, data);
					break;
				case ShaderFieldType.Vec2:
					GL.Uniform2(location, data.Length / 2, data);
					break;
				case ShaderFieldType.Vec3:
					GL.Uniform3(location, data.Length / 3, data);
					break;
				case ShaderFieldType.Vec4:
					GL.Uniform4(location, data.Length / 4, data);
					break;
				case ShaderFieldType.Mat2:
					GL.UniformMatrix2(location, data.Length / 4, false, data);
					break;
				case ShaderFieldType.Mat3:
					GL.UniformMatrix3(location, data.Length / 9, false, data);
					break;
				case ShaderFieldType.Mat4:
					GL.UniformMatrix4(location, data.Length / 16, false, data);
					break;
			}
		}
        protected override void OnUpdateFromObjects(object[] values)
        {
            base.OnUpdateFromObjects(values);

            if (values.Any(o => o != null))
            {
                bool invokeSetter = false;
                IEnumerable<BatchInfo> batchInfos = null;
                DrawTechnique refTech = null;
                batchInfos = values.Cast<BatchInfo>();
                refTech = batchInfos.NotNull().First().Technique.Res;

                // Retrieve data about shader variables
                ShaderFieldInfo[] varInfoArray = null;
                if (refTech != null && refTech.Shader.IsAvailable)
                {
                    varInfoArray = refTech.Shader.Res.Fields;
                }
                else
                {
                    varInfoArray = new ShaderFieldInfo[] { new ShaderFieldInfo(
                        ShaderFieldInfo.DefaultNameMainTex,
                        ShaderFieldType.Sampler2D,
                        ShaderFieldScope.Uniform) };
                }

                // Get rid of unused variables (This changes actual Resource data!)
                if (!this.ReadOnly)
                {
                    foreach (BatchInfo info in batchInfos.NotNull())
                    {
                        List<string> texRemoveSched = null;
                        List<string> uniRemoveSched = null;
                        if (info.Textures != null)
                        {
                            foreach (var pair in info.Textures)
                            {
                                if (!varInfoArray.Any(v => v.Scope == ShaderFieldScope.Uniform && v.Type == ShaderFieldType.Sampler2D && v.Name == pair.Key))
                                {
                                    if (texRemoveSched == null) texRemoveSched = new List<string>();
                                    texRemoveSched.Add(pair.Key);
                                }
                            }
                        }
                        if (info.Uniforms != null)
                        {
                            foreach (var pair in info.Uniforms)
                            {
                                if (!varInfoArray.Any(v => v.Scope == ShaderFieldScope.Uniform && v.Type != ShaderFieldType.Sampler2D && v.Name == pair.Key))
                                {
                                    if (uniRemoveSched == null) uniRemoveSched = new List<string>();
                                    uniRemoveSched.Add(pair.Key);
                                }
                            }
                        }
                        if (texRemoveSched != null)
                        {
                            foreach (string name in texRemoveSched) info.SetTexture(name, null);
                            invokeSetter = true;
                        }
                        if (uniRemoveSched != null)
                        {
                            foreach (string name in uniRemoveSched) info.SetUniform(name, null);
                            invokeSetter = true;
                        }
                    }
                }

                // Create BatchInfo variables according to Shader uniforms, if not existing yet
                if (!this.ReadOnly)
                {
                    foreach (ShaderFieldInfo varInfo in varInfoArray)
                    {
                        if (varInfo.Scope != ShaderFieldScope.Uniform) continue;

                        // Set Texture variables
                        if (varInfo.Type == ShaderFieldType.Sampler2D)
                        {
                            foreach (BatchInfo info in batchInfos.NotNull())
                            {
                                if (info.GetTexture(varInfo.Name).IsExplicitNull)
                                {
                                    info.SetTexture(varInfo.Name, Texture.White);
                                    invokeSetter = true;
                                }
                            }
                        }
                        // Set other uniform variables
                        else
                        {
                            float[] uniformVal = new float[varInfo.ArrayLength * varInfo.Type.GetElementCount()];
                            if (uniformVal != null)
                            {
                                foreach (BatchInfo info in batchInfos.NotNull())
                                {
                                    float[] oldVal = info.GetUniform(varInfo.Name);
                                    if (oldVal == null)
                                    {
                                        info.SetUniform(varInfo.Name, uniformVal);
                                        invokeSetter = true;
                                    }
                                    else if (oldVal.Length != uniformVal.Length)
                                    {
                                        for (int i = 0; i < Math.Min(oldVal.Length, uniformVal.Length); i++) uniformVal[i] = oldVal[i];
                                        info.SetUniform(varInfo.Name, uniformVal);
                                        invokeSetter = true;
                                    }
                                }
                            }
                        }
                    }
                }

                // Create editors according to existing variables
                var texDict = batchInfos.NotNull().First().Textures;
                var uniformDict = batchInfos.NotNull().First().Uniforms;
                Dictionary<string,PropertyEditor> oldEditors = new Dictionary<string,PropertyEditor>(this.shaderVarEditors);
                if (texDict != null)
                {
                    foreach (var tex in texDict)
                    {
                        ShaderFieldInfo varInfo = varInfoArray.FirstOrDefault(v => v.Scope == ShaderFieldScope.Uniform && v.Name == tex.Key);
                        if (varInfo.IsPrivate) continue;

                        string texName = varInfo.Name;
                        if (oldEditors.ContainsKey(texName))
                            oldEditors.Remove(texName);
                        else
                        {
                            PropertyEditor e = this.ParentGrid.CreateEditor(typeof(ContentRef<Texture>), this);
                            e.Getter = this.CreateTextureValueGetter(texName);
                            e.Setter = !this.ReadOnly ? this.CreateTextureValueSetter(texName) : null;
                            e.PropertyName = texName;
                            this.shaderVarEditors[texName] = e;
                            this.ParentGrid.ConfigureEditor(e);
                            this.AddPropertyEditor(e);
                        }
                    }
                }
                if (uniformDict != null)
                {
                    foreach (var uniform in uniformDict)
                    {
                        ShaderFieldInfo varInfo = varInfoArray.FirstOrDefault(v => v.Scope == ShaderFieldScope.Uniform && v.Name == uniform.Key);
                        if (varInfo.IsPrivate) continue;

                        PropertyEditor e = this.CreateUniformEditor(varInfo);
                        if (e != null)
                        {
                            if (oldEditors.ContainsValue(e))
                                oldEditors.Remove(varInfo.Name);
                            else
                            {
                                e.PropertyName = uniform.Key;
                                this.shaderVarEditors[uniform.Key] = e;
                                this.AddPropertyEditor(e);
                            }
                        }
                    }
                }

                // Remove old editors that aren't needed anymore
                foreach (var pair in oldEditors)
                {
                    if (this.shaderVarEditors[pair.Key] == pair.Value) this.shaderVarEditors.Remove(pair.Key);
                    this.RemovePropertyEditor(pair.Value);
                }

                // If we actually changed (updated) data here, invoke the setter
                if (invokeSetter)
                {
                    this.SetValues(batchInfos);
                    if (!this.IsUpdating)
                        this.PerformGetValue();
                }
            }
        }
        protected PropertyEditor CreateUniformEditor(ShaderFieldInfo varInfo)
        {
            PropertyEditor oldEditor;
            this.shaderVarEditors.TryGetValue(varInfo.Name, out oldEditor);
            List<EditorHintAttribute> configData = new List<EditorHintAttribute>();

            if (varInfo.ArrayLength == 1)
            {
                if (varInfo.Type == ShaderFieldType.Float || varInfo.Type == ShaderFieldType.Int)
                {
                    Type editType = typeof(float);
                    if (varInfo.Type == ShaderFieldType.Int) editType = typeof(int);

                    if (oldEditor != null && oldEditor.EditedType == editType)
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(editType, this);
                        if (varInfo.Type == ShaderFieldType.Int)
                        {
                            e.Getter = this.CreateUniformIntValueGetter(varInfo.Name);
                            e.Setter = !this.ReadOnly ? this.CreateUniformIntValueSetter(varInfo.Name) : null;
                        }
                        else
                        {
                            e.Getter = this.CreateUniformFloatValueGetter(varInfo.Name);
                            e.Setter = !this.ReadOnly ? this.CreateUniformFloatValueSetter(varInfo.Name) : null;
                            configData.Add(new EditorHintIncrementAttribute(0.1f));
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else if (varInfo.Type == ShaderFieldType.Vec2)
                {
                    if (oldEditor != null && oldEditor.EditedType == typeof(Vector2))
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(Vector2), this);
                        e.Getter = this.CreateUniformVec2ValueGetter(varInfo.Name);
                        e.Setter = !this.ReadOnly ? this.CreateUniformVec2ValueSetter(varInfo.Name) : null;
                        configData.Add(new EditorHintIncrementAttribute(0.1f));
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else if (varInfo.Type == ShaderFieldType.Vec3)
                {
                    if (oldEditor != null && oldEditor.EditedType == typeof(Vector3))
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(Vector3), this);
                        e.Getter = this.CreateUniformVec3ValueGetter(varInfo.Name);
                        e.Setter = !this.ReadOnly ? this.CreateUniformVec3ValueSetter(varInfo.Name) : null;
                        configData.Add(new EditorHintIncrementAttribute(0.1f));
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else
                {
                    if (oldEditor != null && oldEditor.EditedType == typeof(float[]))
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(float[]), this);
                        e.Getter = this.CreateUniformValueGetter(varInfo.Name);
                        e.Setter = !this.ReadOnly ? this.CreateUniformValueSetter(varInfo.Name) : null;
                        if (e is GroupedPropertyEditor)
                        {
                            (e as GroupedPropertyEditor).EditorAdded += this.UniformList_EditorAdded;
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
            }
            else
            {
                Array oldValue = oldEditor != null ? (oldEditor as IListPropertyEditor).DisplayedValue as Array : null;
                Type oldElementType = oldValue != null ? oldValue.GetType().GetElementType() : null;
                int oldLen = oldValue != null ? oldValue.Length : -1;

                if (varInfo.Type == ShaderFieldType.Float || varInfo.Type == ShaderFieldType.Int)
                {
                    Type editType = typeof(float);
                    if (varInfo.Type == ShaderFieldType.Int) editType = typeof(int);

                    if (oldLen == varInfo.ArrayLength && oldElementType == editType)
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(editType.MakeArrayType(), this);
                        e.Getter = this.CreateUniformValueGetter(varInfo.Name);
                        e.Setter = !this.ReadOnly ? this.CreateUniformValueSetter(varInfo.Name) : null;
                        e.ForceWriteBack = true;
                        if (e is GroupedPropertyEditor)
                        {
                            if (varInfo.Type == ShaderFieldType.Float) (e as GroupedPropertyEditor).EditorAdded += this.UniformList_EditorAdded;
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else if (varInfo.Type == ShaderFieldType.Vec2)
                {
                    if (oldLen == varInfo.ArrayLength && oldElementType == typeof(Vector2))
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(Vector2[]), this);
                        e.Getter = this.CreateUniformVec2ArrayValueGetter(varInfo.Name);
                        e.Setter = !this.ReadOnly ? this.CreateUniformVec2ArrayValueSetter(varInfo.Name) : null;
                        e.ForceWriteBack = true;
                        if (e is GroupedPropertyEditor)
                        {
                            (e as GroupedPropertyEditor).EditorAdded += this.UniformList_EditorAdded;
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else if (varInfo.Type == ShaderFieldType.Vec3)
                {
                    if (oldLen == varInfo.ArrayLength && oldElementType == typeof(Vector3))
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(Vector3[]), this);
                        e.Getter = this.CreateUniformVec3ArrayValueGetter(varInfo.Name);
                        e.Setter = !this.ReadOnly ? this.CreateUniformVec3ArrayValueSetter(varInfo.Name) : null;
                        e.ForceWriteBack = true;
                        if (e is GroupedPropertyEditor)
                        {
                            (e as GroupedPropertyEditor).EditorAdded += this.UniformList_EditorAdded;
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else
                {
                    if (oldLen == varInfo.ArrayLength)
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(float[][]), this);
                        e.Getter = this.CreateUniformArrayValueGetter(varInfo.Name, varInfo.ArrayLength);
                        e.Setter = !this.ReadOnly ? this.CreateUniformArrayValueSetter(varInfo.Name) : null;
                        e.ForceWriteBack = true;
                        if (e is GroupedPropertyEditor)
                        {
                            (e as GroupedPropertyEditor).EditorAdded += this.UniformList_EditorAdded;
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
            }
        }
示例#4
0
        /// <summary>
        /// Parses all shader field declarations, aggregated with their metadata directives.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="ignoreRegions"></param>
        /// <param name="removeSchedule"></param>
        private void ParseFields(string source, List <IndexRange> ignoreRegions, List <IndexRange> removeSchedule)
        {
            // Read the source line by line and parse it along the way
            List <string> fieldMetadata = new List <string>();

            using (StringReader reader = new StringReader(source))
            {
                int lineIndex = 0;
                while (true)
                {
                    string line = reader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    // Trim the current line, so ignored ranges are removed
                    IndexRange lineRange        = new IndexRange(lineIndex, line.Length);
                    IndexRange trimmedLineRange = lineRange;
                    foreach (IndexRange ignoreRange in ignoreRegions)
                    {
                        trimmedLineRange.Trim(ignoreRange);
                        if (trimmedLineRange.Length == 0)
                        {
                            break;
                        }
                    }
                    foreach (IndexRange ignoreRange in removeSchedule)
                    {
                        trimmedLineRange.Trim(ignoreRange);
                        if (trimmedLineRange.Length == 0)
                        {
                            break;
                        }
                    }
                    string trimmedLine =
                        (trimmedLineRange.Length == 0) ?
                        string.Empty :
                        source.Substring(trimmedLineRange.Index, trimmedLineRange.Length);

                    // Keep track of where we are in the source, and skip over lines that
                    // fall within source regions that are flagged to be ignored.
                    lineIndex += line.Length;
                    lineIndex += Environment.NewLine.Length;

                    // Cleanup remaining line to make it easier to parse
                    trimmedLine = trimmedLine.Trim().TrimEnd(';');
                    if (string.IsNullOrEmpty(trimmedLine))
                    {
                        continue;
                    }

                    // Scan for metadata directives and store them until we hit the next variable declaration
                    Match metadataMatch = RegexMetadataDirective.Match(trimmedLine);
                    if (metadataMatch != null && metadataMatch.Length > 0)
                    {
                        string metadataDirective = metadataMatch.Groups[1].Value;
                        fieldMetadata.Add(metadataDirective);
                        continue;
                    }

                    // Scan for field declarations and aggregate them with previously collected metadata directives
                    ShaderFieldInfo field = this.ParseFieldDeclaration(trimmedLine, fieldMetadata);
                    if (field != null)
                    {
                        this.fields.Add(field);
                        fieldMetadata.Clear();
                        continue;
                    }

                    // Clear metadata directives when reading non-empty lines that don't match any of the above
                    fieldMetadata.Clear();
                }
            }
        }