private void SetupMaterial(BatchInfo material, BatchInfo lastMaterial) { if (material == lastMaterial) { return; } DrawTechnique tech = material.Technique.Res ?? DrawTechnique.Solid.Res; DrawTechnique lastTech = lastMaterial != null ? lastMaterial.Technique.Res : null; // Prepare Rendering if (tech.NeedsPreparation) { material = new BatchInfo(material); tech.PrepareRendering(this.currentDevice, material); } // Setup BlendType if (lastTech == null || tech.Blending != lastTech.Blending) { this.SetupBlendType(tech.Blending, this.currentDevice.DepthWrite); } // Bind Shader NativeShaderProgram shader = (tech.Shader.Res != null ? tech.Shader.Res.Native : null) as NativeShaderProgram; NativeShaderProgram.Bind(shader); // Setup shader data if (shader != null) { ShaderFieldInfo[] varInfo = shader.Fields; int[] locations = shader.FieldLocations; int[] builtinIndices = shader.BuiltinVariableIndex; // Setup sampler bindings automatically int curSamplerIndex = 0; if (material.Textures != null) { for (int i = 0; i < varInfo.Length; i++) { if (locations[i] == -1) { continue; } if (varInfo[i].Type != ShaderFieldType.Sampler2D) { continue; } // Bind Texture ContentRef <Texture> texRef = material.GetTexture(varInfo[i].Name); NativeTexture.Bind(texRef, curSamplerIndex); GL.Uniform1(locations[i], curSamplerIndex); curSamplerIndex++; } } NativeTexture.ResetBinding(curSamplerIndex); // Transfer uniform data from material to actual shader if (material.Uniforms != null) { for (int i = 0; i < varInfo.Length; i++) { if (locations[i] == -1) { continue; } float[] data = material.GetUniform(varInfo[i].Name); if (data == null) { continue; } NativeShaderProgram.SetUniform(ref varInfo[i], locations[i], data); } } // Specify builtin shader variables, if requested float[] fieldValue = null; for (int i = 0; i < builtinIndices.Length; i++) { if (BuiltinShaderFields.TryGetValue(this.currentDevice, builtinIndices[i], ref fieldValue)) { NativeShaderProgram.SetUniform(ref varInfo[i], locations[i], fieldValue); } } } // Setup fixed function data else { // Fixed function texture binding if (material.Textures != null) { int samplerIndex = 0; foreach (var pair in material.Textures) { NativeTexture.Bind(pair.Value, samplerIndex); samplerIndex++; } NativeTexture.ResetBinding(samplerIndex); } else { NativeTexture.ResetBinding(); } } }
void INativeShaderProgram.LoadProgram(INativeShaderPart vertex, INativeShaderPart fragment) { DefaultOpenTKBackendPlugin.GuardSingleThreadState(); if (this.handle == 0) { this.handle = GL.CreateProgram(); } else { this.DetachShaders(); } // Attach both shaders if (vertex != null) { GL.AttachShader(this.handle, (vertex as NativeShaderPart).Handle); } if (fragment != null) { GL.AttachShader(this.handle, (fragment as NativeShaderPart).Handle); } // Link the shader program GL.LinkProgram(this.handle); int result; GL.GetProgram(this.handle, GetProgramParameterName.LinkStatus, out result); if (result == 0) { string errorLog = GL.GetProgramInfoLog(this.handle); this.RollbackAtFault(); throw new BackendException(string.Format("Linker error:{1}{0}", errorLog, Environment.NewLine)); } // Collect variable infos from sub programs { NativeShaderPart vert = vertex as NativeShaderPart; NativeShaderPart frag = fragment as NativeShaderPart; ShaderFieldInfo[] fragVarArray = frag != null ? frag.Fields : null; ShaderFieldInfo[] vertVarArray = vert != null ? vert.Fields : null; if (fragVarArray != null && vertVarArray != null) { this.fields = vertVarArray.Union(fragVarArray).ToArray(); } else if (vertVarArray != null) { this.fields = vertVarArray.ToArray(); } else { this.fields = fragVarArray.ToArray(); } } // Determine each variables location this.fieldLocations = new int[this.fields.Length]; for (int i = 0; i < this.fields.Length; i++) { if (this.fields[i].Scope == ShaderFieldScope.Uniform) { this.fieldLocations[i] = GL.GetUniformLocation(this.handle, this.fields[i].Name); } else { this.fieldLocations[i] = GL.GetAttribLocation(this.handle, this.fields[i].Name); } } // Determine whether we're using builtin shader variables this.builtinIndex = new int[this.fields.Length]; bool anyBuildinUsed = false; for (int i = 0; i < this.fields.Length; i++) { if (this.fields[i].Scope == ShaderFieldScope.Uniform) { this.builtinIndex[i] = BuiltinShaderFields.GetIndex(this.fields[i].Name); if (this.builtinIndex[i] != BuiltinShaderFields.InvalidIndex) { anyBuildinUsed = true; } } else { this.builtinIndex[i] = BuiltinShaderFields.InvalidIndex; } } if (!anyBuildinUsed) { this.builtinIndex = new int[0]; } }