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; } } } }
/// <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(); } } }