Konstantin Koch 930b2526f7 made the WindowsGame example work again with all available rendersystems.
Also made the recording inputsystem not selectable for that sample as that needs some code modification in the sample to make it work.
It was not possible to run it with openGL because the creation of the windowInfo object was faulty, it might have worked on linux, but it didn't work on windows.
Also updated a few deprecated calls for OpenGL.
Closing an OpenGL application did wrongly throw an exception when an effect gets disposed, this is fixed now and the memory usage was slightly reduced.
For DirectX 11, which didn't work for the samples out of the box, it was changed that the sharpdx effect dll's are now part of the directx 11 rendersystem so that they don't have to be copied over manually anymore.
Did some very small change to the RecordingGamePad class which makes it work if no data is recorded or played back.
2015-03-15 01:14:25 +01:00

305 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(managedEffect, 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 Apply
public void Apply(GraphicsDevice graphicsDevice)
{
GL.UseProgram(CurrentTechnique.programHandle);
GraphicsDeviceWindowsGL3.activeEffect = this;
ErrorHelper.Check("UseProgram");
}
#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
}
}