Provides information about a shader variable.
예제 #1
0
        /// <summary>
        /// Compiles the ShaderProgram. This is done automatically when loading the ShaderProgram
        /// or when binding it.
        /// </summary>
        public void Compile()
        {
            DualityApp.GuardSingleThreadState();

            if (this.glProgramId == 0)
            {
                return;
            }
            if (this.compiled)
            {
                return;
            }

            GL.LinkProgram(this.glProgramId);

            int result;

            GL.GetProgram(this.glProgramId, GetProgramParameterName.LinkStatus, out result);
            if (result == 0)
            {
                string infoLog = GL.GetProgramInfoLog(this.glProgramId);
                Log.Core.WriteError("Error linking shader program. InfoLog:{1}{0}", infoLog, Environment.NewLine);
                return;
            }
            this.compiled = true;

            // Collect variable infos from sub programs
            ShaderVarInfo[] geomVarArray = this.geom.IsAvailable ? this.geom.Res.VarInfo : null;
            ShaderVarInfo[] fragVarArray = this.frag.IsAvailable ? this.frag.Res.VarInfo : null;
            ShaderVarInfo[] vertVarArray = this.vert.IsAvailable ? this.vert.Res.VarInfo : null;

            var emptyShaderInfo = new ShaderVarInfo[0];

            this.varInfo = (vertVarArray ?? emptyShaderInfo)
                           .Union(fragVarArray ?? emptyShaderInfo)
                           .Union(geomVarArray ?? emptyShaderInfo)
                           .ToArray();

            // Determine actual variable locations
            for (int i = 0; i < this.varInfo.Length; i++)
            {
                if (this.varInfo[i].scope == ShaderVarScope.Uniform)
                {
                    this.varInfo[i].glVarLoc = GL.GetUniformLocation(this.glProgramId, this.varInfo[i].name);
                }
                else
                {
                    this.varInfo[i].glVarLoc = GL.GetAttribLocation(this.glProgramId, this.varInfo[i].name);
                }
            }
        }
예제 #2
0
		/// <summary>
		/// Compiles the shader. This is done automatically when loading the shader
		/// or attaching it to a <see cref="Duality.Resources.ShaderProgram"/>.
		/// </summary>
		public void Compile()
		{
			DualityApp.GuardSingleThreadState();

			if (this.compiled) return;
			if (String.IsNullOrEmpty(this.source)) return;
			if (this.glShaderId == 0) this.glShaderId = GL.CreateShader(this.OglShaderType);
			GL.ShaderSource(this.glShaderId, this.source);
			GL.CompileShader(this.glShaderId);

			int result;
			GL.GetShader(this.glShaderId, ShaderParameter.CompileStatus, out result);
			if (result == 0)
			{
				string infoLog = GL.GetShaderInfoLog(this.glShaderId);
				Log.Core.WriteError("Error compiling {0}. InfoLog:\n{1}", this.OglShaderType, infoLog);
				return;
			}
			this.compiled = true;

			// Remove comments from source code before extracting variables
			string sourceWithoutComments;
			{
				const string blockComments = @"/\*(.*?)\*/";
				const string lineComments = @"//(.*?)\r?\n";
				const string strings = @"""((\\[^\n]|[^""\n])*)""";
				const string verbatimStrings = @"@(""[^""]*"")+";
				sourceWithoutComments = Regex.Replace(this.source,
					blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
					me => {
						if (me.Value.StartsWith("/*") || me.Value.StartsWith("//"))
							return me.Value.StartsWith("//") ? Environment.NewLine : "";
						// Keep the literal strings
						return me.Value;
					},
					RegexOptions.Singleline);
			}

			// Scan remaining code chunk for variable declarations
			List<ShaderVarInfo> varInfoList = new List<ShaderVarInfo>();
			string[] lines = sourceWithoutComments.Split(new[] {';','\n'}, StringSplitOptions.RemoveEmptyEntries);
			ShaderVarInfo varInfo = new ShaderVarInfo();
			foreach (string t in lines)
			{
				string curLine = t.TrimStart();

				if (curLine.StartsWith("uniform"))
					varInfo.scope = ShaderVarScope.Uniform;
				else if (curLine.StartsWith("attribute"))
					varInfo.scope = ShaderVarScope.Attribute;
				else continue;

				string[] curLineSplit = curLine.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
				switch (curLineSplit[1].ToUpper())
				{
					case "FLOAT":		varInfo.type = ShaderVarType.Float; break;
					case "VEC2":		varInfo.type = ShaderVarType.Vec2; break;
					case "VEC3":		varInfo.type = ShaderVarType.Vec3; break;
					case "VEC4":		varInfo.type = ShaderVarType.Vec4; break;
					case "MAT2":		varInfo.type = ShaderVarType.Mat2; break;
					case "MAT3":		varInfo.type = ShaderVarType.Mat3; break;
					case "MAT4":		varInfo.type = ShaderVarType.Mat4; break;
					case "INT":			varInfo.type = ShaderVarType.Int; break;
					case "SAMPLER2D":	varInfo.type = ShaderVarType.Sampler2D; break;
				}

				curLineSplit = curLineSplit[2].Split(new char[] {'[', ']'}, StringSplitOptions.RemoveEmptyEntries);
				varInfo.name = curLineSplit[0];
				varInfo.arraySize = (curLineSplit.Length > 1) ? int.Parse(curLineSplit[1]) : 1;
				varInfo.glVarLoc = -1;

				varInfoList.Add(varInfo);
			}

			this.varInfo = varInfoList.ToArray();
		}
