using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aiwaz.Contracts; using System.Runtime.InteropServices; using Aiwaz.Core; namespace Aiwaz.Resources { public enum CommandFlags : byte { None = 0x00, SubChainStart = 0x01, // Command will start a new command chain (UseShader for example) SubChainEnd = 0x02, // Command will end a command chain (Render) Unique = 0x04, // Similar commands should not be reduced to one Command StartChain = 0x08, // Command will generate a new command chain EndChain = 0x10, // Command will end the command chain (RenderGeometry for example) FlushChain = 0x20, // Command will end the command chain (RenderGeometry for example) } public class Command { [StructLayout(LayoutKind.Explicit)] public struct CommandInfoUnion { [FieldOffset(0)] public uint RawValue; [FieldOffset(0)] public byte Priority; [FieldOffset(1)] public byte SubPriority; [FieldOffset(2)] public CommandFlags Flags; [FieldOffset(3)] public byte Type; } public Command(CommandUser argOwner, CommandFlags argFlags, byte argType) : this(argOwner, argFlags, argType, 0, 0) { } public Command(CommandUser argOwner, CommandFlags argFlags, byte argType, byte argPriority) : this(argOwner, argFlags, argType, argPriority, 0) { } public Command(CommandUser argOwner, CommandFlags argFlags, byte argType, byte argPriority, byte argSubPriority) { CommandInfo.RawValue = 0; Owner = argOwner; Flags = argFlags; Priority = argPriority; SubPriority = argSubPriority; Type = argType; } public CommandInfoUnion CommandInfo; public byte Priority { get { return CommandInfo.Priority; } set { CommandInfo.Priority = value; } } public byte SubPriority { get { return CommandInfo.SubPriority; } set { CommandInfo.SubPriority = value; } } public CommandFlags Flags { get { return CommandInfo.Flags; } set { CommandInfo.Flags = value; } } public byte Type { get { return CommandInfo.Type; } set { CommandInfo.Type = value; } } public CommandUser Owner; }; public enum CommandExecuteResult { None, // Execution done, proceed to the next Command RetrySubChain, // Execution should start from a previous "SubChainStart"-flagged Command RetrySubChainSkipHead // Equal to the above result but skips the as "SubChainStart"-flagged Command }; public abstract class CommandUser : Resource, IDisposable { private List assignedRenderCommandNodes = new List(); public List Commands { get; private set; } public bool IsPreconditionForNextCommands { get; set; } public CommandUser() { this.Commands = new List(); Engine.RegisterEngineDisposable(this); } ~CommandUser() { if (!Engine.Initialized) return; if (Engine.UnregisterEngineDisposable(this)) this.Dispose(); } public abstract CommandExecuteResult ExecuteCommand(byte argCommandType, CommandBuffer argCurrentBuffer, int argCurrentPositon); public void AssignToRenderCommandNode(RenderCommandNode node) { assignedRenderCommandNodes.Add(node); node.MarkDirty(); } public void UnassignFromRenderCommandNode(RenderCommandNode node) { if (assignedRenderCommandNodes.Remove(node)) node.MarkDirty(); } protected void UnassignFromSceneNodes() { for (var i = 0; i < assignedRenderCommandNodes.Count; ++i ) assignedRenderCommandNodes[i].Children.Remove(this); assignedRenderCommandNodes.Clear(); } protected void MarkCommandsAsDirty() { foreach (var node in assignedRenderCommandNodes) node.MarkDirty(); } public new virtual void Dispose() { this.WellKnownName = null; this.UnassignFromSceneNodes(); Engine.UnregisterEngineDisposable(this); base.Dispose(); } } }