210 lines
6.2 KiB
C#
210 lines
6.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Aiwaz.Contracts;
|
|
using Aiwaz.Common;
|
|
using Aiwaz.Core;
|
|
using Aiwaz.Resources.Attributes;
|
|
using System.Collections.ObjectModel;
|
|
|
|
namespace Aiwaz.Resources
|
|
{
|
|
public class TechniqueNotFoundException : Exception { }
|
|
public class UnableToLoadShaderException : Exception
|
|
{
|
|
public UnableToLoadShaderException(string errors)
|
|
: base(errors)
|
|
{
|
|
}
|
|
}
|
|
|
|
[CreationParameters("Load a shader from file")]
|
|
public class ShaderParams : ICreationParams
|
|
{
|
|
[RequiredParameter]
|
|
public string FileName;
|
|
public string TechniqueName;
|
|
|
|
public ShaderParams()
|
|
{
|
|
FileName = null;
|
|
TechniqueName = null;
|
|
}
|
|
}
|
|
|
|
[AiwazResource("Shader", "A complex shader to perform individual shading operations when rendering geometry buffers.")]
|
|
public class Shader : CommandUser, IShader
|
|
{
|
|
#region IShader Members
|
|
|
|
const byte applyFirstPassCommandType = 0;
|
|
const byte nextPassCommandType = 1;
|
|
|
|
private InternalShader internalShader;
|
|
private string techniqueName;
|
|
private byte priority = 0;
|
|
|
|
public Shader(ShaderParams parameters)
|
|
{
|
|
creationParams = parameters;
|
|
Console.WriteLine(string.Format("Creating Shader ({0} Technique: {1})..", parameters.FileName, parameters.TechniqueName));
|
|
|
|
internalShader = Engine.FindNamedObject(parameters.FileName) as InternalShader;
|
|
if (internalShader == null)
|
|
internalShader = new InternalShader(parameters.FileName);
|
|
|
|
Commands.Add(new Command(this, CommandFlags.StartChain | CommandFlags.SubChainStart, applyFirstPassCommandType, 2, this.Priority));
|
|
Commands.Add(new Command(this, CommandFlags.SubChainEnd, nextPassCommandType, byte.MaxValue, this.Priority));
|
|
|
|
this.TechniqueName = parameters.TechniqueName;
|
|
}
|
|
|
|
public string TechniqueName
|
|
{
|
|
get { return techniqueName; }
|
|
set
|
|
{
|
|
techniqueName = value;
|
|
|
|
if (string.IsNullOrEmpty(techniqueName))
|
|
{
|
|
this.Technique = internalShader.Effect.GetTechniqueByIndex(0);
|
|
|
|
if (this.Technique != null)
|
|
techniqueName = this.Technique.Description.Name;
|
|
}
|
|
else
|
|
this.Technique = internalShader.Effect.GetTechniqueByName(TechniqueName);
|
|
|
|
if (this.Technique == null)
|
|
throw new TechniqueNotFoundException();
|
|
|
|
CurrentPass = 0;
|
|
}
|
|
}
|
|
|
|
public SlimDX.Direct3D10.EffectTechnique Technique { get; protected set; }
|
|
|
|
public SlimDX.Direct3D10.Effect Effect { get { return internalShader.Effect; } }
|
|
|
|
public byte Priority
|
|
{
|
|
get
|
|
{
|
|
return priority;
|
|
}
|
|
set
|
|
{
|
|
priority = value;
|
|
foreach (var command in Commands)
|
|
if (command.Type == applyFirstPassCommandType)
|
|
command.SubPriority = priority;
|
|
}
|
|
}
|
|
|
|
public int CurrentPass { get; protected set; }
|
|
|
|
#endregion
|
|
|
|
public override CommandExecuteResult ExecuteCommand(byte commandType, CommandBuffer currentBuffer, int currentPositon)
|
|
{
|
|
if (commandType == applyFirstPassCommandType)
|
|
{
|
|
CurrentPass = 0;
|
|
Engine.EngineStates.LastShader = this;
|
|
}
|
|
else if (commandType == nextPassCommandType)
|
|
{
|
|
if (CurrentPass >= this.Technique.Description.PassCount)
|
|
CurrentPass = this.Technique.Description.PassCount;
|
|
else
|
|
CurrentPass++;
|
|
|
|
if (CurrentPass >= this.Technique.Description.PassCount)
|
|
return CommandExecuteResult.None;
|
|
return CommandExecuteResult.RetrySubChainSkipHead;
|
|
}
|
|
return CommandExecuteResult.None;
|
|
}
|
|
|
|
#region IDisposable Members
|
|
|
|
public override void Dispose()
|
|
{
|
|
Engine.EngineStates.LastShader = null;
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private ICreationParams creationParams;
|
|
public override ICreationParams CreationParams
|
|
{
|
|
get { return creationParams; }
|
|
}
|
|
|
|
public override ObservableCollection<IResource> Children
|
|
{
|
|
get { return null; }
|
|
}
|
|
}
|
|
|
|
internal class InternalShader : IDisposable
|
|
{
|
|
#region IInternalShader Members
|
|
|
|
private string fileName;
|
|
|
|
public InternalShader(string fileName)
|
|
{
|
|
this.fileName = fileName;
|
|
Engine.RegisterNamedObject(fileName, this);
|
|
Engine.RegisterEngineDisposable(this);
|
|
|
|
using (var stream = Engine.FileSystem.Open(fileName))
|
|
{
|
|
string errors;
|
|
Effect = SlimDX.Direct3D10.Effect.FromStream(Engine.Device, stream, "fx_4_0",
|
|
#if DEBUG
|
|
SlimDX.Direct3D10.ShaderFlags.EnableStrictness | SlimDX.Direct3D10.ShaderFlags.Debug,
|
|
#else
|
|
SlimDX.Direct3D10.ShaderFlags.EnableStrictness,
|
|
#endif
|
|
SlimDX.Direct3D10.EffectFlags.None, null, null, out errors);
|
|
|
|
if (!string.IsNullOrEmpty(errors))
|
|
throw new UnableToLoadShaderException(errors);
|
|
}
|
|
}
|
|
|
|
~InternalShader()
|
|
{
|
|
if (!Engine.Initialized)
|
|
return;
|
|
|
|
Engine.UnregisterNamedObject(fileName);
|
|
if (Engine.UnregisterEngineDisposable(this))
|
|
this.Dispose();
|
|
}
|
|
|
|
public SlimDX.Direct3D10.Effect Effect { get; protected set; }
|
|
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
public void Dispose()
|
|
{
|
|
if (this.Effect != null)
|
|
this.Effect.Dispose();
|
|
this.Effect = null;
|
|
Engine.UnregisterNamedObject(fileName);
|
|
Engine.UnregisterEngineDisposable(this);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|