예제 #3
0
        /// <summary>
        /// Compiles the shader. This is done automatically when loading the shader
        /// or attaching it to a <see cref="Duality.Resources.ShaderProgram"/>.
        /// </summary>
        public void Compile()
        {
            DualityApp.GuardSingleThreadState();

            if (this.compiled)
            {
                return;
            }
            if (String.IsNullOrEmpty(this.source))
            {
                return;
            }
            if (this.glShaderId == 0)
            {
                this.glShaderId = GL.CreateShader(this.OglShaderType);
            }
            GL.ShaderSource(this.glShaderId, this.source);
            GL.CompileShader(this.glShaderId);

            int result;

            GL.GetShader(this.glShaderId, ShaderParameter.CompileStatus, out result);
            if (result == 0)
            {
                string infoLog = GL.GetShaderInfoLog(this.glShaderId);
                Log.Core.WriteError("Error compiling {0}. InfoLog:\n{1}", this.OglShaderType, infoLog);
                return;
            }
            this.compiled = true;

            // Remove comments from source code before extracting variables
            string sourceWithoutComments;
            {
                const string blockComments   = @"/\*(.*?)\*/";
                const string lineComments    = @"//(.*?)\r?\n";
                const string strings         = @"""((\\[^\n]|[^""\n])*)""";
                const string verbatimStrings = @"@(""[^""]*"")+";
                sourceWithoutComments = Regex.Replace(this.source,
                                                      blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
                                                      me => {
                    if (me.Value.StartsWith("/*") || me.Value.StartsWith("//"))
                    {
                        return(me.Value.StartsWith("//") ? Environment.NewLine : "");
                    }
                    // Keep the literal strings
                    return(me.Value);
                },
                                                      RegexOptions.Singleline);
            }

            // Scan remaining code chunk for variable declarations
            List <ShaderVarInfo> varInfoList = new List <ShaderVarInfo>();

            string[]      lines   = sourceWithoutComments.Split(new[] { ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            ShaderVarInfo varInfo = new ShaderVarInfo();

            foreach (string t in lines)
            {
                string curLine = t.TrimStart();

                if (curLine.StartsWith("uniform"))
                {
                    varInfo.scope = ShaderVarScope.Uniform;
                }
                else if (curLine.StartsWith("attribute"))
                {
                    varInfo.scope = ShaderVarScope.Attribute;
                }
                else
                {
                    continue;
                }

                string[] curLineSplit = curLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                switch (curLineSplit[1].ToUpper())
                {
                case "FLOAT":           varInfo.type = ShaderVarType.Float; break;

                case "VEC2":            varInfo.type = ShaderVarType.Vec2; break;

                case "VEC3":            varInfo.type = ShaderVarType.Vec3; break;

                case "VEC4":            varInfo.type = ShaderVarType.Vec4; break;

                case "MAT2":            varInfo.type = ShaderVarType.Mat2; break;

                case "MAT3":            varInfo.type = ShaderVarType.Mat3; break;

                case "MAT4":            varInfo.type = ShaderVarType.Mat4; break;

                case "INT":                     varInfo.type = ShaderVarType.Int; break;

                case "SAMPLER2D":       varInfo.type = ShaderVarType.Sampler2D; break;
                }

                curLineSplit      = curLineSplit[2].Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
                varInfo.name      = curLineSplit[0];
                varInfo.arraySize = (curLineSplit.Length > 1) ? int.Parse(curLineSplit[1]) : 1;
                varInfo.glVarLoc  = -1;

                varInfoList.Add(varInfo);
            }

            this.varInfo = varInfoList.ToArray();
        }
예제 #4
0
        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
                ShaderVarInfo[] varInfoArray = null;
                if (refTech != null && refTech.Shader.IsAvailable)
                {
                    varInfoArray = refTech.Shader.Res.VarInfo;
                }
                else
                {
                    varInfoArray = new ShaderVarInfo[] { new ShaderVarInfo() };
                    varInfoArray[0].arraySize = 1;
                    varInfoArray[0].glVarLoc = -1;
                    varInfoArray[0].name = ShaderVarInfo.VarName_MainTex;
                    varInfoArray[0].scope = ShaderVarScope.Uniform;
                    varInfoArray[0].type = ShaderVarType.Sampler2D;
                }

                // 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 == ShaderVarScope.Uniform && v.type == ShaderVarType.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 == ShaderVarScope.Uniform && v.type != ShaderVarType.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, ContentRef<Texture>.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 (ShaderVarInfo varInfo in varInfoArray)
                    {
                        if (varInfo.scope != ShaderVarScope.Uniform) continue;

                        // Set Texture variables
                        if (varInfo.type == ShaderVarType.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 = varInfo.InitUniformData();
                            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)
                    {
                        ShaderVarInfo varInfo = varInfoArray.FirstOrDefault(v => v.scope == ShaderVarScope.Uniform && v.name == tex.Key);
                        if (!varInfo.IsEditorVisible) 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)
                    {
                        ShaderVarInfo varInfo = varInfoArray.FirstOrDefault(v => v.scope == ShaderVarScope.Uniform && v.name == uniform.Key);
                        if (!varInfo.IsEditorVisible) 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();
                }
            }
        }
예제 #5
0
        protected PropertyEditor CreateUniformEditor(ShaderVarInfo varInfo)
        {
            PropertyEditor oldEditor;
            this.shaderVarEditors.TryGetValue(varInfo.name, out oldEditor);
            List<EditorHintAttribute> configData = new List<EditorHintAttribute>();

            if (varInfo.arraySize == 1)
            {
                if (varInfo.type == ShaderVarType.Float || varInfo.type == ShaderVarType.Int)
                {
                    Type editType = typeof(float);
                    if (varInfo.type == ShaderVarType.Int) editType = typeof(int);

                    if (oldEditor != null && oldEditor.EditedType == editType)
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(editType, this);
                        if (varInfo.type == ShaderVarType.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 == ShaderVarType.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 == ShaderVarType.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 == ShaderVarType.Float || varInfo.type == ShaderVarType.Int)
                {
                    Type editType = typeof(float);
                    if (varInfo.type == ShaderVarType.Int) editType = typeof(int);

                    if (oldLen == varInfo.arraySize && 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 == ShaderVarType.Float) (e as GroupedPropertyEditor).EditorAdded += this.UniformList_EditorAdded;
                        }
                        this.ParentGrid.ConfigureEditor(e, configData);
                        return e;
                    }
                }
                else if (varInfo.type == ShaderVarType.Vec2)
                {
                    if (oldLen == varInfo.arraySize && 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 == ShaderVarType.Vec3)
                {
                    if (oldLen == varInfo.arraySize && 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.arraySize)
                        return oldEditor;
                    else
                    {
                        PropertyEditor e = this.ParentGrid.CreateEditor(typeof(float[][]), this);
                        e.Getter = this.CreateUniformArrayValueGetter(varInfo.name, varInfo.arraySize);
                        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;
                    }
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Compiles the ShaderProgram. This is done automatically when loading the ShaderProgram
        /// or when binding it.
        /// </summary>
        public void Compile()
        {
            DualityApp.GuardSingleThreadState();

            if (this.glProgramId == 0) return;
            if (this.compiled) return;

            GL.LinkProgram(this.glProgramId);

            int result;
            GL.GetProgram(this.glProgramId, GetProgramParameterName.LinkStatus, out result);
            if (result == 0)
            {
                string infoLog = GL.GetProgramInfoLog(this.glProgramId);
                Log.Core.WriteError("Error linking shader program. InfoLog:{1}{0}", infoLog, Environment.NewLine);
                return;
            }
            this.compiled = true;

            // Collect variable infos from sub programs
            ShaderVarInfo[] geomVarArray = this.geom.IsAvailable ? this.geom.Res.VarInfo : null;
            ShaderVarInfo[] fragVarArray = this.frag.IsAvailable ? this.frag.Res.VarInfo : null;
            ShaderVarInfo[] vertVarArray = this.vert.IsAvailable ? this.vert.Res.VarInfo : null;

            var emptyShaderInfo = new ShaderVarInfo[0];
            this.varInfo = (vertVarArray ?? emptyShaderInfo)
                .Union(fragVarArray ?? emptyShaderInfo)
                .Union(geomVarArray ?? emptyShaderInfo)
                .ToArray();

            // Determine actual variable locations
            for (int i = 0; i < this.varInfo.Length; i++)
            {
                if (this.varInfo[i].scope == ShaderVarScope.Uniform)
                    this.varInfo[i].glVarLoc = GL.GetUniformLocation(this.glProgramId, this.varInfo[i].name);
                else
                    this.varInfo[i].glVarLoc = GL.GetAttribLocation(this.glProgramId, this.varInfo[i].name);
            }
        }