Konstantin Koch c61b7a077e Migrated WindowsFormsEditor and WindowsGame and did basic implementation of OpenTK InputDevices
Made it possible to separate the InputDevices by their provider and set
a preffered provider. Otherwise you are restricted to only having one
input Device provider.
Improved the error message if the WindowHandle on the InputDeviceFactory
is invalid.
Improved AssemblyLoader which was skipping the InputDevices.OpenTK
assembly because the OpenTK assembly was blocked. Added ANX.Framework
and SharpDX.Direct3D11.Effects to the ignore list.
The AssemblyLoader is not static anymore (Only used in
AddinSystemFactory) and it doesn't add the same assembly multiple times
anymore. Additionally, if a type of an assembly couldn't be loaded, it
throws now a TypeLoadException with the hint that a dependency might
have been loaded in the wrong version.
Refactored RenderSystem.GL3 with the latest changes on the effect system
that have been done in the ANX.Framework.
2015-10-18 13:37:39 +02:00

296 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using ANX.Framework.Graphics;
using ANX.Framework.NonXNA;
using ANX.RenderSystem.GL3.Helpers;
using OpenTK.Graphics.OpenGL;
using ANX.Framework.Content.Pipeline.Helpers.GL3;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.RenderSystem.GL3
{
/// <summary>
/// Native OpenGL Effect implementation.
/// http://wiki.delphigl.com/index.php/Tutorial_glsl
/// </summary>
public class EffectGL3 : INativeEffect
{
#region Private
private Effect managedEffect;
private ShaderData shaderData;
private List<EffectParameter> parameters;
private List<EffectTechnique> techniques;
internal bool IsDisposed;
internal EffectTechniqueGL3 CurrentTechnique
{
get
{
if (managedEffect.CurrentTechnique == null)
return null;
return managedEffect.CurrentTechnique.NativeTechnique as EffectTechniqueGL3;
}
}
#endregion
#region Public
#region Techniques
public IEnumerable<EffectTechnique> Techniques
{
get
{
if (techniques.Count == 0)
{
Compile();
}
return techniques;
}
}
#endregion
#region Parameters
public IEnumerable<EffectParameter> Parameters
{
get
{
if (techniques.Count == 0)
{
Compile();
}
return parameters;
}
}
#endregion
#endregion
#region Constructor
/// <summary>
/// Private helper constructor for the basic initialization.
/// </summary>
private EffectGL3(Effect setManagedEffect)
{
GraphicsResourceManager.UpdateResource(this, true);
parameters = new List<EffectParameter>();
techniques = new List<EffectTechnique>();
managedEffect = setManagedEffect;
}
~EffectGL3()
{
GraphicsResourceManager.UpdateResource(this, false);
}
/// <summary>
/// Create a new effect instance of separate streams.
/// </summary>
/// <param name="vertexShaderByteCode">The vertex shader code.</param>
/// <param name="pixelShaderByteCode">The fragment shader code.</param>
public EffectGL3(Effect setManagedEffect, Stream vertexShaderByteCode, Stream pixelShaderByteCode)
: this(setManagedEffect)
{
// TODO: this is probably not right!
throw new NotImplementedException("TODO: implement effect constructor with vertex and fragment streams, check HOWTO...");
//CreateShader(ShaderHelper.LoadShaderCode(vertexShaderByteCode),
// ShaderHelper.LoadShaderCode(pixelShaderByteCode));
}
/// <summary>
/// Create a new effect instance of one streams.
/// </summary>
/// <param name="byteCode">The byte code of the shader.</param>
public EffectGL3(Effect setManagedEffect, Stream byteCode)
: this(setManagedEffect)
{
string source = ShaderHelper.LoadShaderCode(byteCode);
shaderData = ShaderHelper.ParseShaderCode(source);
}
#endregion
#region RecreateData
internal void RecreateData()
{
Compile();
}
#endregion
#region Compile
private void Compile()
{
parameters.Clear();
techniques.Clear();
Dictionary<string, int> vertexShaders = new Dictionary<string, int>();
Dictionary<string, int> fragmentShaders = new Dictionary<string, int>();
List<string> parameterNames = new List<string>();
#region Compile vertex shaders
foreach (string vertexName in shaderData.VertexShaderCodes.Keys)
{
string vertexSource = shaderData.VertexGlobalCode + shaderData.VertexShaderCodes[vertexName];
int vertexShader = GL.CreateShader(ShaderType.VertexShader);
string vertexError = CompileShader(vertexShader, vertexSource);
if (String.IsNullOrEmpty(vertexError) == false)
throw new InvalidDataException("Failed to compile the vertex shader '" + vertexName + "' cause of: " +
vertexError);
vertexShaders.Add(vertexName, vertexShader);
}
#endregion
#region Compile fragment shaders
foreach (string fragmentName in shaderData.FragmentShaderCodes.Keys)
{
string fragmentSource = shaderData.FragmentGlobalCode + shaderData.FragmentShaderCodes[fragmentName];
int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
string fragmentError = CompileShader(fragmentShader, fragmentSource);
if (String.IsNullOrEmpty(fragmentError) == false)
throw new InvalidDataException("Failed to compile the fragment shader '" + fragmentName + "' cause of: " +
fragmentError);
fragmentShaders.Add(fragmentName, fragmentShader);
}
#endregion
#region Compile programs
foreach (string programName in shaderData.Techniques.Keys)
{
string vertexName = shaderData.Techniques[programName].Key;
string fragmentName = shaderData.Techniques[programName].Value;
int vertexShaderHandle = vertexShaders[vertexName];
int fragmentShaderHandle = fragmentShaders[fragmentName];
int programHandle = GL.CreateProgram();
ErrorHelper.Check("CreateProgram");
GL.AttachShader(programHandle, vertexShaderHandle);
ErrorHelper.Check("AttachShader vertexShader");
GL.AttachShader(programHandle, fragmentShaderHandle);
ErrorHelper.Check("AttachShader fragmentShader");
GL.LinkProgram(programHandle);
int result;
GL.GetProgram(programHandle, GetProgramParameterName.LinkStatus, out result);
if (result == 0)
{
string programError;
GL.GetProgramInfoLog(programHandle, out programError);
throw new InvalidDataException("Failed to link the shader program '" +
programName + "' because of: " + programError);
}
//After the program has been linked, the shaders don't have to be attached anymore as they won't do anything.
//We also save some memory because the shader source code gets freed by this.
GL.DetachShader(programHandle, vertexShaderHandle);
GL.DetachShader(programHandle, fragmentShaderHandle);
GL.DeleteShader(vertexShaderHandle);
GL.DeleteShader(fragmentShaderHandle);
EffectTechniqueGL3 technique = new EffectTechniqueGL3((EffectGL3)managedEffect.NativeEffect, programName, programHandle);
techniques.Add(new EffectTechnique(managedEffect, technique));
AddParametersFrom(programHandle, parameterNames, technique);
}
#endregion
}
#endregion
#region CompileShader
private string CompileShader(int shader, string source)
{
GL.ShaderSource(shader, source);
GL.CompileShader(shader);
int result;
GL.GetShader(shader, ShaderParameter.CompileStatus, out result);
if (result == 0)
{
string error = "";
GL.GetShaderInfoLog(shader, out error);
GL.DeleteShader(shader);
return error;
}
return null;
}
#endregion
#region AddParametersFrom
private void AddParametersFrom(int programHandle, List<string> parameterNames, EffectTechniqueGL3 technique)
{
int uniformCount;
GL.GetProgram(programHandle, GetProgramParameterName.ActiveUniforms, out uniformCount);
ErrorHelper.Check("GetProgram ActiveUniforms");
for (int index = 0; index < uniformCount; index++)
{
string name = GL.GetActiveUniformName(programHandle, index);
ErrorHelper.Check("GetActiveUniformName name=" + name);
if (parameterNames.Contains(name) == false)
{
parameterNames.Add(name);
int uniformIndex = GL.GetUniformLocation(programHandle, name);
ErrorHelper.Check("GetUniformLocation name=" + name + " uniformIndex=" + uniformIndex);
parameters.Add(new EffectParameter(new EffectParameterGL3(technique, name, uniformIndex)));
}
}
}
#endregion
#region Dispose
/// <summary>
/// Dispose the native shader data.
/// </summary>
public void Dispose()
{
if (IsDisposed == false)
{
IsDisposed = true;
DisposeResource();
}
}
internal void DisposeResource()
{
if (GraphicsDeviceWindowsGL3.IsContextCurrent == false)
{
return;
}
foreach (EffectTechnique technique in techniques)
{
int programHandle =
(technique.NativeTechnique as EffectTechniqueGL3).programHandle;
GL.DeleteProgram(programHandle);
ErrorHelper.Check("DeleteProgram");
int result;
GL.GetProgram(programHandle, GetProgramParameterName.DeleteStatus, out result);
//If it isn't deleted, it means it's somehow still in use.
if (result == 1)
{
string deleteError;
GL.GetProgramInfoLog(programHandle, out deleteError);
throw new Exception("Failed to delete the shader program '" +
technique.Name + "' because of: " + deleteError);
}
}
techniques.Clear();
parameters.Clear();
}
#endregion
}
}